final Stack stack = new Stack(); ///< the object stack
int pc = 0; ///< the program counter
- Interpreter(JSFunction f, boolean pauseable, JSArray args) {
+ Interpreter(JSFunction f, boolean pauseable, JSArgs args) {
this.f = f;
this.pausecount = pauseable ? 0 : -1;
this.scope = new JSScope(f.parentScope);
if(t != null) {
tm.t = t;
stack.push(tm);
- JSArray args = new JSArray();
- args.addElement(tm.val);
- stack.push(args);
+ stack.push(new JSArgs(tm.val,t.f));
f = t.f;
scope = new JSScope(f.parentScope);
pc = -1;
if(t != null) {
stack.push(new TrapMarker(this,t,target,key,val));
- JSArray args = new JSArray();
- args.addElement(val);
- stack.push(args);
+ stack.push(new JSArgs(t.f));
f = t.f;
scope = new TrapScope(f.parentScope,target,f,key);
pc = -1;
if(t != null) {
stack.push(new TrapMarker(this,t,(JS)target,key,null));
- stack.push(new JSArray());
+ stack.push(new JSArgs(t.f));
f = t.f;
scope = new TrapScope(f.parentScope,target,f,key);
pc = -1;
case CALL: case CALLMETHOD: {
int numArgs = JS.toInt((JS)arg);
+
+ JS[] rest = numArgs > 3 ? new JS[numArgs - 3] : null;
+ for(int i=numArgs - 1; i>2; i--) rest[i-3] = stack.pop();
+ JS a2 = numArgs <= 2 ? null : stack.pop();
+ JS a1 = numArgs <= 1 ? null : stack.pop();
+ JS a0 = numArgs <= 0 ? null : stack.pop();
+
JS method = null;
JS ret = null;
JS object = stack.pop();
stack.pop();
}
}
- JS[] rest = numArgs > 3 ? new JS[numArgs - 3] : null;
- for(int i=numArgs - 1; i>2; i--) rest[i-3] = stack.pop();
- JS a2 = numArgs <= 2 ? null : stack.pop();
- JS a1 = numArgs <= 1 ? null : stack.pop();
- JS a0 = numArgs <= 0 ? null : stack.pop();
-
if (object instanceof JSFunction) {
- // FIXME: use something similar to call0/call1/call2 here
- JSArray arguments = new JSArray();
- for(int i=0; i<numArgs; i++) arguments.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
stack.push(new CallMarker(this));
- stack.push(arguments);
+ stack.push(new JSArgs(a0,a1,a2,rest,numArgs,object));
f = (JSFunction)object;
scope = new JSScope(f.parentScope);
pc = -1;
return super.get(key);
}
}
+
+ static class JSArgs extends JS {
+ private final JS a0;
+ private final JS a1;
+ private final JS a2;
+ private final JS[] rest;
+ private final int nargs;
+ private final JS callee;
+
+ public JSArgs(JS callee) { this(null,null,null,null,0,callee); }
+ public JSArgs(JS a0, JS callee) { this(a0,null,null,null,1,callee); }
+ public JSArgs(JS a0, JS a1, JS a2, JS[] rest, int nargs, JS callee) {
+ this.a0 = a0; this.a1 = a1; this.a2 = a2;
+ this.rest = rest; this.nargs = nargs;
+ this.callee = callee;
+ }
+
+ public JS get(JS key) throws JSExn {
+ if(JS.isInt(key)) {
+ int n = JS.toInt(key);
+ switch(n) {
+ case 0: return a0;
+ case 1: return a1;
+ case 2: return a2;
+ default: return n>= 0 && n < nargs ? rest[n-3] : null;
+ }
+ }
+ //#switch(JS.toString(key))
+ case "callee": return callee;
+ case "length": return JS.N(nargs);
+ //#end
+ return super.get(key);
+ }
+ }
static class Stub extends JS {
private JS method;
JS[] stack2 = new JS[stack.length * 2];
System.arraycopy(stack,0,stack2,0,stack.length);
}
- // FIXME: Eliminate all uses of SWAP n>1 so we don't need this
public int size() { return sp; }
- public void setElementAt(JS o, int i) { stack[i] = o; }
public JS elementAt(int i) { return stack[i]; }
+
+ // FIXME: Eliminate all uses of SWAP n>1 so we don't need this
+ public void setElementAt(JS o, int i) { stack[i] = o; }
}
}
// FEATURE: make sure that this can only be called from the Scheduler...
/** if you enqueue a function, it gets invoked in its own pauseable context */
public void perform() throws JSExn {
- Interpreter i = new Interpreter(this, true, new JSArray());
+ Interpreter i = new Interpreter(this, true, new Interpreter.JSArgs(this));
i.resume();
}
/** Note: code gets run in an <i>unpauseable</i> context. */
public JS call(JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- JSArray args = new JSArray();
- if (nargs > 0) args.addElement(a0);
- if (nargs > 1) args.addElement(a1);
- if (nargs > 2) args.addElement(a2);
- for(int i=3; i<nargs; i++) args.addElement(rest[i-3]);
- Interpreter cx = new Interpreter(this, false, args);
+ Interpreter cx = new Interpreter(this, false, new Interpreter.JSArgs(a0,a1,a2,rest,nargs,this));
return cx.resume();
}
// Method calls are implemented by doing a GET_PRESERVE
// first. If the object supports method calls, it will
// return JS.METHOD
- int n = parseArgs(b, 2);
b.add(parserLine, GET_PRESERVE);
+ int n = parseArgs(b,0);
b.add(parserLine, CALLMETHOD, JS.N(n));
break;
}
switch (tok) {
case LP: { // invocation (not grouping)
- int n = parseArgs(b, 1);
+ int n = parseArgs(b,0);
b.add(parserLine, CALL, JS.N(n));
break;
}
i++;
if (peekToken() != COMMA) {
startExpr(b, NO_COMMA);
- b.add(parserLine, SWAP, JS.N(pushdown));
+ if(pushdown != 0) b.add(parserLine, SWAP, JS.N(pushdown));
if (peekToken() == RP) break;
}
consume(COMMA);