Tue, 23 Apr 2013 12:52:29 +0200
8011065: Problems when script implements an interface with variadic methods
Reviewed-by: jlaskey, hannesw, sundar
1.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Apr 22 19:57:57 2013 +0530 1.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Apr 23 12:52:29 2013 +0200 1.3 @@ -664,7 +664,7 @@ 1.4 final int useCount = symbol.getUseCount(); 1.5 1.6 // Threshold for generating shared scope callsite is lower for fast scope symbols because we know 1.7 - // we can dial in the correct scope. However, we als need to enable it for non-fast scopes to 1.8 + // we can dial in the correct scope. However, we also need to enable it for non-fast scopes to 1.9 // support huge scripts like mandreel.js. 1.10 if (callNode.isEval()) { 1.11 evalCall(node, flags);
2.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Mon Apr 22 19:57:57 2013 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Apr 23 12:52:29 2013 +0200 2.3 @@ -28,6 +28,7 @@ 2.4 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 2.5 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall; 2.6 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; 2.7 +import static jdk.nashorn.internal.lookup.Lookup.MH; 2.8 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; 2.9 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 2.10 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE; 2.11 @@ -39,7 +40,6 @@ 2.12 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 2.13 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow; 2.14 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 2.15 -import static jdk.nashorn.internal.lookup.Lookup.MH; 2.16 2.17 import java.lang.invoke.MethodHandle; 2.18 import java.lang.invoke.MethodHandles; 2.19 @@ -61,12 +61,13 @@ 2.20 import jdk.internal.dynalink.support.CallSiteDescriptorFactory; 2.21 import jdk.nashorn.internal.codegen.CompilerConstants.Call; 2.22 import jdk.nashorn.internal.codegen.ObjectClassGenerator; 2.23 +import jdk.nashorn.internal.lookup.Lookup; 2.24 +import jdk.nashorn.internal.lookup.MethodHandleFactory; 2.25 import jdk.nashorn.internal.objects.AccessorPropertyDescriptor; 2.26 import jdk.nashorn.internal.objects.DataPropertyDescriptor; 2.27 import jdk.nashorn.internal.runtime.arrays.ArrayData; 2.28 import jdk.nashorn.internal.runtime.linker.Bootstrap; 2.29 -import jdk.nashorn.internal.lookup.Lookup; 2.30 -import jdk.nashorn.internal.lookup.MethodHandleFactory; 2.31 +import jdk.nashorn.internal.runtime.linker.LinkerCallSite; 2.32 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 2.33 import jdk.nashorn.internal.runtime.linker.NashornGuards; 2.34 2.35 @@ -2139,8 +2140,11 @@ 2.36 * 2.37 * Make sure arguments are paired correctly. 2.38 * @param methodHandle MethodHandle to adjust. 2.39 - * @param callType MethodType of caller. 2.40 - * @param callerVarArg true if the caller is vararg, false otherwise, null if it should be inferred. 2.41 + * @param callType MethodType of the call site. 2.42 + * @param callerVarArg true if the caller is vararg, false otherwise, null if it should be inferred from the 2.43 + * {@code callType}; basically, if the last parameter type of the call site is an array, it'll be considered a 2.44 + * variable arity call site. These are ordinarily rare; Nashorn code generator creates variable arity call sites 2.45 + * when the call has more than {@link LinkerCallSite#ARGLIMIT} parameters. 2.46 * 2.47 * @return method handle with adjusted arguments 2.48 */ 2.49 @@ -2155,7 +2159,7 @@ 2.50 final int callCount = callType.parameterCount(); 2.51 2.52 final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); 2.53 - final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 1 && 2.54 + final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 0 && 2.55 callType.parameterType(callCount - 1).isArray()); 2.56 2.57 if (callCount < parameterCount) {
3.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Mon Apr 22 19:57:57 2013 +0530 3.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Tue Apr 23 12:52:29 2013 +0200 3.3 @@ -127,9 +127,9 @@ 3.4 private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class); 3.5 private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class); 3.6 private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, 3.7 - OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE); 3.8 + OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE); 3.9 private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, 3.10 - SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE); 3.11 + SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE); 3.12 private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE); 3.13 private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class); 3.14 private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); 3.15 @@ -315,7 +315,6 @@ 3.16 mv.dup(); 3.17 mv.aconst(mi.getName()); 3.18 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 3.19 - mv.iconst(mi.method.isVarArgs() ? 1 : 0); 3.20 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR); 3.21 mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 3.22 } 3.23 @@ -459,7 +458,6 @@ 3.24 mv.aconst(mi.getName()); 3.25 } 3.26 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 3.27 - mv.iconst(mi.method.isVarArgs() ? 1 : 0); 3.28 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor); 3.29 } 3.30 mv.putfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
4.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java Mon Apr 22 19:57:57 2013 +0530 4.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java Tue Apr 23 12:52:29 2013 +0200 4.3 @@ -50,12 +50,11 @@ 4.4 * handles for their abstract method implementations. 4.5 * @param fn the script function 4.6 * @param type the method type it has to conform to 4.7 - * @param varArg if the Java method for which the function is being adapted is a variable arity method 4.8 * @return the appropriately adapted method handle for invoking the script function. 4.9 */ 4.10 - public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type, final boolean varArg) { 4.11 + public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type) { 4.12 // JS "this" will be null for SAMs 4.13 - return adaptHandle(fn.getBoundInvokeHandle(null), type, varArg); 4.14 + return adaptHandle(fn.getBoundInvokeHandle(null), type); 4.15 } 4.16 4.17 /** 4.18 @@ -66,12 +65,11 @@ 4.19 * @param obj the script obj 4.20 * @param name the name of the property that contains the function 4.21 * @param type the method type it has to conform to 4.22 - * @param varArg if the Java method for which the function is being adapted is a variable arity method 4.23 * @return the appropriately adapted method handle for invoking the script function, or null if the value of the 4.24 * property is either null or undefined, or "toString" was requested as the name, but the object doesn't directly 4.25 * define it but just inherits it through prototype. 4.26 */ 4.27 - public static MethodHandle getHandle(final Object obj, final String name, final MethodType type, final boolean varArg) { 4.28 + public static MethodHandle getHandle(final Object obj, final String name, final MethodType type) { 4.29 if (! (obj instanceof ScriptObject)) { 4.30 throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 4.31 } 4.32 @@ -84,7 +82,7 @@ 4.33 4.34 final Object fnObj = sobj.get(name); 4.35 if (fnObj instanceof ScriptFunction) { 4.36 - return adaptHandle(((ScriptFunction)fnObj).getBoundInvokeHandle(sobj), type, varArg); 4.37 + return adaptHandle(((ScriptFunction)fnObj).getBoundInvokeHandle(sobj), type); 4.38 } else if(fnObj == null || fnObj instanceof Undefined) { 4.39 return null; 4.40 } else { 4.41 @@ -108,7 +106,7 @@ 4.42 classOverrides.set(overrides); 4.43 } 4.44 4.45 - private static MethodHandle adaptHandle(final MethodHandle handle, final MethodType type, final boolean varArg) { 4.46 - return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(handle, type, varArg), type); 4.47 + private static MethodHandle adaptHandle(final MethodHandle handle, final MethodType type) { 4.48 + return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(handle, type, false), type); 4.49 } 4.50 }
5.1 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Mon Apr 22 19:57:57 2013 +0530 5.2 +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Tue Apr 23 12:52:29 2013 +0200 5.3 @@ -906,4 +906,26 @@ 5.4 fail(se.getMessage()); 5.5 } 5.6 } 5.7 + 5.8 + @Test 5.9 + /** 5.10 + * Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array. 5.11 + * Both non-vararg and vararg JavaScript methods are tested. 5.12 + * @throws ScriptException 5.13 + */ 5.14 + public void variableArityInterfaceTest() throws ScriptException { 5.15 + final ScriptEngineManager m = new ScriptEngineManager(); 5.16 + final ScriptEngine e = m.getEngineByName("nashorn"); 5.17 + e.eval( 5.18 + "function test1(i, strings) {" + 5.19 + " return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" + 5.20 + "}" + 5.21 + "function test2() {" + 5.22 + " return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])" + 5.23 + "}" 5.24 + ); 5.25 + final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class); 5.26 + Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); 5.27 + Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); 5.28 + } 5.29 }
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java Tue Apr 23 12:52:29 2013 +0200 6.3 @@ -0,0 +1,31 @@ 6.4 +/* 6.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. Oracle designates this 6.11 + * particular file as subject to the "Classpath" exception as provided 6.12 + * by Oracle in the LICENSE file that accompanied this code. 6.13 + * 6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.17 + * version 2 for more details (a copy is included in the LICENSE file that 6.18 + * accompanied this code). 6.19 + * 6.20 + * You should have received a copy of the GNU General Public License version 6.21 + * 2 along with this work; if not, write to the Free Software Foundation, 6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.23 + * 6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.25 + * or visit www.oracle.com if you need additional information or have any 6.26 + * questions. 6.27 + */ 6.28 + 6.29 +package jdk.nashorn.api.scripting; 6.30 + 6.31 +public interface VariableArityTestInterface { 6.32 + public String test1(int i, String... strings); 6.33 + public String test2(int i, String... strings); 6.34 +}