return this;
}
- public static int getLine(JS.Thread cx) {
- if(cx.pc < 0 || cx.pc >= ((CompiledFunctionImpl)cx.currentCompiledFunction).size) return -1;
- return ((CompiledFunctionImpl)cx.currentCompiledFunction).line[cx.pc];
+ public static int getLine(Context cx) {
+ if(cx.pc < 0 || cx.pc >= ((CompiledFunctionImpl)cx.f).size) return -1;
+ return ((CompiledFunctionImpl)cx.f).line[cx.pc];
}
// Invoking the Bytecode ///////////////////////////////////////////////////////
/** returns false if the thread has been paused */
- static Object eval(final JS.Thread cx) throws JS.Exn {
+ static Object eval(final Context cx, Object pushFirst) throws JS.Exn {
+ cx.stack.push(pushFirst);
OUTER: for(;; cx.pc++) {
try {
- if (cx.paused) return null;
- cx.bind();
- if (cx.currentCompiledFunction == null) return cx.stack.pop();
- if (cx.pc >= ((CompiledFunctionImpl)cx.currentCompiledFunction).size) return cx.stack.pop();
+ if (cx.f == null) return cx.stack.pop();
+ if (cx.pc >= ((CompiledFunctionImpl)cx.f).size) return cx.stack.pop();
String label = null;
- int curOP = cx.currentCompiledFunction.op[cx.pc];
- Object curArg = cx.currentCompiledFunction.arg[cx.pc];
+ int curOP = cx.f.op[cx.pc];
+ Object curArg = cx.f.arg[cx.pc];
+ Object returnedFromJava = null;
+ boolean checkReturnedFromJava = false;
if(curOP == FINALLY_DONE) {
FinallyData fd = (FinallyData) cx.stack.pop();
if(fd == null) continue OUTER; // NOP
case LABEL: break;
case LOOP: {
- cx.stack.push(new LoopMarker(cx.pc, cx.pc > 0 && cx.currentCompiledFunction.op[cx.pc - 1] == LABEL ? (String)cx.currentCompiledFunction.arg[cx.pc - 1] : (String)null, cx.scope));
+ cx.stack.push(new LoopMarker(cx.pc, cx.pc > 0 && cx.f.op[cx.pc - 1] == LABEL ? (String)cx.f.arg[cx.pc - 1] : (String)null, cx.scope));
cx.stack.push(Boolean.TRUE);
break;
}
if (o instanceof LoopMarker) {
if (curArg == null || curArg.equals(((LoopMarker)o).label)) {
int loopInstructionLocation = ((LoopMarker)o).location;
- int endOfLoop = ((Integer)cx.currentCompiledFunction.arg[loopInstructionLocation]).intValue() + loopInstructionLocation;
+ int endOfLoop = ((Integer)cx.f.arg[loopInstructionLocation]).intValue() + loopInstructionLocation;
cx.scope = ((LoopMarker)o).scope;
if (curOP == CONTINUE) { cx.stack.push(o); cx.stack.push(Boolean.FALSE); }
cx.pc = curOP == BREAK ? endOfLoop - 1 : loopInstructionLocation;
}
}
}
- throw new Error("CONTINUE/BREAK invoked but couldn't find a LoopMarker at " + ((CompiledFunctionImpl)cx.currentCompiledFunction).sourceName + ":" + getLine(cx));
+ throw new Error("CONTINUE/BREAK invoked but couldn't find a LoopMarker at " + ((CompiledFunctionImpl)cx.f).sourceName + ":" + getLine(cx));
case TRY: {
int[] jmps = (int[]) curArg;
if (o instanceof CallMarker) {
cx.scope = ((CallMarker)o).scope;
cx.pc = ((CallMarker)o).pc;
- cx.currentCompiledFunction = (CompiledFunction)((CallMarker)o).currentCompiledFunction;
+ cx.f = (CompiledFunction)((CallMarker)o).f;
cx.stack.push(retval);
continue OUTER;
}
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");
- // FIXME too many allocations here
- TailCall tail = new TailCall();
- ((JS)target).put(key, val, tail);
- cx.stack.push(val);
- if (tail.func != null) {
- cx.stack.push(new CallMarker(cx));
- cx.stack.push(tail.args);
- cx.currentCompiledFunction = tail.func;
- cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", tail.func.parentScope);
- cx.pc = -1;
- break;
+ returnedFromJava = ((JS)target).put(key, val);
+ if (returnedFromJava != null) {
+ checkReturnedFromJava = true;
+ } else {
+ cx.stack.push(val);
}
break;
}
if (o instanceof String || o instanceof Number || o instanceof Boolean)
ret = Internal.getFromPrimitive(o,v);
else if (o instanceof JS) {
- ret = ((JS)o).get(v);
- if (ret instanceof JS.TailCall) {
- cx.stack.push(new CallMarker(cx));
- cx.stack.push(((JS.TailCall)ret).args);
- cx.currentCompiledFunction = ((JS.TailCall)ret).func;
- cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)ret).func.parentScope);
- cx.pc = -1;
- break;
- }
+ returnedFromJava = ((JS)o).get(v);
+ checkReturnedFromJava = true;
+ break;
} else
throw je("tried to get property " + v + " from a " + o.getClass().getName());
cx.stack.push(ret);
case CALLMETHOD:
case CALL:
+ case CALL_REVERSED:
{
JS.Array arguments = new JS.Array();
int numArgs = JS.toNumber(curArg).intValue();
arguments.setSize(numArgs);
+ Object o = null;
+ if (curOP == CALL_REVERSED) o = cx.stack.pop();
for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
- Object o = cx.stack.pop();
+ if (curOP != CALL_REVERSED) o = cx.stack.pop();
if(o == null) throw je("attempted to call null");
Object ret;
+
if(curOP == CALLMETHOD) {
Object method = o;
o = cx.stack.pop();
if(o instanceof String || o instanceof Number || o instanceof Boolean) {
ret = Internal.callMethodOnPrimitive(o,method,arguments);
cx.stack.push(ret);
+ cx.pc += 2; // skip the GET and CALL
+ break;
+ } else if (o instanceof JS && ((JS)o).callMethod(method, arguments, true) == Boolean.TRUE) {
+ returnedFromJava = ((JS)o).callMethod(method, arguments, false);
+ checkReturnedFromJava = true;
+ cx.pc += 2; // skip the GET and CALL
break;
- } else if (o instanceof JS) {
- if (((JS)o).callMethod(method, arguments, true) == Boolean.TRUE) {
- ret = ((JS)o).callMethod(method,arguments,false);
- cx.stack.push(ret);
- break;
- } else {
- o = ((JS)o).get(method);
- if (o instanceof JS.TailCall) {
- cx.stack.push(new CallMarker(cx));
- cx.stack.push(((JS.TailCall)o).args);
- cx.currentCompiledFunction = ((JS.TailCall)o).func;
- cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)o).func.parentScope);
- cx.pc = -1;
- break;
- }
- }
} else {
- throw new JS.Exn("Tried to call a method on an object that isn't a JS object: " + o);
+ // put the args back on the stack and let the GET followed by CALL happen
+ for(int j=0; j<numArgs; j++) cx.stack.push(arguments.elementAt(j));
+ cx.stack.push(o);
+ cx.stack.push(method);
+ break;
}
}
if (o instanceof CompiledFunctionImpl) {
cx.stack.push(new CallMarker(cx));
cx.stack.push(arguments);
- cx.currentCompiledFunction = (CompiledFunction)o;
- cx.scope = new FunctionScope("unknown", cx.currentCompiledFunction.parentScope);
+ cx.f = (CompiledFunction)o;
+ cx.scope = new FunctionScope("unknown", cx.f.parentScope);
cx.pc = -1;
break;
} else {
- ret = ((JS.Callable)o).call(arguments);
- if (ret instanceof JS.TailCall) {
- cx.stack.push(new CallMarker(cx));
- cx.stack.push(((JS.TailCall)ret).args);
- cx.currentCompiledFunction = ((JS.TailCall)ret).func;
- cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", ((JS.TailCall)ret).func.parentScope);
- cx.pc = -1;
- break;
- }
+ returnedFromJava = ((JS.Callable)o).call(arguments);
+ checkReturnedFromJava = true;
+ break;
}
- cx.stack.push(ret);
- break;
}
- // fall through if exception was thrown
+
case THROW: {
Object o = cx.stack.pop();
if(o instanceof JS.Exn) throw (JS.Exn)o;
default: throw new Error("unknown opcode " + curOP);
} }
}
+
+ // handle special directions returned from Java callouts
+ // ideally we would do this with exceptions, but they're *very* slow in gcj
+ if (checkReturnedFromJava) {
+ checkReturnedFromJava = false;
+ if (returnedFromJava == Context.pause) {
+ cx.pc++;
+ return Context.pause;
+ } else if (returnedFromJava instanceof TailCall) {
+ cx.stack.push(new CallMarker(cx));
+ cx.stack.push(((JS.TailCall)returnedFromJava).args);
+ cx.f = ((JS.TailCall)returnedFromJava).func;
+ cx.scope = new CompiledFunctionImpl.FunctionScope("unknown", cx.f.parentScope);
+ cx.pc = -1;
+ } else {
+ cx.stack.push(returnedFromJava);
+ }
+ continue OUTER;
+ }
+
+
} catch(JS.Exn e) {
while(cx.stack.size() > 0) {
Object o = cx.stack.pop();
// Exception Stuff ////////////////////////////////////////////////////////////////
static class EvaluatorException extends RuntimeException { public EvaluatorException(String s) { super(s); } }
- static EvaluatorException ee(String s) { throw new EvaluatorException(((CompiledFunctionImpl)(JS.Thread.current()).currentCompiledFunction).sourceName + ":" + JS.Thread.current().getLine() + " " + s); }
- static JS.Exn je(String s) { throw new JS.Exn(((CompiledFunctionImpl)(JS.Thread.current()).currentCompiledFunction).sourceName + ":" + JS.Thread.current().getLine() + " " + s); }
-
+ static EvaluatorException ee(String s) {
+ throw new EvaluatorException(JS.Context.getSourceName() + ":" + JS.Context.getLine() + " " + s);
+ }
+ static JS.Exn je(String s) {
+ throw new JS.Exn(JS.Context.getSourceName() + ":" + JS.Context.getLine() + " " + s);
+ }
// FunctionScope /////////////////////////////////////////////////////////////////
public static class CallMarker {
int pc;
Scope scope;
- CompiledFunctionImpl currentCompiledFunction;
- public CallMarker(JS.Thread cx) { pc = cx.pc + 1; scope = cx.scope; currentCompiledFunction = cx.currentCompiledFunction; }
+ CompiledFunctionImpl f;
+ public CallMarker(Context cx) { pc = cx.pc + 1; scope = cx.scope; f = cx.f; }
}
public static class CatchMarker { public CatchMarker() { } }