more trap cleanup, properly handle JS.Clones
[org.ibex.core.git] / src / org / ibex / js / Interpreter.java
index 6fc452b..15d42be 100644 (file)
@@ -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;
         }