Thu, 09 Jan 2014 19:23:34 +0530
8031359: Invocable.getInterface() works incorrectly if interface has default methods
Reviewed-by: attila, hannesw
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Jan 08 17:51:47 2014 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Jan 09 19:23:34 2014 +0530 1.3 @@ -628,6 +628,11 @@ 1.4 continue; 1.5 } 1.6 1.7 + // skip check for default methods - non-abstract, interface methods 1.8 + if (! Modifier.isAbstract(method.getModifiers())) { 1.9 + continue; 1.10 + } 1.11 + 1.12 Object obj = sobj.get(method.getName()); 1.13 if (! (obj instanceof ScriptFunction)) { 1.14 return false;
2.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed Jan 08 17:51:47 2014 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu Jan 09 19:23:34 2014 +0530 2.3 @@ -645,7 +645,7 @@ 2.4 mv.athrow(); 2.5 } else { 2.6 // If the super method is not abstract, delegate to it. 2.7 - emitSuperCall(mv, name, methodDesc); 2.8 + emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 2.9 } 2.10 2.11 mv.visitLabel(handleDefined); 2.12 @@ -817,12 +817,12 @@ 2.13 SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); 2.14 mv.visitCode(); 2.15 2.16 - emitSuperCall(mv, name, methodDesc); 2.17 + emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 2.18 2.19 endMethod(mv); 2.20 } 2.21 2.22 - private void emitSuperCall(final InstructionAdapter mv, final String name, final String methodDesc) { 2.23 + private void emitSuperCall(final InstructionAdapter mv, final Class owner, final String name, final String methodDesc) { 2.24 mv.visitVarInsn(ALOAD, 0); 2.25 int nextParam = 1; 2.26 final Type methodType = Type.getMethodType(methodDesc); 2.27 @@ -830,7 +830,13 @@ 2.28 mv.load(nextParam, t); 2.29 nextParam += t.getSize(); 2.30 } 2.31 - mv.invokespecial(superClassName, name, methodDesc, false); 2.32 + 2.33 + // default method - non-abstract, interface method 2.34 + if (Modifier.isInterface(owner.getModifiers())) { 2.35 + mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false); 2.36 + } else { 2.37 + mv.invokespecial(superClassName, name, methodDesc, false); 2.38 + } 2.39 mv.areturn(methodType.getReturnType()); 2.40 } 2.41
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/script/basic/JDK-8031359.js Thu Jan 09 19:23:34 2014 +0530 3.3 @@ -0,0 +1,62 @@ 3.4 +/* 3.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + */ 3.26 + 3.27 +/** 3.28 + * JDK-8031359: Invocable.getInterface() works incorrectly if interface has default methods 3.29 + * 3.30 + * @test 3.31 + * @run 3.32 + */ 3.33 + 3.34 +var func = new java.util.function.Function() { 3.35 + apply: function(arg) { 3.36 + print("func called with " + arg); 3.37 + return arg.toUpperCase(); 3.38 + } 3.39 +}; 3.40 + 3.41 +// Function.andThen is a default method 3.42 +func.andThen(func)("hello"); 3.43 + 3.44 +// Function.compose is another default method 3.45 +func.compose(new java.util.function.Function() { 3.46 + apply: function(arg) { 3.47 + print("compose called with " + arg); 3.48 + return arg.charAt(0); 3.49 + } 3.50 +})("hello"); 3.51 + 3.52 +var func2 = new java.util.function.Function() { 3.53 + apply: function(arg) { 3.54 + print("I am func2: " + arg); 3.55 + return arg; 3.56 + }, 3.57 + 3.58 + andThen: function(func) { 3.59 + print("This is my andThen!"); 3.60 + return func; 3.61 + } 3.62 +}; 3.63 + 3.64 +func2.apply("hello"); 3.65 +func2.andThen(func);
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/script/basic/JDK-8031359.js.EXPECTED Thu Jan 09 19:23:34 2014 +0530 4.3 @@ -0,0 +1,6 @@ 4.4 +func called with hello 4.5 +func called with HELLO 4.6 +compose called with hello 4.7 +func called with h 4.8 +I am func2: hello 4.9 +This is my andThen!
5.1 --- a/test/src/jdk/nashorn/api/scripting/InvocableTest.java Wed Jan 08 17:51:47 2014 +0530 5.2 +++ b/test/src/jdk/nashorn/api/scripting/InvocableTest.java Thu Jan 09 19:23:34 2014 +0530 5.3 @@ -26,6 +26,7 @@ 5.4 package jdk.nashorn.api.scripting; 5.5 5.6 import java.util.Objects; 5.7 +import java.util.function.Function; 5.8 import javax.script.Invocable; 5.9 import javax.script.ScriptContext; 5.10 import javax.script.ScriptEngine; 5.11 @@ -522,4 +523,16 @@ 5.12 Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); 5.13 Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); 5.14 } 5.15 + 5.16 + @Test 5.17 + @SuppressWarnings("unchecked") 5.18 + public void defaultMethodTest() throws ScriptException { 5.19 + final ScriptEngineManager m = new ScriptEngineManager(); 5.20 + final ScriptEngine e = m.getEngineByName("nashorn"); 5.21 + final Invocable inv = (Invocable) e; 5.22 + 5.23 + Object obj = e.eval("({ apply: function(arg) { return arg.toUpperCase(); }})"); 5.24 + Function<String, String> func = inv.getInterface(obj, Function.class); 5.25 + assertEquals(func.apply("hello"), "HELLO"); 5.26 + } 5.27 }