2003/11/03 00:08:26
[org.ibex.core.git] / src / org / xwt / js / CompiledFunctionImpl.java
index 2c69e1d..90f0322 100644 (file)
@@ -102,17 +102,6 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens {
         try {
             if (cx.paused) return null;
             cx.bind();
-            if (cx.tailCallFunction != null) {
-                cx.stack.pop();  // discard actual return value
-                cx.pc -= 2;
-                cx.stack.push(new CallMarker(cx));
-                cx.stack.push(cx.tailCallArgs);
-                cx.currentCompiledFunction = cx.tailCallFunction;
-                cx.tailCallFunction = null;
-                cx.tailCallArgs = null;
-                cx.scope = new FunctionScope("unknown", cx.currentCompiledFunction.parentScope);
-                cx.pc = 0;
-            }
             if (cx.currentCompiledFunction == null) return cx.stack.pop();
             if (cx.pc >= ((CompiledFunctionImpl)cx.currentCompiledFunction).size) return cx.stack.pop();
             String label = null;
@@ -245,8 +234,18 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens {
                     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");
-                ((JS)target).put(key, val);
+                // 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;
+                }
                 break;
             }
 
@@ -268,6 +267,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens {
                     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;
+                    }
                 } else 
                     throw je("tried to get property " + v + " from a " + o.getClass().getName());
                 cx.stack.push(ret);
@@ -298,6 +305,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens {
                             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);
@@ -314,6 +329,14 @@ class CompiledFunctionImpl extends JS.Obj implements ByteCodes, Tokens {
                     
                 } 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;
+                    }
                 }
                 cx.stack.push(ret);
                 break;