final Object target = o;
final String method = key.toString();
return new JSCallable() {
- public Object call(JSArray args) { return callMethodOnPrimitive(target,method,args); }
+ public Object call(Object notUsed, JSArray args) { return callMethodOnPrimitive(target,method,args); }
};
}
return null;
return call(method, args);
}
public Object call(Object method, JSArray args) throws JS.Exn {
- throw new JS.Exn("cannot invoke this method with " + args.size() + " arguments");
+ if (method != null) {
+ Object meth = get(method);
+ if (meth == null) throw new JS.Exn("attempt to invoke the null method");
+ if (!(meth instanceof JSCallable)) throw new JS.Exn("cannot call a " + meth.getClass().getName());
+ switch (args.size()) {
+ case 0: return ((JSCallable)meth).call0(null);
+ case 1: return ((JSCallable)meth).call1(null, args.elementAt(0));
+ case 2: return ((JSCallable)meth).call2(null, args.elementAt(0), args.elementAt(1));
+ default: return ((JSCallable)meth).call(null, args);
+ }
+ }
+ throw new JS.Exn("cannot invoke method " + method + " on object " + this.getClass().getName() + " with " + args.size() + " arguments");
}
}
pausecount++;
return new Callback() { public Object call(Object o) {
stack.push(o);
+ pc++;
resume();
return null;
} };
case JMP: cx.pc += JS.toNumber(arg).intValue() - 1; break;
case POP: cx.stack.pop(); break;
case SWAP: {
- int depth = (1 + (arg == null ? 1 : toInt(arg)));
+ int depth = (arg == null ? 1 : toInt(arg));
Object save = cx.stack.elementAt(cx.stack.size() - 1);
- for(int i=cx.stack.size() - 1; i > cx.stack.size() - depth; i--)
+ for(int i=cx.stack.size() - 1; i > cx.stack.size() - 1 - depth; i--)
cx.stack.setElementAt(cx.stack.elementAt(i-1), i);
- cx.stack.setElementAt(save, cx.stack.size() - depth);
+ cx.stack.setElementAt(save, cx.stack.size() - depth - 1);
break; }
case DUP: cx.stack.push(cx.stack.peek()); break;
case NEWSCOPE: cx.scope = new JSScope(cx.scope); break;
}
Object ret = null;
if (v == null) throw je("tried to get the null key from " + o);
- if (o == null) throw je("tried to get property \"" + v + "\" from the null value");
+ if (o == null) throw je("tried to get property \"" + v + "\" from the null value @" + cx.pc + "\n" + cx.f.dump());
if (o instanceof String || o instanceof Number || o instanceof Boolean) {
ret = Internal.getFromPrimitive(o,v);
cx.stack.push(ret);
case CALL: case CALLMETHOD: {
int numArgs = JS.toInt(arg);
- JSArray arguments = null;
- Object arg0 = null;
- Object arg1 = null;
- Object o = cx.stack.pop();
- if(o == null) throw je("attempted to call null");
- Object ret;
Object method = null;
+ Object object = null;
+ Object ret = null;
+ JSArray arguments = null;
+
if(op == CALLMETHOD) {
- 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) {
- 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
- break;
- } else if (o instanceof JSCallable) {
- cx.pc += 2; // skip the GET and CALL
- // fall through
- } else {
- // put the args back on the stack and let the GET followed by CALL happen
- cx.stack.push(o);
- cx.stack.push(method);
- break;
+ Object getResult = cx.stack.pop();
+ method = cx.stack.pop();
+ object = cx.stack.pop();
+ if (getResult != null) {
+ method = null;
+ object = getResult;
}
+ } else {
+ method = null;
+ object = cx.stack.pop();
+ }
+
+ if (object instanceof String || object instanceof Number || object instanceof Boolean) {
+ arguments = new JSArray(); for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ ret = Internal.callMethodOnPrimitive(object, method, arguments);
- } else if (o instanceof JSFunction) {
+ } else if (object instanceof JSFunction) {
// FEATURE: use something similar to call0/call1/call2 here
- arguments = new JSArray();
- for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ arguments = new JSArray(); for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
cx.stack.push(new CallMarker(cx));
cx.stack.push(arguments);
- cx.f = (JSFunction)o;
+ cx.f = (JSFunction)object;
cx.scope = new JSScope(cx.f.parentJSScope);
cx.pc = -1;
break;
- }
- if (!(o instanceof JSCallable)) throw new JS.Exn("can't call " + o + " @ " + cx.pc + "\n" + cx.f.dump());
- 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: { Object first = cx.stack.pop(); ret = c.call2(method, cx.stack.pop(), first); break; }
- default: {
- 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 null; // we were paused
- break;
+ } else if (object instanceof JSCallable) {
+ JSCallable c = (JSCallable)object;
+ switch(numArgs) {
+ case 0: ret = c.call0(method); break;
+ case 1: ret = c.call1(method, cx.stack.pop()); break;
+ case 2: {
+ Object first = cx.stack.pop();
+ Object second = cx.stack.pop();
+ ret = c.call2(method, second, first);
+ break;
+ }
+ default: {
+ arguments = new JSArray();
+ for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(cx.stack.pop(), j);
+ ret = c.call(method, arguments);
+ break;
+ }
}
+ } else {
+ throw new JS.Exn("can't call a " + object.getClass().getName() + " @" + cx.pc + "\n" + cx.f.dump());
}
+ if (cx.pausecount > initialPauseCount) return null;
cx.stack.push(ret);
-
break;
}
import java.util.*;
/** The JavaScript Math object */
-public class JSMath extends JSObj {
+public class JSMath extends JSCallable {
public static JSMath singleton = new JSMath();
public Object call(Object method, JSArray args) {
if (method.equals("stringFromCharCode")) return stringFromCharCode(args);
- else throw new JS.Exn("method not found");
+ return super.call(method, args);
}
public Object call1(Object method, Object arg0) {
case "escape": throw new JS.Exn("unimplemented");
case "unescape": throw new JS.Exn("unimplemented");
//#end
- return null;
+ return super.call1(method, arg0);
}
public Object call2(Object method, Object arg1, Object arg2) {
if (method.equals("parseInt")) return parseInt(arg1, arg2);
- return null;
+ return super.call2(method, arg1, arg2);
}
private Object stringFromCharCode(JSArray args) {
throw pe("prefixed increment/decrement can only be performed on a valid assignment target");
b.add(parserLine, GET_PRESERVE, Boolean.TRUE);
b.add(parserLine, LITERAL, new Integer(1));
- b.add(parserLine, tok == INC ? ADD : SUB, null);
+ b.add(parserLine, tok == INC ? ADD : SUB, new Integer(2));
b.add(parserLine, PUT, null);
b.add(parserLine, SWAP, null);
b.add(parserLine, POP, null);
case INC: case DEC: { // postfix
b.add(parserLine, GET_PRESERVE, Boolean.TRUE);
b.add(parserLine, LITERAL, new Integer(1));
- b.add(parserLine, tok == INC ? ADD : SUB, null);
+ b.add(parserLine, tok == INC ? ADD : SUB, new Integer(2));
b.add(parserLine, PUT, null);
b.add(parserLine, SWAP, null);
b.add(parserLine, POP, null);
break;
}
case LP: {
- int n = parseArgs(b);
-
- // if the object supports CALLMETHOD, we use this, and jump over the following two instructions
- b.add(parserLine,CALLMETHOD,new Integer(n));
- b.add(parserLine,GET);
- b.add(parserLine,CALL,new Integer(n));
+ int n = parseArgs(b, 2);
+ b.add(parserLine, GET_PRESERVE);
+ b.add(parserLine, CALLMETHOD, new Integer(n));
break;
}
default: {
switch (tok) {
case LP: { // invocation (not grouping)
- int n = parseArgs(b);
+ int n = parseArgs(b, 1);
b.add(parserLine, CALL, new Integer(n));
break;
}
// parse a set of comma separated function arguments, assume LP has already been consumed
// if swap is true, (because the function is already on the stack) we will SWAP after each argument to keep it on top
- private int parseArgs(JSFunction b) throws IOException {
+ private int parseArgs(JSFunction b, int pushdown) throws IOException {
int i = 0;
while(peekToken() != RP) {
i++;
if (peekToken() != COMMA) {
startExpr(b, NO_COMMA);
- b.add(parserLine, SWAP, new Integer(2));
+ b.add(parserLine, SWAP, new Integer(pushdown));
if (peekToken() == RP) break;
}
consume(COMMA);
}
// FIXME: try to use os acceleration
- public void fillJSTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) {
+ public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) {
g.setColor(new Color((argb & 0x00FF0000) >> 16, (argb & 0x0000FF00) >> 8, (argb & 0x000000FF)));
if (x1 == x3 && x2 == x4) {
g.fillRect(x1, y1, x4 - x1, y2 - y1);
else return null;
} catch (Throwable e) {
- if (Log.on) Log.log(this, "exception while querying sun.plugin.protocol.PluginProxyHandler: " + e);
+ if (Log.on) Log.log(this, "No proxy information found in Java Plugin classes");
return null;
}
}});
public native void setClip(int x, int y, int x2, int y2);
public native void resetClip();
- public native void fillJSTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
+ public native void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
public void drawString(String font, String text, int x, int y, int color) {
//System.out.println("drawString(): " + text);
public native void finalize();
// FIXME: try to use os acceleration
- public void fillJSTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) {
+ public void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int argb) {
if (x1 == x3 && x2 == x4) {
fillRect(x1, y1, x4, y2, argb);
} else for(int y=y1; y<y2; y++) {