if(op == FINALLY_DONE) {
FinallyData fd = (FinallyData) stack.pop();
if(fd == null) continue OUTER; // NOP
+ if(fd.exn != null) throw fd.exn;
op = fd.op;
arg = fd.arg;
}
int[] jmps = (int[]) arg;
// jmps[0] is how far away the catch block is, jmps[1] is how far away the finally block is
// each can be < 0 if the specified block does not exist
- stack.push(new TryMarker(jmps[0] < 0 ? -1 : pc + jmps[0], jmps[1] < 0 ? -1 : pc + jmps[1], scope));
+ stack.push(new TryMarker(jmps[0] < 0 ? -1 : pc + jmps[0], jmps[1] < 0 ? -1 : pc + jmps[1], this));
break;
}
break;
}
- case THROW: {
- Object o = stack.pop();
- if(o instanceof JSExn) throw (JSExn)o;
- throw new JSExn(o);
- }
+ case THROW:
+ throw new JSExn(stack.pop());
case ASSIGN_SUB: case ASSIGN_ADD: {
Object val = stack.pop();
- Object old = stack.pop();
Object key = stack.pop();
Object obj = stack.peek();
- if (val instanceof JSFunction && obj instanceof JSScope) {
- JSScope parent = (JSScope)obj;
- while(parent.getParentScope() != null) parent = parent.getParentScope();
- if (parent instanceof JS) {
- JS b = (JS)parent;
- if (op == ASSIGN_ADD) b.addTrap(key, (JSFunction)val);
- else b.delTrap(key, (JSFunction)val);
- // skip over the "normal" implementation of +=/-=
- pc += ((Integer)arg).intValue() - 1;
- break;
- }
+ if (val instanceof JSFunction && obj instanceof JS) {
+ // A trap addition/removal
+ JS js = obj instanceof JSScope ? ((JSScope)obj).top() : (JS) obj;
+ if(op == ASSIGN_ADD) js.addTrap(key, (JSFunction)val);
+ else js.delTrap(key, (JSFunction)val);
+ pc += ((Integer)arg).intValue() - 1;
+ } else {
+ // The following setup is VERY important. The generated bytecode depends on the stack
+ // being setup like this (top to bottom) KEY, OBJ, VAL, KEY, OBJ
+ stack.push(key);
+ stack.push(val);
+ stack.push(obj);
+ stack.push(key);
}
- // use the "normal" implementation
- stack.push(key);
- stack.push(old);
- stack.push(val);
break;
}
}
} catch(JSExn e) {
+ if(f.op[pc] != FINALLY_DONE) e.addBacktrace(f.sourceName,f.line[pc]);
while(stack.size() > 0) {
Object o = stack.pop();
if (o instanceof CatchMarker || o instanceof TryMarker) {
stack.push(o);
stack.push(catchMarker);
stack.push(e.getObject());
+ f = ((TryMarker)o).f;
scope = ((TryMarker)o).scope;
pc = ((TryMarker)o).catchLoc - 1;
continue OUTER;
} else {
- stack.push(e);
- stack.push(new FinallyData(THROW));
+ stack.push(new FinallyData(e));
+ f = ((TryMarker)o).f;
scope = ((TryMarker)o).scope;
pc = ((TryMarker)o).finallyLoc - 1;
continue OUTER;
}
+ } else if(o instanceof CallMarker) {
+ CallMarker cm = (CallMarker) o;
+ if(cm.f == null)
+ e.addBacktrace("<java>",0); // This might not even be worth mentioning
+ else
+ e.addBacktrace(cm.f.sourceName,cm.f.line[cm.pc-1]);
}
- // no handler found within this func
- if(o instanceof CallMarker) throw e;
}
throw e;
} // end try/catch
public int catchLoc;
public int finallyLoc;
public JSScope scope;
- public TryMarker(int catchLoc, int finallyLoc, JSScope scope) {
+ public JSFunction f;
+ public TryMarker(int catchLoc, int finallyLoc, Interpreter cx) {
this.catchLoc = catchLoc;
this.finallyLoc = finallyLoc;
- this.scope = scope;
+ this.scope = cx.scope;
+ this.f = cx.f;
}
}
public static class FinallyData {
public int op;
public Object arg;
- public FinallyData(int op, Object arg) { this.op = op; this.arg = arg; }
+ public JSExn exn;
public FinallyData(int op) { this(op,null); }
+ public FinallyData(int op, Object arg) { this.op = op; this.arg = arg; }
+ public FinallyData(JSExn exn) { this.exn = exn; } // Just throw this exn
}
return JS.N(s.lastIndexOf(search,start));
}
case "match": return JSRegexp.stringMatch(s,arg0);
- case "replace": return JSRegexp.stringReplace(s,(String)arg0,arg1);
+ case "replace": return JSRegexp.stringReplace(s,arg0,arg1);
case "search": return JSRegexp.stringSearch(s,arg0);
case "split": return JSRegexp.stringSplit(s,arg0,arg1,alength);
case "toLowerCase": return s.toLowerCase();