case JMP: cx.pc += JS.toNumber(arg).intValue() - 1; break;
case POP: cx.stack.pop(); break;
case SWAP: {
- int depth = (1 + (arg == null ? 1 : toInt(arg)));
+ int depth = (arg == null ? 1 : toInt(arg));
Object save = cx.stack.elementAt(cx.stack.size() - 1);
- for(int i=cx.stack.size() - 1; i > cx.stack.size() - depth; i--)
+ for(int i=cx.stack.size() - 1; i > cx.stack.size() - 1 - depth; i--)
cx.stack.setElementAt(cx.stack.elementAt(i-1), i);
- cx.stack.setElementAt(save, cx.stack.size() - depth);
+ cx.stack.setElementAt(save, cx.stack.size() - depth - 1);
break; }
case DUP: cx.stack.push(cx.stack.peek()); break;
case NEWSCOPE: cx.scope = new JSScope(cx.scope); break;
}
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 value");
+ if (o == null) throw je("tried to get property \"" + v + "\" from the null value @" + cx.pc + "\n" + cx.f.dump());
if (o instanceof String || o instanceof Number || o instanceof Boolean) {
ret = Internal.getFromPrimitive(o,v);
cx.stack.push(ret);
case CALL: case CALLMETHOD: {
int numArgs = JS.toInt(arg);
- JSArray arguments = null;
- Object arg0 = null;
- Object arg1 = null;
- Object o = cx.stack.pop();
- if(o == null) throw je("attempted to call null");
- Object ret;
Object method = null;
+ Object object = null;
+ Object ret = null;
+ JSArray arguments = null;
+
if(op == CALLMETHOD) {
- method = o;
- if (method == null) throw new JS.Exn("cannot call the null method");
- o = cx.stack.pop();
- if(o instanceof String || o instanceof Number || o instanceof Boolean) {
- arguments = new JSArray();
- for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
- ret = Internal.callMethodOnPrimitive(o, method, arguments);
- cx.stack.push(ret);
- cx.pc += 2; // skip the GET and CALL
- break;
- } else if (o instanceof JSCallable) {
- cx.pc += 2; // skip the GET and CALL
- // fall through
- } else {
- // put the args back on the stack and let the GET followed by CALL happen
- cx.stack.push(o);
- cx.stack.push(method);
- break;
+ Object getResult = cx.stack.pop();
+ method = cx.stack.pop();
+ object = cx.stack.pop();
+ if (getResult != null) {
+ method = null;
+ object = getResult;
}
+ } else {
+ method = null;
+ object = cx.stack.pop();
+ }
+
+ if (object instanceof String || object instanceof Number || object instanceof Boolean) {
+ arguments = new JSArray(); for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ ret = Internal.callMethodOnPrimitive(object, method, arguments);
- } else if (o instanceof JSFunction) {
+ } else if (object instanceof JSFunction) {
// FEATURE: use something similar to call0/call1/call2 here
- arguments = new JSArray();
- for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ arguments = new JSArray(); for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
cx.stack.push(new CallMarker(cx));
cx.stack.push(arguments);
- cx.f = (JSFunction)o;
+ cx.f = (JSFunction)object;
cx.scope = new JSScope(cx.f.parentJSScope);
cx.pc = -1;
break;
- }
- if (!(o instanceof JSCallable)) throw new JS.Exn("can't call " + o + " @ " + cx.pc + "\n" + cx.f.dump());
- JSCallable c = ((JSCallable)o);
- switch(numArgs) {
- case 0: ret = c.call0(method); break;
- case 1: ret = c.call1(method, cx.stack.pop()); break;
- case 2: { Object first = cx.stack.pop(); ret = c.call2(method, cx.stack.pop(), first); break; }
- default: {
- arguments = new JSArray();
- for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
- ret = c.call(method, arguments);
- if (cx.pausecount > initialPauseCount) return null; // we were paused
- break;
+ } else if (object instanceof JSCallable) {
+ JSCallable c = (JSCallable)object;
+ switch(numArgs) {
+ case 0: ret = c.call0(method); break;
+ case 1: ret = c.call1(method, cx.stack.pop()); break;
+ case 2: {
+ Object first = cx.stack.pop();
+ Object second = cx.stack.pop();
+ ret = c.call2(method, second, first);
+ break;
+ }
+ default: {
+ arguments = new JSArray();
+ for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ ret = c.call(method, arguments);
+ break;
+ }
}
+ } else {
+ throw new JS.Exn("can't call a " + object.getClass().getName() + " @" + cx.pc + "\n" + cx.f.dump());
}
+ if (cx.pausecount > initialPauseCount) return null;
cx.stack.push(ret);
-
break;
}