2003/07/07 04:44:17
[org.ibex.core.git] / src / org / xwt / js / CompiledFunctionImpl.java
index e8fa95f..721b0a4 100644 (file)
@@ -37,7 +37,12 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
 
     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;
     }
 
@@ -63,7 +68,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
         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();
@@ -81,8 +86,10 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
     // 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_) {
@@ -126,7 +133,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
             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;
@@ -249,7 +256,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
             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();
@@ -346,26 +353,51 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
                 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;
@@ -452,7 +484,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
 
     // 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; }
@@ -462,6 +494,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
     // 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();