X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FCompiledFunctionImpl.java;h=f118b76a16efcfcc0db22d069ec0416b920db305;hb=8235361e8601ae7b36ab707058de3b52225d15a2;hp=217a61372598760c2e5cd87af3fb9b4b844a6ef1;hpb=0c542e57d5c7dbc07a8970d3bff6a819767db4d8;p=org.ibex.core.git diff --git a/src/org/xwt/js/CompiledFunctionImpl.java b/src/org/xwt/js/CompiledFunctionImpl.java index 217a613..f118b76 100644 --- a/src/org/xwt/js/CompiledFunctionImpl.java +++ b/src/org/xwt/js/CompiledFunctionImpl.java @@ -4,12 +4,14 @@ package org.xwt.js; import org.xwt.util.*; import java.io.*; -// FIXME: could use some cleaning up /** a JavaScript function, compiled into bytecode */ -class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens { +class CompiledFunctionImpl extends JS.Callable implements ByteCodes, Tokens { // Fields and Accessors /////////////////////////////////////////////// + /** the number of formal arguments */ + int numFormalArgs = 0; + /** the source code file that this block was drawn from */ private String sourceName; public String getSourceName() throws JS.Exn { return sourceName; } @@ -37,7 +39,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,15 +70,19 @@ 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(); - // FIXME: if we catch an exception in Java, JS won't notice and the stack will be messed up if (cx.stack.size() > size) // this should never happen - throw new Error("ERROR: stack grew by " + (cx.stack.size() - size) + " elements during call"); + throw new Error("ERROR: stack grew by " + (cx.stack.size() - size) + + " elements during call at " + sourceName + ":" + firstLine); return ret; + } catch(Error e) { + // Unwind the stack + while(cx.stack.size() > 0) if(cx.stack.pop() instanceof CallMarker) throw e; + throw new Error("CallMarker not found on the stack"); // should never happen } finally { cx.currentCompiledFunction = saved; } @@ -114,6 +125,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens { int pc; int lastPC = -1; OUTER: for(pc=0; pc= 0; j--) arguments.setElementAt(t.pop(), j); Object o = t.pop(); if(o == null) throw je("attempted to call null"); - try { - Object ret; - if(op[pc] == CALLMETHOD) { - Object method = o; - o = t.pop(); - if(o instanceof String || o instanceof Number || o instanceof Boolean) - ret = Internal.callMethodOnPrimitive(o,method,arguments); - else if(o instanceof JS) - ret = ((JS)o).callMethod(method,arguments,false); - else - throw new JS.Exn("Tried to call a method on an object that isn't a JS object"); - } else { - ret = ((JS.Callable)o).call(arguments); - } - t.push(ret); - break; - } catch (JS.Exn e) { - t.push(e); + Object ret; + if(op[pc] == CALLMETHOD) { + Object method = o; + o = t.pop(); + if(o instanceof String || o instanceof Number || o instanceof Boolean) + ret = Internal.callMethodOnPrimitive(o,method,arguments); + else if(o instanceof JS) + ret = ((JS)o).callMethod(method,arguments,false); + else + throw new JS.Exn("Tried to call a method on an object that isn't a JS object"); + } else { + ret = ((JS.Callable)o).call(arguments); } + t.push(ret); + break; } // fall through if exception was thrown case THROW: { - Object exn = t.pop(); - while(t.size() > 0) { - Object o = t.pop(); - if (o instanceof CatchMarker || o instanceof TryMarker) { - boolean inCatch = o instanceof CatchMarker; - if(inCatch) { - o = t.pop(); - if(((TryMarker)o).finallyLoc < 0) continue; // no finally block, keep going - } - if(!inCatch && ((TryMarker)o).catchLoc >= 0) { - // run the catch block, this will implicitly run the finally block, if it exists - t.push(o); - t.push(catchMarker); - t.push((exn instanceof JS.Exn) ? ((JS.Exn)exn).getObject() : exn); - s = ((TryMarker)o).scope; - pc = ((TryMarker)o).catchLoc - 1; - continue OUTER; - } else { - t.push(exn); - t.push(new FinallyData(THROW)); - s = ((TryMarker)o).scope; - pc = ((TryMarker)o).finallyLoc - 1; - continue OUTER; - } - } - // no handler found within this func - if(o instanceof CallMarker) { - if(exn instanceof JS.Exn) - throw (JS.Exn)exn; - else - throw new JS.Exn(exn); - } - } - throw new Error("error: THROW invoked but couldn't find a Try or Call Marker!"); + Object o = t.pop(); + if(o instanceof JS.Exn) throw (JS.Exn)o; + throw new JS.Exn(o); } case INC: case DEC: { @@ -348,26 +325,78 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens { t.push(isPrefix ? val : num); break; } + + case ASSIGN_SUB: case ASSIGN_ADD: { + Object val = t.pop(); + Object old = t.pop(); + Object key = t.pop(); + Object obj = t.peek(); + if (val instanceof CompiledFunction) { + if (obj instanceof JS.Scope) { + JS.Scope parent = (JS.Scope)obj; + while(parent.getParentScope() != null) parent = parent.getParentScope(); + if (parent instanceof org.xwt.Box) { + if (curOP == ASSIGN_ADD) { + ((org.xwt.Box)parent).addTrap(key, val); + } else { + ((org.xwt.Box)parent).delTrap(key, val); + } + // skip over the "normal" implementation of +=/-= + pc += ((Integer)arg[pc]).intValue() - 1; + break; + } + } + } + // use the "normal" implementation + t.push(key); + t.push(old); + t.push(arg); + 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))); + } else { + 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 0) { + Object o = t.pop(); + if (o instanceof CatchMarker || o instanceof TryMarker) { + boolean inCatch = o instanceof CatchMarker; + if(inCatch) { + o = t.pop(); + if(((TryMarker)o).finallyLoc < 0) continue; // no finally block, keep going + } + if(!inCatch && ((TryMarker)o).catchLoc >= 0) { + // run the catch block, this will implicitly run the finally block, if it exists + t.push(o); + t.push(catchMarker); + t.push(e.getObject()); + s = ((TryMarker)o).scope; + pc = ((TryMarker)o).catchLoc - 1; + continue OUTER; + } else { + t.push(e); + t.push(new FinallyData(THROW)); + s = ((TryMarker)o).scope; + pc = ((TryMarker)o).finallyLoc - 1; + continue OUTER; + } + } + // no handler found within this func + if(o instanceof CallMarker) throw e; + } + throw new Error("couldn't find a Try or Call Marker!"); + } // end try/catch + } // end for // this should never happen, we will ALWAYS have a RETURN at the end of the func throw new Error("Just fell out of CompiledFunction::eval() loop. Last PC was " + lastPC); } @@ -454,7 +513,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; } @@ -464,6 +523,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();