From b1c3851aa91d7da83b62c267596ecacb6ac73868 Mon Sep 17 00:00:00 2001 From: brian Date: Wed, 7 Jul 2004 06:18:52 +0000 Subject: [PATCH] more trap cleanup, properly handle JS.Clones darcs-hash:20040707061852-24bed-96f9c4cfe82803fc415617a9bbc811784b383de9.gz --- src/org/ibex/js/Interpreter.java | 90 +++++++++++++++++++++----------------- src/org/ibex/js/JS.java | 20 +++++---- src/org/ibex/js/JSScope.java | 1 - src/org/ibex/js/Test.java | 10 ++++- src/org/ibex/js/Trap.java | 45 +++++-------------- 5 files changed, 81 insertions(+), 85 deletions(-) diff --git a/src/org/ibex/js/Interpreter.java b/src/org/ibex/js/Interpreter.java index 6fc452b..15d42be 100644 --- a/src/org/ibex/js/Interpreter.java +++ b/src/org/ibex/js/Interpreter.java @@ -170,26 +170,28 @@ class Interpreter implements ByteCodes, Tokens { } else if (o instanceof CallMarker) { if (o instanceof TrapMarker) { // handles return component of a read trap TrapMarker tm = (TrapMarker) o; - boolean cascade = tm.t.writeTrap() && !tm.cascadeHappened && !JS.toBoolean(retval); + boolean cascade = tm.t.isWriteTrap() && !tm.cascadeHappened && !JS.toBoolean(retval); if(cascade) { - Trap t = tm.t.next; - while(t != null && t.readTrap()) t = t.next; + Trap t = tm.t.nextWriteTrap(); + if(t == null && tm.target instanceof JS.Clone) { + tm.target = ((JS.Clone)tm.target).clonee; + t = tm.target.getTrap(tm.key); + if(t != null) t = t.writeTrap(); + } if(t != null) { - tm.t = t; - stack.push(tm); - stack.push(new JSArgs(tm.val,t.f)); - f = t.f; - scope = new JSScope(f.parentScope); - pc = -1; + tm.t = t; // we reuse the old trap marker + setupTrap(t,tm.val,tm); + pc--; // we increment it on the next iter continue OUTER; } else { - tm.trapee.put(tm.key,tm.val); + tm.target.put(tm.key,tm.val); } } } - scope = ((CallMarker)o).scope; - pc = ((CallMarker)o).pc - 1; - f = (JSFunction)((CallMarker)o).f; + CallMarker cm = (CallMarker) o; + scope = cm.scope; + pc = cm.pc - 1; + f = cm.f; stack.push(retval); if (pausecount > initialPauseCount) { pc++; return null; } // we were paused if(f == null) return retval; @@ -212,28 +214,29 @@ class Interpreter implements ByteCodes, Tokens { CallMarker o = stack.findCall(); if(o instanceof TrapMarker) { tm = (TrapMarker) o; - target = tm.trapee; + target = tm.target; key = tm.key; tm.cascadeHappened = true; t = tm.t; - if(t.readTrap()) throw new JSExn("can't do a write cascade in a read trap"); - t = t.next; - while(t != null && t.readTrap()) t = t.next; + if(t.isReadTrap()) throw new JSExn("can't do a write cascade in a read trap"); + t = t.nextWriteTrap(); } } - if(tm == null) { // didn't find a trap marker, try to find a trap - t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : ((JS)target).getTrap(key); - while(t != null && t.readTrap()) t = t.next; + if(tm == null) { // not cascading + t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : target.getTrap(key); + if(t != null) t = t.writeTrap(); + } + if(t == null && target instanceof JS.Clone) { + target = ((JS.Clone)target).clonee; + t = target.getTrap(key); + if(t != null) t = t.writeTrap(); } stack.push(val); if(t != null) { - stack.push(new TrapMarker(this,t,target,key,val)); - stack.push(new JSArgs(val,t.f)); - f = t.f; - scope = new TrapScope(f.parentScope,target,f,key); - pc = -1; + setupTrap(t,val,new TrapMarker(this,t,target,key,val)); + pc--; // we increment later break; } else { target.put(key,val); @@ -263,26 +266,26 @@ class Interpreter implements ByteCodes, Tokens { CallMarker o = stack.findCall(); if(o instanceof TrapMarker) { tm = (TrapMarker) o; - target = tm.trapee; + target = tm.target; key = tm.key; t = tm.t; - if(t.writeTrap()) throw new JSExn("can't do a read cascade in a write trap"); - t = t.next; - while(t != null && t.writeTrap()) t = t.next; - if(t != null) tm.cascadeHappened = true; + if(t.isWriteTrap()) throw new JSExn("can't do a read cascade in a write trap"); + t = t.nextReadTrap(); } } - if(tm == null) { // didn't find a trap marker, try to find a trap + if(tm == null) { // not cascading t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : ((JS)target).getTrap(key); - while(t != null && t.writeTrap()) t = t.next; + if(t != null) t = t.readTrap(); + } + if(t == null && target instanceof JS.Clone) { + target = ((JS.Clone)target).clonee; + t = target.getTrap(key); + if(t != null) t = t.readTrap(); } if(t != null) { - stack.push(new TrapMarker(this,t,(JS)target,key,null)); - stack.push(new JSArgs(t.f)); - f = t.f; - scope = new TrapScope(f.parentScope,target,f,key); - pc = -1; + setupTrap(t,null,new TrapMarker(this,t,target,key,null)); + pc--; // we increment later break; } else { ret = target.get(key); @@ -513,6 +516,13 @@ class Interpreter implements ByteCodes, Tokens { throw e; } + void setupTrap(Trap t, JS val, CallMarker cm) throws JSExn { + stack.push(cm); + stack.push(t.isWriteTrap() ? new JSArgs(val,t.f) : new JSArgs(t.f)); + f = t.f; + scope = new TrapScope(t.f.parentScope,t.target,t.f,t.key); + pc = 0; + } // Markers ////////////////////////////////////////////////////////////////////// @@ -534,14 +544,14 @@ class Interpreter implements ByteCodes, Tokens { static class TrapMarker extends CallMarker { Trap t; - final JS trapee; + JS target; final JS key; final JS val; boolean cascadeHappened; - public TrapMarker(Interpreter cx, Trap t, JS trapee, JS key, JS val) { + public TrapMarker(Interpreter cx, Trap t, JS target, JS key, JS val) { super(cx); this.t = t; - this.trapee = trapee; + this.target = target; this.key = key; this.val = val; } diff --git a/src/org/ibex/js/JS.java b/src/org/ibex/js/JS.java index a81c419..c13d2a0 100644 --- a/src/org/ibex/js/JS.java +++ b/src/org/ibex/js/JS.java @@ -44,7 +44,7 @@ public abstract class JS { String debugToString() { return "[class=" + getClass().getName() + "]"; } boolean jsequals(JS o) { return this == o; } - public static class O extends JS { + public static class O extends JS implements Cloneable { private Hash entries; public Enumeration keys() throws JSExn { return entries == null ? (Enumeration)EMPTY_ENUMERATION : (Enumeration)new JavaEnumeration(null,entries.keys()); } @@ -85,7 +85,7 @@ public abstract class JS { public interface Cloneable { } - public static class Clone extends JS.O implements Cloneable { + public static class Clone extends JS.O { protected final JS clonee; JS _unclone() { return clonee.unclone(); } public JS getClonee() { return clonee; } @@ -95,8 +95,8 @@ public abstract class JS { } public boolean jsequals(JS o) { return unclone().jsequals(o.unclone()); } public Enumeration keys() throws JSExn { return clonee.keys(); } - public JS get(JS key) throws JSExn { return clonee.get(key); } - public void put(JS key, JS val) throws JSExn { clonee.put(key, val); } + public JS get(JS key) throws JSExn { return clonee.getAndTriggerTraps(key); } + public void put(JS key, JS val) throws JSExn { clonee.putAndTriggerTraps(key, val); } public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn { return clonee.callMethod(method, a0, a1, a2, rest, nargs); } @@ -300,15 +300,17 @@ public abstract class JS { /** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */ public void putAndTriggerTraps(JS key, JS value) throws JSExn { Trap t = getTrap(key); - if (t != null) t.invoke(value); - else put(key, value); + throw new Error("FIXME"); + /*if (t != null) t.invoke(value); + elese put(key, value);*/ } /** performs a get, triggering traps if present; traps are run in an unpauseable interpreter */ public JS getAndTriggerTraps(JS key) throws JSExn { Trap t = getTrap(key); - if (t != null) return t.invoke(); - else return get(key); + throw new Error("FIXME"); + /*if (t != null) return t.invoke(); + else return get(key);*/ } /** adds a trap, avoiding duplicates */ @@ -323,7 +325,7 @@ public abstract class JS { final void delTrap(JS key, JSFunction f) throws JSExn { Trap t = (Trap)getTrap(key); if (t == null) return; - if (t.f == f) { putTrap(t.name, t.next); return; } + if (t.f == f) { putTrap(t.target, t.next); return; } for(; t.next != null; t = t.next) if (t.next.f == f) { t.next = t.next.next; return; } } diff --git a/src/org/ibex/js/JSScope.java b/src/org/ibex/js/JSScope.java index f7c6355..f7d3d6d 100644 --- a/src/org/ibex/js/JSScope.java +++ b/src/org/ibex/js/JSScope.java @@ -2,7 +2,6 @@ package org.ibex.js; // FIXME: should allow parentScope to be a JS, not a JSScope -// FIXME: Index local vars by number and lookup in an array /** Implementation of a JavaScript Scope */ // HACK: JSScope doesn't really need the BT, this is just for Box.java public class JSScope extends JS.BT { diff --git a/src/org/ibex/js/Test.java b/src/org/ibex/js/Test.java index 8e4be33..478ef8e 100644 --- a/src/org/ibex/js/Test.java +++ b/src/org/ibex/js/Test.java @@ -31,6 +31,7 @@ public class Test extends JS { public JS get(JS key) throws JSExn { if(!JS.isString(key)) return null; if("print".equals(JS.toString(key))) return METHOD; + if("clone".equals(JS.toString(key))) return METHOD; if("bgget".equals(JS.toString(key))) { action = "bgget"; try { @@ -51,8 +52,12 @@ public class Test extends JS { } catch(NotPauseableException e) { throw new Error("should never happen"); } - return; - } + return; + } + if("exit".equals(JS.toString(key))) { + System.exit(JS.toInt(val)); + return; + } super.put(key,val); } @@ -62,6 +67,7 @@ public class Test extends JS { System.out.println(JS.debugToString(a0)); return null; } + if("clone".equals(JS.toString(method))) return a0 == null ? null : a0.jsclone(); return null; } } diff --git a/src/org/ibex/js/Trap.java b/src/org/ibex/js/Trap.java index 67d0238..580ed69 100644 --- a/src/org/ibex/js/Trap.java +++ b/src/org/ibex/js/Trap.java @@ -7,43 +7,22 @@ package org.ibex.js; * linked list stack, with the most recently placed trap at the head * of the list. */ -class Trap { +final class Trap { - JS trapee = null; ///< the box on which this trap was placed - JS name = null; ///< the property that the trap was placed on + final JS target; ///< the box on which this trap was placed + final JS key; ///< the property that the trap was placed on - JSFunction f = null; ///< the function for this trap - Trap next = null; ///< the next trap down the trap stack + final JSFunction f; ///< the function for this trap + Trap next; ///< the next trap down the trap stack Trap(JS b, JS n, JSFunction f, Trap nx) { - trapee = b; name = n; this.f = f; this.next = nx; + target = b; key = n; this.f = f; this.next = nx; } - - static final JSFunction putInvoker = new JSFunction("putInvoker", 0, null); - static final JSFunction getInvoker = new JSFunction("getInvoker", 0, null); - - static { - putInvoker.add(1, ByteCodes.PUT, null); - putInvoker.add(2, Tokens.RETURN, null); - getInvoker.add(1, ByteCodes.GET, null); - getInvoker.add(2, Tokens.RETURN, null); - } - - boolean readTrap() { return f.numFormalArgs == 0; } - boolean writeTrap() { return f.numFormalArgs != 0; } - void invoke(JS value) throws JSExn { - Interpreter i = new Interpreter(putInvoker, false, null); - i.stack.push(trapee); - i.stack.push(name); - i.stack.push(value); - i.resume(); - } - - JS invoke() throws JSExn { - Interpreter i = new Interpreter(getInvoker, false, null); - i.stack.push(trapee); - i.stack.push(name); - return i.resume(); - } + boolean isReadTrap() { return f.numFormalArgs == 0; } + boolean isWriteTrap() { return f.numFormalArgs != 0; } + Trap readTrap() { Trap t = this; while(t!=null && t.isWriteTrap()) t = t.next; return t; } + Trap writeTrap() { Trap t = this; while(t!=null && t.isReadTrap()) t = t.next; return t; } + Trap nextReadTrap() { return next == null ? null : next.readTrap(); } + Trap nextWriteTrap() { return next == null ? null : next.writeTrap(); } } -- 1.7.10.4