diff --git a/js/rhino/src/org/mozilla/javascript/FunctionObject.java b/js/rhino/src/org/mozilla/javascript/FunctionObject.java index b5737212826f..b7a4aea7cd21 100644 --- a/js/rhino/src/org/mozilla/javascript/FunctionObject.java +++ b/js/rhino/src/org/mozilla/javascript/FunctionObject.java @@ -46,8 +46,6 @@ import java.io.*; public class FunctionObject extends BaseFunction { - static final long serialVersionUID = -4074285335521944312L; - /** * Create a JavaScript function object from a Java method. * @@ -386,70 +384,96 @@ public class FunctionObject extends BaseFunction public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { + Object result; + boolean checkMethodResult = false; + if (parmsLength < 0) { - return callVarargs(cx, thisObj, args); - } - if (!isStatic) { - Class clazz = member.getDeclaringClass(); - if (!clazz.isInstance(thisObj)) { - boolean compatible = false; - if (thisObj == scope) { - Scriptable parentScope = getParentScope(); - if (scope != parentScope) { - // Call with dynamic scope for standalone function, - // use parentScope as thisObj - compatible = clazz.isInstance(parentScope); - if (compatible) { - thisObj = parentScope; + if (parmsLength == VARARGS_METHOD) { + Object[] invokeArgs = { cx, thisObj, args, this }; + result = member.invoke(null, invokeArgs); + checkMethodResult = true; + } else { + boolean inNewExpr = (thisObj == null); + Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE; + Object[] invokeArgs = { cx, args, this, b }; + result = (member.isCtor()) + ? member.newInstance(invokeArgs) + : member.invoke(null, invokeArgs); + } + + } else { + if (!isStatic) { + Class clazz = member.getDeclaringClass(); + if (!clazz.isInstance(thisObj)) { + boolean compatible = false; + if (thisObj == scope) { + Scriptable parentScope = getParentScope(); + if (scope != parentScope) { + // Call with dynamic scope for standalone function, + // use parentScope as thisObj + compatible = clazz.isInstance(parentScope); + if (compatible) { + thisObj = parentScope; + } } } - } - if (!compatible) { - // Couldn't find an object to call this on. - throw ScriptRuntime.typeError1("msg.incompat.call", - functionName); - } - } - } - - Object[] invokeArgs; - if (parmsLength == args.length) { - // Do not allocate new argument array if java arguments are - // the same as the original js ones. - invokeArgs = args; - for (int i = 0; i != parmsLength; ++i) { - Object arg = args[i]; - Object converted = convertArg(cx, scope, arg, typeTags[i]); - if (arg != converted) { - if (invokeArgs == args) { - invokeArgs = (Object[])args.clone(); + if (!compatible) { + // Couldn't find an object to call this on. + throw ScriptRuntime.typeError1("msg.incompat.call", + functionName); } - invokeArgs[i] = converted; } } - } else if (parmsLength == 0) { - invokeArgs = ScriptRuntime.emptyArgs; - } else { - invokeArgs = new Object[parmsLength]; - for (int i = 0; i != parmsLength; ++i) { - Object arg = (i < args.length) - ? args[i] - : Undefined.instance; - invokeArgs[i] = convertArg(cx, scope, arg, typeTags[i]); + + Object[] invokeArgs; + if (parmsLength == args.length) { + // Do not allocate new argument array if java arguments are + // the same as the original js ones. + invokeArgs = args; + for (int i = 0; i != parmsLength; ++i) { + Object arg = args[i]; + Object converted = convertArg(cx, scope, arg, typeTags[i]); + if (arg != converted) { + if (invokeArgs == args) { + invokeArgs = (Object[])args.clone(); + } + invokeArgs[i] = converted; + } + } + } else if (parmsLength == 0) { + invokeArgs = ScriptRuntime.emptyArgs; + } else { + invokeArgs = new Object[parmsLength]; + for (int i = 0; i != parmsLength; ++i) { + Object arg = (i < args.length) + ? args[i] + : Undefined.instance; + invokeArgs[i] = convertArg(cx, scope, arg, typeTags[i]); + } } + + if (member.isMethod()) { + result = member.invoke(thisObj, invokeArgs); + checkMethodResult = true; + } else { + result = member.newInstance(invokeArgs); + } + } - Object result; - if (member.isMethod()) { - result = member.invoke(thisObj, invokeArgs); - if (returnTypeTag == JAVA_UNSUPPORTED_TYPE) { + if (checkMethodResult) { + if (hasVoidReturn) { + result = Undefined.instance; + } else if (returnTypeTag == JAVA_UNSUPPORTED_TYPE) { result = cx.getWrapFactory().wrap(cx, scope, result, null); } - } else { - result = member.newInstance(invokeArgs); + // XXX: the code assumes that if returnTypeTag == JAVA_OBJECT_TYPE + // then the Java method did a proper job of converting the + // result to JS primitive or Scriptable to avoid + // potentially costly Context.javaToJS call. } - return hasVoidReturn ? Undefined.instance : result; + return result; } /** @@ -474,22 +498,6 @@ public class FunctionObject extends BaseFunction return result; } - private Object callVarargs(Context cx, Scriptable thisObj, Object[] args) - { - if (parmsLength == VARARGS_METHOD) { - Object[] invokeArgs = { cx, thisObj, args, this }; - Object result = member.invoke(null, invokeArgs); - return hasVoidReturn ? Undefined.instance : result; - } else { - boolean inNewExpr = (thisObj == null); - Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE; - Object[] invokeArgs = { cx, args, this, b }; - return (member.isCtor()) - ? member.newInstance(invokeArgs) - : member.invoke(null, invokeArgs); - } - } - boolean isVarArgsMethod() { return parmsLength == VARARGS_METHOD; }