X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fjs%2FJSFunction.java;fp=src%2Forg%2Fxwt%2Fjs%2FFunction.java;h=1d068e9ac605b450bc49bc5b0b2d35a9bbfec060;hb=67eeff476179a91ae930ea89cbecde22132ca532;hp=f31d0ff50c445bafe61f557b7c3efdac02c15315;hpb=9d07963a45f2147a62d8897e9c4245c224d98ccb;p=org.ibex.core.git
diff --git a/src/org/xwt/js/Function.java b/src/org/xwt/js/JSFunction.java
similarity index 71%
rename from src/org/xwt/js/Function.java
rename to src/org/xwt/js/JSFunction.java
index f31d0ff..1d068e9 100644
--- a/src/org/xwt/js/Function.java
+++ b/src/org/xwt/js/JSFunction.java
@@ -4,10 +4,15 @@ package org.xwt.js;
import org.xwt.util.*;
import java.io.*;
-/** a JavaScript function, compiled into bytecode */
-public class Function extends JS.Obj implements ByteCodes, Tokens {
-
- public int getNumFormalArgs() { return numFormalArgs; }
+/** A JavaScript function, compiled into bytecode */
+public class JSFunction extends JSCallable implements ByteCodes, Tokens {
+
+ /** Note: code gets run in an unpauseable context. */
+ public Object call(JSArray args) {
+ Context cx = new JSContext(this, false);
+ cx.invoke(args);
+ return cx.stack.pop();
+ }
// Fields and Accessors ///////////////////////////////////////////////
@@ -19,13 +24,13 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
int[] op = new int[10]; ///< the instructions
Object[] arg = new Object[10]; ///< the arguments to the instructions
int size = 0; ///< the number of instruction/argument pairs
- JS.Scope parentScope; ///< the default scope to use as a parent scope when executing this
+ JSScope parentJSScope; ///< the default scope to use as a parent scope when executing this
// Constructors ////////////////////////////////////////////////////////
- private Function cloneWithNewParentScope(JS.Scope s) {
- Function ret = new Function(sourceName, firstLine, s);
+ public JSFunction cloneWithNewParentJSScope(JSScope s) {
+ JSFunction ret = new JSFunction(sourceName, firstLine, s);
// 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;
@@ -36,14 +41,14 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
return ret;
}
- private Function(String sourceName, int firstLine, JS.Scope parentScope) {
+ private JSFunction(String sourceName, int firstLine, JSScope parentJSScope) {
this.sourceName = sourceName;
this.firstLine = firstLine;
- this.parentScope = parentScope;
+ this.parentJSScope = parentJSScope;
}
- protected Function(String sourceName, int firstLine, Reader sourceCode, JS.Scope parentScope) throws IOException {
- this(sourceName, firstLine, parentScope);
+ protected JSFunction(String sourceName, int firstLine, Reader sourceCode, JSScope parentJSScope) throws IOException {
+ this(sourceName, firstLine, parentJSScope);
if (sourceCode == null) return;
Parser p = new Parser(sourceCode, sourceName, firstLine);
while(true) {
@@ -64,9 +69,9 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
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(Function other) { for(int i=0; i= cx.f.size) return cx.stack.pop();
int op = cx.f.op[cx.pc];
Object arg = cx.f.arg[cx.pc];
- Object returnedFromJava = null;
- boolean checkReturnedFromJava = false;
if(op == FINALLY_DONE) {
FinallyData fd = (FinallyData) cx.stack.pop();
if(fd == null) continue OUTER; // NOP
@@ -99,8 +103,8 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
}
switch(op) {
case LITERAL: cx.stack.push(arg); break;
- case OBJECT: cx.stack.push(new JS.Obj()); break;
- case ARRAY: cx.stack.push(new JS.Array(JS.toNumber(arg).intValue())); break;
+ case OBJECT: cx.stack.push(new JSObj()); break;
+ case ARRAY: cx.stack.push(new JSArray(JS.toNumber(arg).intValue())); break;
case DECLARE: cx.scope.declare((String)(arg==null ? cx.stack.peek() : arg)); if(arg != null) cx.stack.push(arg); break;
case TOPSCOPE: cx.stack.push(cx.scope); break;
case JT: if (JS.toBoolean(cx.stack.pop())) cx.pc += JS.toNumber(arg).intValue() - 1; break;
@@ -109,12 +113,12 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
case POP: cx.stack.pop(); break;
case SWAP: { Object o1 = cx.stack.pop(); Object o2 = cx.stack.pop(); cx.stack.push(o1); cx.stack.push(o2); break; }
case DUP: cx.stack.push(cx.stack.peek()); break;
- case NEWSCOPE: cx.scope = new JS.Scope(cx.scope); break;
- case OLDSCOPE: cx.scope = cx.scope.getParentScope(); break;
+ case NEWSCOPE: cx.scope = new JSScope(cx.scope); break;
+ case OLDSCOPE: cx.scope = cx.scope.getParentJSScope(); break;
case ASSERT: if (!JS.toBoolean(cx.stack.pop())) throw je("assertion failed"); break;
case BITNOT: cx.stack.push(new Long(~JS.toLong(cx.stack.pop()))); break;
case BANG: cx.stack.push(new Boolean(!JS.toBoolean(cx.stack.pop()))); break;
- case NEWFUNCTION: cx.stack.push(((Function)arg).cloneWithNewParentScope(cx.scope)); break;
+ case NEWFUNCTION: cx.stack.push(((JSFunction)arg).cloneWithNewParentJSScope(cx.scope)); break;
case LABEL: break;
case TYPEOF: {
@@ -130,10 +134,9 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
case PUSHKEYS: {
Object o = cx.stack.peek();
- Object[] keys = ((JS)o).keys();
- JS.Array a = new JS.Array();
- a.setSize(keys.length);
- for(int j=0; j initialPauseCount) return; // we were paused
+ } else {
+ cx.stack.push(o);
+ JSArray args = new JSArray();
+ args.addElement(ts.val);
+ cx.stack.push(ta);
+ cx.f = t.f;
+ cx.scope = new JSTrap.JSTrapScope(cx.f.parentJSScope, ts.val);
+ cx.pc = -1;
+ break;
+ }
+ }
+ }
cx.scope = ((CallMarker)o).scope;
cx.pc = ((CallMarker)o).pc;
- cx.f = (Function)((CallMarker)o).f;
+ cx.f = (JSFunction)((CallMarker)o).f;
cx.stack.push(retval);
continue OUTER;
}
@@ -210,9 +234,30 @@ public class Function 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");
- returnedFromJava = ((JS)target).put(key, val);
- if (returnedFromJava != null) checkReturnedFromJava = true;
- else cx.stack.push(val);
+ JSTrap t = null;
+ if (o instanceof JSTrap.JSTrappable) {
+ t = ((JSTrap.JSTrappable)o).getTrap(v);
+ while (t != null && t.f.numFormalArgs == 0) t = t.next;
+ } else if (o instanceof JSTrap.JSTrapScope && key.equals("cascade")) {
+ JSTrap.JSTrapScope ts = (JSTrap.JSTrapScope)o;
+ t = ts.t.next;
+ ts.cascadeHappened = true;
+ while (t != null && t.f.numFormalArgs == 0) t = t.next;
+ if (t == null) o = ts.t.trappee;
+ }
+ if (t != null) {
+ cx.stack.push(new CallMarker(cx));
+ JSArray args = new JSArray();
+ args.addElement(val);
+ cx.stack.push(ta);
+ cx.f = t.f;
+ cx.scope = new JSTrap.JSTrapScope(cx.f.parentJSScope, val);
+ cx.pc = -1;
+ break;
+ }
+ ((JS)target).put(key, val);
+ if (cx.pausecount > initialPauseCount) return; // we were paused
+ cx.stack.push(val);
break;
}
@@ -235,53 +280,87 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
cx.stack.push(ret);
break;
} else if (o instanceof JS) {
- returnedFromJava = ((JS)o).get(v);
- checkReturnedFromJava = true;
+ JSTrap t = null;
+ if (o instanceof JSTrap.JSTrappable) {
+ t = ((JSTrap.JSTrappable)o).getTrap(v);
+ while (t != null && t.f.numFormalArgs != 0) t = t.next;
+ } else if (o instanceof JSTrap.JSTrapScope && key.equals("cascade")) {
+ t = ((JSTrap.JSTrapScope)o).t.next;
+ while (t != null && t.f.numFormalArgs != 0) t = t.next;
+ if (t == null) o = ((JSTrap.JSTrapScope)o).t.trappee;
+ }
+ if (t != null) {
+ cx.stack.push(new CallMarker(cx));
+ JSArray args = new JSArray();
+ cx.stack.push(ta);
+ cx.f = t.f;
+ cx.scope = new JSTrap.JSTrapScope(cx.f.parentJSScope, null);
+ ((JSTrap.JSTrapScope)cx.scope).cascadeHappened = true;
+ cx.pc = -1;
+ break;
+ }
+ ret = ((JS)o).get(v);
+ if (cx.pausecount > initialPauseCount) return; // we were paused
+ cx.stack.push(ret);
break;
}
throw je("tried to get property " + v + " from a " + o.getClass().getName());
}
- case CALL: case CALLMETHOD: case CALL_REVERSED: {
- JS.Array arguments = new JS.Array();
+ case CALL: case CALLMETHOD: {
int numArgs = JS.toNumber(arg).intValue();
- arguments.setSize(numArgs);
- Object o = null;
- if (op == CALL_REVERSED) o = cx.stack.pop();
- for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
- if (op != CALL_REVERSED) o = cx.stack.pop();
+ Object o = cx.stack.pop();
if(o == null) throw je("attempted to call null");
Object ret;
-
+ Object method = null;
if(op == CALLMETHOD) {
- Object method = o;
+ method = o;
+ if (method == null) throw new JS.Exn("cannot call the null method");
o = cx.stack.pop();
if(o instanceof String || o instanceof Number || o instanceof Boolean) {
+ JSArray arguments = new JSArray();
+ for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
ret = Internal.callMethodOnPrimitive(o,method,arguments);
cx.stack.push(ret);
cx.pc += 2; // skip the GET and CALL
- } else if (o instanceof JS && ((JS)o).callMethod(method, arguments, true) == Boolean.TRUE) {
- returnedFromJava = ((JS)o).callMethod(method, arguments, false);
- checkReturnedFromJava = true;
- cx.pc += 2; // skip the GET and CALL
+ break;
+ } else if (o instanceof JSCallable) {
+ // fall through
} else {
// put the args back on the stack and let the GET followed by CALL happen
- for(int j=0; j= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
cx.stack.push(new CallMarker(cx));
cx.stack.push(arguments);
- cx.f = (Function)o;
- cx.scope = new Scope(cx.f.parentScope);
+ cx.f = (JSFunction)o;
+ cx.scope = new JSScope(cx.f.parentJSScope);
cx.pc = -1;
-
- } else {
- returnedFromJava = ((JS.Callable)o).call(arguments);
- checkReturnedFromJava = true;
+ break;
+ }
+
+ JSCallable c = ((JSCallable)o);
+ switch(numArgs) {
+ case 0: ret = c.call0(method); break;
+ case 1: ret = c.call1(method, cx.stack.pop()); break;
+ case 2: ret = c.call2(method, cx.stack.pop(), cx.stack.pop()); break;
+ default: {
+ JSArray arguments = new JSArray();
+ for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ ret = c.call(method, arguments);
+ if (cx.pausecount > initialPauseCount) return; // we were paused
+ break;
+ }
}
+ cx.stack.push(ret);
+ if (method != null) cx.pc += 2; // skip the GET and CALL if this was a GETCALL
+
break;
}
@@ -291,28 +370,18 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
throw new JS.Exn(o);
}
- case INC: case DEC: {
- boolean isPrefix = JS.toBoolean(arg);
- Object key = cx.stack.pop();
- JS obj = (JS)cx.stack.pop();
- Number num = JS.toNumber(obj.get(key));
- Number val = new Double(op == INC ? num.doubleValue() + 1.0 : num.doubleValue() - 1.0);
- obj.put(key, val);
- cx.stack.push(isPrefix ? val : num);
- break;
- }
-
case ASSIGN_SUB: case ASSIGN_ADD: {
Object val = cx.stack.pop();
Object old = cx.stack.pop();
Object key = cx.stack.pop();
Object obj = cx.stack.peek();
- if (val instanceof Function && obj instanceof JS.Scope) {
- JS.Scope parent = (JS.Scope)obj;
- while(parent.getParentScope() != null) parent = parent.getParentScope();
- if (parent instanceof org.xwt.Box) {
- org.xwt.Box b = (org.xwt.Box)parent;
- if (op == ASSIGN_ADD) b.addTrap(key, val); else b.delTrap(key, val);
+ if (val instanceof JSFunction && obj instanceof JSScope) {
+ JSScope parent = (JSScope)obj;
+ while(parent.getParentJSScope() != null) parent = parent.getParentJSScope();
+ if (parent instanceof JSTrap.JSTrappable) {
+ JSTrap.JSTrappable b = (JSTrap.JSTrappable)parent;
+ if (op == ASSIGN_ADD) JSTrap.addTrap(b, key, (JSFunction)val);
+ else JSTrap.delTrap(b, key, (JSFunction)val);
// skip over the "normal" implementation of +=/-=
cx.pc += ((Integer)arg).intValue() - 1;
break;
@@ -418,26 +487,6 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
} }
}
- // handle special directions returned from Java callouts
- // ideally we would do this with exceptions, but they're *very* slow in gcj
- if (checkReturnedFromJava) {
- checkReturnedFromJava = false;
- if (returnedFromJava == Context.pause) {
- cx.pc++;
- return Context.pause;
- } else if (returnedFromJava instanceof TailCall) {
- cx.stack.push(new CallMarker(cx));
- cx.stack.push(((JS.TailCall)returnedFromJava).args);
- cx.f = ((JS.TailCall)returnedFromJava).func;
- cx.scope = new Scope(cx.f.parentScope);
- cx.pc = -1;
- } else {
- cx.stack.push(returnedFromJava);
- }
- continue OUTER;
- }
-
-
} catch(JS.Exn e) {
while(cx.stack.size() > 0) {
Object o = cx.stack.pop();
@@ -474,7 +523,7 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
// Debugging //////////////////////////////////////////////////////////////////////
- public String toString() { return "Function [" + sourceName + ":" + firstLine + "]"; }
+ public String toString() { return "JSFunction [" + sourceName + ":" + firstLine + "]"; }
public String dump() {
StringBuffer sb = new StringBuffer(1024);
sb.append("\n" + sourceName + ": " + firstLine + "\n");
@@ -504,10 +553,10 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
static class EvaluatorException extends RuntimeException { public EvaluatorException(String s) { super(s); } }
static EvaluatorException ee(String s) {
- throw new EvaluatorException(Context.getSourceName() + ":" + Context.getLine() + " " + s);
+ throw new EvaluatorException(JSContext.getSourceName() + ":" + JSContext.getLine() + " " + s);
}
static JS.Exn je(String s) {
- throw new JS.Exn(Context.getSourceName() + ":" + Context.getLine() + " " + s);
+ throw new JS.Exn(JSContext.getSourceName() + ":" + JSContext.getLine() + " " + s);
}
@@ -515,9 +564,9 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
public static class CallMarker {
int pc;
- Scope scope;
- Function f;
- public CallMarker(Context cx) { pc = cx.pc + 1; scope = cx.scope; f = cx.f; }
+ JSScope scope;
+ JSFunction f;
+ public CallMarker(JSContext cx) { pc = cx.pc + 1; scope = cx.scope; f = cx.f; }
}
public static class CatchMarker { public CatchMarker() { } }
@@ -526,8 +575,8 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
public static class LoopMarker {
public int location;
public String label;
- public JS.Scope scope;
- public LoopMarker(int location, String label, JS.Scope scope) {
+ public JSScope scope;
+ public LoopMarker(int location, String label, JSScope scope) {
this.location = location;
this.label = label;
this.scope = scope;
@@ -536,8 +585,8 @@ public class Function extends JS.Obj implements ByteCodes, Tokens {
public static class TryMarker {
public int catchLoc;
public int finallyLoc;
- public JS.Scope scope;
- public TryMarker(int catchLoc, int finallyLoc, JS.Scope scope) {
+ public JSScope scope;
+ public TryMarker(int catchLoc, int finallyLoc, JSScope scope) {
this.catchLoc = catchLoc;
this.finallyLoc = finallyLoc;
this.scope = scope;