private CompiledFunctionImpl cloneWithNewParentScope(JS.Scope s) throws IOException {
CompiledFunctionImpl ret = new JS.CompiledFunction(sourceName, firstLine, null, s);
- ret.paste(this);
+ // Reuse the same op, arg, line, and size variables for the new "instance" of the function
+ // NOTE: Neither *this* function nor the new function should be modified after this call
+ ret.op = this.op;
+ ret.arg = this.arg;
+ ret.line = this.line;
+ ret.size = this.size;
return ret;
}
try {
cx.currentCompiledFunction = (CompiledFunction)this;
int size = cx.stack.size();
- cx.stack.push(new CallMarker());
+ cx.stack.push(callMarker);
cx.stack.push(args);
eval(scope);
Object ret = cx.stack.pop();
// Adding and Altering Bytecodes ///////////////////////////////////////////////////
int get(int pos) { return op[pos]; }
+ Object getArg(int pos) { return arg[pos]; }
void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; }
void set(int pos, Object arg_) { arg[pos] = arg_; }
+ int pop() { size--; arg[size] = null; return op[size]; }
void paste(CompiledFunctionImpl other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
CompiledFunctionImpl add(int line, int op_) { return add(line, op_, null); }
CompiledFunctionImpl add(int line, int op_, Object arg_) {
case LITERAL: t.push(arg[pc]); break;
case OBJECT: t.push(new JS.Obj()); break;
case ARRAY: t.push(new JS.Array(JS.toNumber(arg[pc]).intValue())); break;
- case DECLARE: s.declare((String)t.pop()); break;
+ case DECLARE: s.declare((String)(arg[pc]==null ? t.peek() : arg[pc])); if(arg[pc] != null) t.push(arg[pc]); break;
case TOPSCOPE: t.push(s); break;
case JT: if (JS.toBoolean(t.pop())) pc += JS.toNumber(arg[pc]).intValue() - 1; break;
case JF: if (!JS.toBoolean(t.pop())) pc += JS.toNumber(arg[pc]).intValue() - 1; break;
case GET_PRESERVE: {
Object o, v;
if (op[pc] == GET) {
- v = t.pop();
+ v = arg[pc] == null ? t.pop() : arg[pc];
o = t.pop();
} else {
v = t.pop();
t.push(isPrefix ? val : num);
break;
}
+
+
+ case ADD: {
+ int count = ((Number)arg[pc]).intValue();
+ if(count < 2) throw new Error("this should never happen");
+ if(count == 2) {
+ // common case
+ Object right = t.pop();
+ Object left = t.pop();
+ if(left instanceof String || right instanceof String) t.push(JS.toString(left).concat(JS.toString(right)));
+ else t.push(new Double(JS.toDouble(left) + JS.toDouble(right)));
+ break;
+ }
+ Object[] args = new Object[count];
+ while(--count >= 0) args[count] = t.pop();
+ if(args[0] instanceof String) {
+ StringBuffer sb = new StringBuffer(64);
+ for(int i=0;i<args.length;i++) sb.append(JS.toString(args[i]));
+ t.push(sb.toString());
+ } else {
+ int numStrings = 0;
+ for(int i=0;i<args.length;i++) if(args[i] instanceof String) numStrings++;
+ if(numStrings == 0) {
+ double d = 0.0;
+ for(int i=0;i<args.length;i++) d += JS.toDouble(args[i]);
+ t.push(new Double(d));
+ } else {
+ double d=0.0;
+ int i=0;
+ do {
+ d += JS.toDouble(args[i++]);
+ } while(!(args[i] instanceof String));
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(JS.toString(new Double(d)));
+ while(i < args.length) sb.append(JS.toString(args[i++]));
+ t.push(sb.toString());
+ }
+ }
+ break;
+ }
default: {
Object right = t.pop();
Object left = t.pop();
switch(op[pc]) {
-
- case ADD: {
- Object l = left;
- Object r = right;
- if (l instanceof String || r instanceof String) {
- if (l == null) l = "null";
- if (r == null) r = "null";
- if (l instanceof Number && ((Number)l).doubleValue() == ((Number)l).longValue())
- l = new Long(((Number)l).longValue());
- if (r instanceof Number && ((Number)r).doubleValue() == ((Number)r).longValue())
- r = new Long(((Number)r).longValue());
- t.push(l.toString() + r.toString()); break;
- }
- t.push(new Double(JS.toDouble(l) + JS.toDouble(r))); break;
- }
case BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break;
case BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break;
// FunctionScope /////////////////////////////////////////////////////////////////
- private class FunctionScope extends JS.Scope {
+ private static class FunctionScope extends JS.Scope {
String sourceName;
public FunctionScope(String sourceName, Scope parentScope) { super(parentScope); this.sourceName = sourceName; }
public String getSourceName() { return sourceName; }
// Markers //////////////////////////////////////////////////////////////////////
public static class CallMarker { public CallMarker() { } }
+ private static CallMarker callMarker = new CallMarker();
public static class CatchMarker { public CatchMarker() { } }
private static CatchMarker catchMarker = new CatchMarker();