From 64b8c4b435a4457e342fd03fc4a725d5ea16da36 Mon Sep 17 00:00:00 2001 From: brian Date: Sat, 3 Jul 2004 14:46:18 +0000 Subject: [PATCH] cleaned up trap handling in Interpreter.java darcs-hash:20040703144618-24bed-17896b73aab9000aeeb7b666c052ae99462b1409.gz --- src/org/ibex/js/Interpreter.java | 196 +++++++++++++++++++++----------------- src/org/ibex/js/JS.java | 5 +- src/org/ibex/js/JSExn.java | 9 +- src/org/ibex/js/JSFunction.java | 6 +- src/org/ibex/js/JSScope.java | 1 + src/org/ibex/js/Trap.java | 7 +- 6 files changed, 126 insertions(+), 98 deletions(-) diff --git a/src/org/ibex/js/Interpreter.java b/src/org/ibex/js/Interpreter.java index 5fac7cb..5ad7014 100644 --- a/src/org/ibex/js/Interpreter.java +++ b/src/org/ibex/js/Interpreter.java @@ -172,26 +172,24 @@ class Interpreter implements ByteCodes, Tokens { pc = ((TryMarker)o).finallyLoc - 1; continue OUTER; } else if (o instanceof CallMarker) { - if (scope instanceof Trap.TrapScope) { // handles return component of a read trap - Trap.TrapScope ts = (Trap.TrapScope)scope; - if (retval != null && retval instanceof Boolean && ((Boolean)retval).booleanValue()) - ts.cascadeHappened = true; - if (!ts.cascadeHappened) { - ts.cascadeHappened = true; - Trap t = ts.t.next; - while (t != null && t.f.numFormalArgs == 0) t = t.next; - if (t == null) { - ((JS)ts.t.trapee).put(ts.t.name, ts.val); - if (pausecount > initialPauseCount) { pc++; return null; } // we were paused - } else { - stack.push(o); + 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); + if(cascade) { + Trap t = tm.t.next; + while(t != null && t.readTrap()) t = t.next; + if(t != null) { + tm.t = t; + stack.push(tm); JSArray args = new JSArray(); - args.addElement(ts.val); + args.addElement(tm.val); stack.push(args); f = t.f; - scope = new Trap.TrapScope(f.parentScope, t, ts.val); + scope = new JSScope(f.parentScope); pc = -1; continue OUTER; + } else { + tm.trapee.put(tm.key,tm.val); } } } @@ -199,6 +197,7 @@ class Interpreter implements ByteCodes, Tokens { pc = ((CallMarker)o).pc - 1; f = (JSFunction)((CallMarker)o).f; stack.push(retval); + if (pausecount > initialPauseCount) { pc++; return null; } // we were paused continue OUTER; } } @@ -215,106 +214,109 @@ class Interpreter implements ByteCodes, Tokens { throw je("tried to put a value to the " + key + " property on a " + target.getClass().getName()); if (key == null) throw je("tried to assign \"" + (val==null?"(null)":val.toString()) + "\" to the null key"); + + if (target instanceof String || target instanceof Number || target instanceof Boolean) throw new JSExn("can't put values to primitives"); + if(!(target instanceof JS)) throw new Error("should never happen"); Trap t = null; - Trap.TrapScope ts = null; - if (target instanceof JSScope && key.equals("cascade")) { - JSScope p = (JSScope)target; // search the scope-path for the trap - if (target instanceof Trap.TrapScope) { - ts = (Trap.TrapScope)target; - } else { - while (ts == null && p.getParentScope() != null) { - p = p.getParentScope(); - if (p instanceof Trap.TrapScope) ts = (Trap.TrapScope)p; - } - } - if(ts != null) { - t = ts.t.next; - ts.cascadeHappened = true; - while (t != null && t.f.numFormalArgs == 0) t = t.next; - if (t == null) { target = ts.t.trapee; key = ts.t.name; } + TrapMarker tm = null; + if(target instanceof JSScope && key.equals("cascade")) { + Object o=null; + int i; + for(i=stack.size()-1;i>=0;i--) if((o = stack.elementAt(i)) instanceof CallMarker) break; + if(i==0) throw new Error("didn't find a call marker while doing cascade"); + if(o instanceof TrapMarker) { + tm = (TrapMarker) o; + target = tm.trapee; + key = tm.key; + tm.cascadeHappened = true; + t = tm.t; + if(t.readTrap()) throw new JSExn("can't put to cascade in a read trap"); + t = t.next; + while(t != null && t.readTrap()) t = t.next; } } - if(ts == null) { - if (target instanceof JSScope) { - JSScope p = (JSScope)target; // search the scope-path for the trap - t = p.getTrap(key); - while (t == null && p.getParentScope() != null) { p = p.getParentScope(); t = p.getTrap(key); } - } else { - t = ((JS)target).getTrap(key); - } - while (t != null && t.f.numFormalArgs == 0) t = t.next; // find the first write trap + 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 (t != null) { - stack.push(new CallMarker(this)); - if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow"); + + stack.push(val); + + if(t != null) { + stack.push(new TrapMarker(this,t,(JS)target,key,val)); JSArray args = new JSArray(); args.addElement(val); stack.push(args); f = t.f; - scope = new Trap.TrapScope(f.parentScope, t, val); + scope = new JSScope(f.parentScope); pc = -1; break; + } else { + ((JS)target).put(key,val); + if (pausecount > initialPauseCount) { pc++; return null; } // we were paused + break; } - ((JS)target).put(key, val); - if (pausecount > initialPauseCount) { pc++; return null; } // we were paused - stack.push(val); - break; } case GET: case GET_PRESERVE: { - Object o, v; + Object target, key; if (op == GET) { - v = arg == null ? stack.pop() : arg; - o = stack.pop(); + key = arg == null ? stack.pop() : arg; + target = stack.pop(); } else { - v = stack.pop(); - o = stack.peek(); - stack.push(v); + key = stack.pop(); + target = stack.peek(); + stack.push(key); } Object ret = null; - if (v == null) throw je("tried to get the null key from " + o); - if (o == null) throw je("tried to get property \"" + v + "\" from the null object"); - if (o instanceof String || o instanceof Number || o instanceof Boolean) { - ret = getFromPrimitive(o,v); + if (key == null) throw je("tried to get the null key from " + target); + if (target == null) throw je("tried to get property \"" + key + "\" from the null object"); + if (target instanceof String || target instanceof Number || target instanceof Boolean) { + ret = getFromPrimitive(target,key); stack.push(ret); break; - } else if (o instanceof JS) { - Trap t = null; - if (o instanceof Trap.TrapScope && v.equals("cascade")) { - t = ((Trap.TrapScope)o).t.next; - while (t != null && t.f.numFormalArgs != 0) t = t.next; - if (t == null) { v = ((Trap.TrapScope)o).t.name; o = ((Trap.TrapScope)o).t.trapee; } - - } else if (o instanceof JS) { - if (o instanceof JSScope) { - JSScope p = (JSScope)o; // search the scope-path for the trap - t = p.getTrap(v); - while (t == null && p.getParentScope() != null) { p = p.getParentScope(); t = p.getTrap(v); } - } else { - t = ((JS)o).getTrap(v); - } - while (t != null && t.f.numFormalArgs != 0) t = t.next; // get first read trap - } - if (t != null) { - stack.push(new CallMarker(this)); - if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow"); - JSArray args = new JSArray(); - stack.push(args); - f = t.f; - scope = new Trap.TrapScope(f.parentScope, t, null); - ((Trap.TrapScope)scope).cascadeHappened = true; - pc = -1; - break; + } + if(!(target instanceof JS)) throw new Error("should never happen"); + + Trap t = null; + TrapMarker tm = null; + if(target instanceof JSScope && key.equals("cascade")) { + Object o=null; + int i; + for(i=stack.size()-1;i>=0;i--) if((o = stack.elementAt(i)) instanceof CallMarker) break; + if(i==0) throw new Error("didn't find a call marker while doing cascade"); + if(o instanceof TrapMarker) { + tm = (TrapMarker) o; + target = tm.trapee; + key = tm.key; + t = tm.t; + if(t.writeTrap()) throw new JSExn("can't do a write cascade in a read trap"); + t = t.next; + while(t != null && t.writeTrap()) t = t.next; + if(t != null) tm.cascadeHappened = true; } - ret = ((JS)o).get(v); - if (ret == JS.METHOD) ret = new Stub((JS)o, v); - if (pausecount > initialPauseCount) { pc++; return null; } // we were paused + } + 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.writeTrap()) t = t.next; + } + + if(t != null) { + stack.push(new TrapMarker(this,t,(JS)target,key,null)); + stack.push(new JSArray()); + f = t.f; + scope = new JSScope(f.parentScope); + pc = -1; + break; + } else { + ret = ((JS)target).get(key); + if (ret == JS.METHOD) ret = new Stub((JS)target, key); stack.push(ret); + if (pausecount > initialPauseCount) { pc++; return null; } // we were paused break; } - throw je("tried to get property " + v + " from a " + o.getClass().getName()); } case CALL: case CALLMETHOD: { @@ -473,6 +475,7 @@ class Interpreter implements ByteCodes, Tokens { } default: { + if(op == BITOR) throw new Error("pc: " + pc + " of " + f); Object right = stack.pop(); Object left = stack.pop(); switch(op) { @@ -567,6 +570,21 @@ class Interpreter implements ByteCodes, Tokens { public CallMarker(Interpreter cx) { pc = cx.pc + 1; scope = cx.scope; f = cx.f; } } + public static class TrapMarker extends CallMarker { + Trap t; + JS trapee; + Object key; + Object val; + boolean cascadeHappened; + public TrapMarker(Interpreter cx, Trap t, JS trapee, Object key, Object val) { + super(cx); + this.t = t; + this.trapee = trapee; + this.key = key; + this.val = val; + } + } + public static class CatchMarker { } private static CatchMarker catchMarker = new CatchMarker(); diff --git a/src/org/ibex/js/JS.java b/src/org/ibex/js/JS.java index 1e38ce5..65f624e 100644 --- a/src/org/ibex/js/JS.java +++ b/src/org/ibex/js/JS.java @@ -10,14 +10,15 @@ public class JS extends org.ibex.util.BalancedTree { public static boolean checkAssertions = false; - public static final Object METHOD = new Object(); + public static final Object METHOD = new Object() { public String toString() { return "JS.METHOD"; } }; public final JS unclone() { return _unclone(); } public Enumeration keys() throws JSExn { return entries == null ? emptyEnumeration : entries.keys(); } public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); } public void put(Object key, Object val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); } public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn { - throw new JSExn("attempted to call the null value (method "+method+")"); + throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")"); } + // FIXME: JSArgs objects, pointers into stack frame public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn { throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")"); } diff --git a/src/org/ibex/js/JSExn.java b/src/org/ibex/js/JSExn.java index ff4abc5..6f2a1ab 100644 --- a/src/org/ibex/js/JSExn.java +++ b/src/org/ibex/js/JSExn.java @@ -16,16 +16,17 @@ public class JSExn extends Exception { public JSExn(Object js, Vec stack, JSFunction f, int pc, JSScope scope) { this.js = js; fill(stack, f, pc, scope); } private void fill(Vec stack, JSFunction f, int pc, JSScope scope) { addBacktrace(f.sourceName + ":" + f.line[pc]); - if (scope != null && scope instanceof Trap.TrapScope) - addBacktrace("trap on property \"" + ((Trap.TrapScope)scope).t.name + "\""); + // FIXME: "trap on property" + /*if (scope != null && scope instanceof Trap.TrapScope) + addBacktrace("trap on property \"" + ((Trap.TrapScope)scope).t.name + "\"");*/ for(int i=stack.size()-1; i>=0; i--) { Object element = stack.elementAt(i); if (element instanceof Interpreter.CallMarker) { Interpreter.CallMarker cm = (Interpreter.CallMarker)element; if (cm.f != null) addBacktrace(cm.f.sourceName + ":" + cm.f.line[cm.pc-1]); - if (cm.scope != null && cm.scope instanceof Trap.TrapScope) - addBacktrace("trap on property \"" + ((Trap.TrapScope)cm.scope).t.name + "\""); + /*if (cm.scope != null && cm.scope instanceof Trap.TrapScope) + addBacktrace("trap on property \"" + ((Trap.TrapScope)cm.scope).t.name + "\"");*/ } } } diff --git a/src/org/ibex/js/JSFunction.java b/src/org/ibex/js/JSFunction.java index 4bf41e4..40a550d 100644 --- a/src/org/ibex/js/JSFunction.java +++ b/src/org/ibex/js/JSFunction.java @@ -105,10 +105,12 @@ class JSFunction extends JS implements ByteCodes, Tokens, Task { public String toString() { return "JSFunction [" + sourceName + ":" + firstLine + "]"; } - public String dump() { + String dump() { return dump(""); } + private String dump(String prefix) { StringBuffer sb = new StringBuffer(1024); sb.append("\n" + sourceName + ": " + firstLine + "\n"); for (int i=0; i < size; i++) { + sb.append(prefix); sb.append(i).append(" (").append(line[i]).append(") :"); if (op[i] < 0) sb.append(bytecodeToString[-op[i]]); else sb.append(codeToString[op[i]]); @@ -120,6 +122,8 @@ class JSFunction extends JS implements ByteCodes, Tokens, Task { int[] jmps = (int[]) arg[i]; sb.append(" catch: ").append(jmps[0] < 0 ? "No catch block" : ""+(i+jmps[0])); sb.append(" finally: ").append(jmps[1] < 0 ? "No finally block" : ""+(i+jmps[1])); + } else if(op[i] == NEWFUNCTION) { + sb.append(((JSFunction) arg[i]).dump(prefix + " ")); } sb.append("\n"); } diff --git a/src/org/ibex/js/JSScope.java b/src/org/ibex/js/JSScope.java index f025b24..e133f4c 100644 --- a/src/org/ibex/js/JSScope.java +++ b/src/org/ibex/js/JSScope.java @@ -2,6 +2,7 @@ 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 */ public class JSScope extends JS { diff --git a/src/org/ibex/js/Trap.java b/src/org/ibex/js/Trap.java index 77476f6..e2566c5 100644 --- a/src/org/ibex/js/Trap.java +++ b/src/org/ibex/js/Trap.java @@ -29,6 +29,9 @@ class Trap { getInvoker.add(2, Tokens.RETURN, null); } + boolean readTrap() { return f.numFormalArgs == 0; } + boolean writeTrap() { return f.numFormalArgs != 0; } + void invoke(Object value) throws JSExn { Interpreter i = new Interpreter(putInvoker, false, null); i.stack.push(trapee); @@ -45,7 +48,7 @@ class Trap { } // FIXME: review; is necessary? - static class TrapScope extends JSScope { + /*static class TrapScope extends JSScope { Trap t; Object val = null; boolean cascadeHappened = false; @@ -56,6 +59,6 @@ class Trap { if (key.equals("trapname")) return t.name; return super.get(key); } - } + }*/ } -- 1.7.10.4