cleaned up trap handling in Interpreter.java
authorbrian <brian@brianweb.net>
Sat, 3 Jul 2004 14:46:18 +0000 (14:46 +0000)
committerbrian <brian@brianweb.net>
Sat, 3 Jul 2004 14:46:18 +0000 (14:46 +0000)
darcs-hash:20040703144618-24bed-17896b73aab9000aeeb7b666c052ae99462b1409.gz

src/org/ibex/js/Interpreter.java
src/org/ibex/js/JS.java
src/org/ibex/js/JSExn.java
src/org/ibex/js/JSFunction.java
src/org/ibex/js/JSScope.java
src/org/ibex/js/Trap.java

index 5fac7cb..5ad7014 100644 (file)
@@ -172,26 +172,24 @@ class Interpreter implements ByteCodes, Tokens {
                         pc = ((TryMarker)o).finallyLoc - 1;
                         continue OUTER;
                     } else if (o instanceof CallMarker) {
                         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();
                                     JSArray args = new JSArray();
-                                    args.addElement(ts.val);
+                                    args.addElement(tm.val);
                                     stack.push(args);
                                     f = t.f;
                                     stack.push(args);
                                     f = t.f;
-                                    scope = new Trap.TrapScope(f.parentScope, t, ts.val);
+                                    scope = new JSScope(f.parentScope);
                                     pc = -1;
                                     continue OUTER;
                                     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);
                         pc = ((CallMarker)o).pc - 1;
                         f = (JSFunction)((CallMarker)o).f;
                         stack.push(retval);
+                        if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
                         continue OUTER;
                     }
                 }
                         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");
                     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 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;
                     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;
                     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: {
             }
 
             case GET:
             case GET_PRESERVE: {
-                Object o, v;
+                Object target, key;
                 if (op == GET) {
                 if (op == GET) {
-                    v = arg == null ? stack.pop() : arg;
-                    o = stack.pop();
+                    key = arg == null ? stack.pop() : arg;
+                    target = stack.pop();
                 } else {
                 } else {
-                    v = stack.pop();
-                    o = stack.peek();
-                    stack.push(v);
+                    key = stack.pop();
+                    target = stack.peek();
+                    stack.push(key);
                 }
                 Object ret = null;
                 }
                 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;
                     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);
                     stack.push(ret);
+                    if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
                     break;
                 }
                     break;
                 }
-                throw je("tried to get property " + v + " from a " + o.getClass().getName());
             }
             
             case CALL: case CALLMETHOD: {
             }
             
             case CALL: case CALLMETHOD: {
@@ -473,6 +475,7 @@ class Interpreter implements ByteCodes, Tokens {
             }
 
             default: {
             }
 
             default: {
+                if(op == BITOR) throw new Error("pc: " + pc + " of " + f);
                 Object right = stack.pop();
                 Object left = stack.pop();
                 switch(op) {
                 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 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();
     
     public static class CatchMarker { }
     private static CatchMarker catchMarker = new CatchMarker();
     
index 1e38ce5..65f624e 100644 (file)
@@ -10,14 +10,15 @@ public class JS extends org.ibex.util.BalancedTree {
 
     public static boolean checkAssertions = false;
 
 
     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 {
     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() +")");
     }
     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() +")");
     }
index ff4abc5..6f2a1ab 100644 (file)
@@ -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]);
     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]);
         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 + "\"");*/
             }
         }
     }
             }
         }
     }
index 4bf41e4..40a550d 100644 (file)
@@ -105,10 +105,12 @@ class JSFunction extends JS implements ByteCodes, Tokens, Task {
 
     public String toString() { return "JSFunction [" + sourceName + ":" + firstLine + "]"; }
 
 
     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++) {
         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]]);
             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]));
                 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");
         }
             }
             sb.append("\n");
         }
index f025b24..e133f4c 100644 (file)
@@ -2,6 +2,7 @@
 package org.ibex.js; 
 
 // FIXME: should allow parentScope to be a JS, not a JSScope
 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 { 
 
 /** Implementation of a JavaScript Scope */
 public class JSScope extends JS { 
 
index 77476f6..e2566c5 100644 (file)
@@ -29,6 +29,9 @@ class Trap {
         getInvoker.add(2, Tokens.RETURN, null);
     }
     
         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);
     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?
     }
 
     // FIXME: review; is necessary?
-    static class TrapScope extends JSScope {
+    /*static class TrapScope extends JSScope {
         Trap t;
         Object val = null;
         boolean cascadeHappened = false;
         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);
         }
             if (key.equals("trapname")) return t.name;
             return super.get(key);
         }
-    }
+    }*/
 }
 
 }