+
+ case CASCADE: {
+ boolean write = JS.toBoolean((JS)arg);
+ JS val = write ? stack.pop() : null;
+ CallMarker o = stack.findCall();
+ if(!(o instanceof TrapMarker)) throw new JSExn("tried to CASCADE while not in a trap");
+ TrapMarker tm = (TrapMarker) o;
+ JS key = tm.t.key;
+ JS target = tm.t.target;
+ if(tm.t.isWriteTrap() != write) throw new JSExn("tried to do a " + (write?"write":"read") + " cascade in a " + (write?"read":"write") + " trap");
+ Trap t = write ? tm.t.nextWriteTrap() : tm.t.nextReadTrap();
+ // FIXME: Doesn't handle multiple levels of clone's (probably can just make this a while loop)
+ if(t == null && target instanceof JS.Clone) {
+ target = ((JS.Clone)target).clonee;
+ t = target.getTrap(key);
+ if(t != null) t = write ? t.writeTrap() : t.readTrap();
+ }
+ if(write) {
+ tm.cascadeHappened = true;
+ stack.push(val);
+ }
+ if(t != null) {
+ setupTrap(t,val,new TrapMarker(this,t,val,tm.pauseOnPut));
+ pc--; // we increment later
+ } else {
+ if(write) {
+ if (tm.pauseOnPut) { pc++; return val; }
+ target.put(key,val);
+ } else {
+ JS ret = target.get(key);
+ if (ret == JS.METHOD) ret = new Stub(target, key);
+ stack.push(ret);
+ }
+ if (pausecount > initialPauseCount) { pc++; return null; } // we were paused
+ }
+ break;
+ }
+