Tue, 01 Sep 2015 18:28:11 +0530
8068901: Surprising behavior with more than one functional interface on a class
8068903: Can't invoke vararg @FunctionalInterface methods
Reviewed-by: attila, hannesw
1.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Aug 31 17:51:02 2015 +0530 1.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Sep 01 18:28:11 2015 +0530 1.3 @@ -190,7 +190,7 @@ 1.4 * @return true if the obj is an instance of @FunctionalInterface interface 1.5 */ 1.6 public static boolean isFunctionalInterfaceObject(final Object obj) { 1.7 - return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null); 1.8 + return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethodName(obj.getClass()) != null); 1.9 } 1.10 1.11 /**
2.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Mon Aug 31 17:51:02 2015 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Tue Sep 01 18:28:11 2015 +0530 2.3 @@ -79,10 +79,10 @@ 2.4 } 2.5 2.6 // cache of @FunctionalInterface method of implementor classes 2.7 - private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() { 2.8 + private static final ClassValue<String> FUNCTIONAL_IFACE_METHOD_NAME = new ClassValue<String>() { 2.9 @Override 2.10 - protected Method computeValue(final Class<?> type) { 2.11 - return findFunctionalInterfaceMethod(type); 2.12 + protected String computeValue(final Class<?> type) { 2.13 + return findFunctionalInterfaceMethodName(type); 2.14 } 2.15 }; 2.16 2.17 @@ -107,19 +107,21 @@ 2.18 // annotated interface. This way Java method, constructor references or 2.19 // implementations of java.util.function.* interfaces can be called as though 2.20 // those are script functions. 2.21 - final Method m = getFunctionalInterfaceMethod(self.getClass()); 2.22 - if (m != null) { 2.23 + final String name = getFunctionalInterfaceMethodName(self.getClass()); 2.24 + if (name != null) { 2.25 final MethodType callType = desc.getMethodType(); 2.26 - // 'callee' and 'thiz' passed from script + actual arguments 2.27 - if (callType.parameterCount() != m.getParameterCount() + 2) { 2.28 - throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); 2.29 - } 2.30 - return new GuardedInvocation( 2.31 - // drop 'thiz' passed from the script. 2.32 - MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1, 2.33 - callType.parameterType(1)), Guards.getInstanceOfGuard( 2.34 - m.getDeclaringClass())).asTypeSafeReturn( 2.35 - new NashornBeansLinkerServices(linkerServices), callType); 2.36 + // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name> 2.37 + final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(), 2.38 + "dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2), 2.39 + NashornCallSiteDescriptor.getFlags(desc)); 2.40 + final GuardedInvocation gi = getGuardedInvocation(beansLinker, 2.41 + linkRequest.replaceArguments(newDesc, linkRequest.getArguments()), 2.42 + new NashornBeansLinkerServices(linkerServices)); 2.43 + 2.44 + // drop 'thiz' passed from the script. 2.45 + return gi.replaceMethods( 2.46 + MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)), 2.47 + gi.getGuard()); 2.48 } 2.49 } 2.50 return getGuardedInvocation(beansLinker, linkRequest, linkerServices); 2.51 @@ -163,7 +165,7 @@ 2.52 return arg instanceof ConsString ? arg.toString() : arg; 2.53 } 2.54 2.55 - private static Method findFunctionalInterfaceMethod(final Class<?> clazz) { 2.56 + private static String findFunctionalInterfaceMethodName(final Class<?> clazz) { 2.57 if (clazz == null) { 2.58 return null; 2.59 } 2.60 @@ -179,20 +181,20 @@ 2.61 // return the first abstract method 2.62 for (final Method m : iface.getMethods()) { 2.63 if (Modifier.isAbstract(m.getModifiers())) { 2.64 - return m; 2.65 + return m.getName(); 2.66 } 2.67 } 2.68 } 2.69 } 2.70 2.71 // did not find here, try super class 2.72 - return findFunctionalInterfaceMethod(clazz.getSuperclass()); 2.73 + return findFunctionalInterfaceMethodName(clazz.getSuperclass()); 2.74 } 2.75 2.76 // Returns @FunctionalInterface annotated interface's single abstract 2.77 - // method. If not found, returns null. 2.78 - static Method getFunctionalInterfaceMethod(final Class<?> clazz) { 2.79 - return FUNCTIONAL_IFACE_METHOD.get(clazz); 2.80 + // method name. If not found, returns null. 2.81 + static String getFunctionalInterfaceMethodName(final Class<?> clazz) { 2.82 + return FUNCTIONAL_IFACE_METHOD_NAME.get(clazz); 2.83 } 2.84 2.85 static MethodHandleTransformer createHiddenObjectFilter() {
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/script/basic/JDK-8068901.js Tue Sep 01 18:28:11 2015 +0530 3.3 @@ -0,0 +1,49 @@ 3.4 +/* 3.5 + * Copyright (c) 2015, 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-8068901: Surprising behavior with more than one functional interface on a class 3.29 + * 3.30 + * @test 3.31 + * @run 3.32 + */ 3.33 + 3.34 +var Consumer = java.util.function.Consumer; 3.35 +var JFunction = java.util.function.Function; 3.36 + 3.37 +var fc = new (Java.extend(JFunction, Consumer))({ 3.38 + apply: function(x) { print("fc invoked as a function") }, 3.39 + accept: function(x) { print("fc invoked as a consumer") } 3.40 +}); 3.41 + 3.42 +var c = new Consumer(function(x) { print("c invoked as a consumer") }); 3.43 + 3.44 +var cf = new (Java.extend(Consumer, JFunction))({ 3.45 + apply: function(x) { print("cf invoked as a function") }, 3.46 + accept: function(x) { print("cf invoked as a consumer") } 3.47 +}); 3.48 + 3.49 +var f = new JFunction(function(x) { print("f invoked as a function") }); 3.50 + 3.51 +for each(x in [fc, c, fc, cf, f, cf, c, fc, f, cf]) { x(null); } 3.52 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/script/basic/JDK-8068901.js.EXPECTED Tue Sep 01 18:28:11 2015 +0530 4.3 @@ -0,0 +1,10 @@ 4.4 +fc invoked as a function 4.5 +c invoked as a consumer 4.6 +fc invoked as a function 4.7 +cf invoked as a consumer 4.8 +f invoked as a function 4.9 +cf invoked as a consumer 4.10 +c invoked as a consumer 4.11 +fc invoked as a function 4.12 +f invoked as a function 4.13 +cf invoked as a consumer
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/script/basic/JDK-8068903.js Tue Sep 01 18:28:11 2015 +0530 5.3 @@ -0,0 +1,40 @@ 5.4 +/* 5.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/** 5.28 + * JDK-8068903: Can't invoke vararg @FunctionalInterface methods 5.29 + * 5.30 + * @test 5.31 + * @run 5.32 + */ 5.33 + 5.34 +var vc = new (Java.type("jdk.nashorn.test.models.VarArgConsumer"))( 5.35 + function(x) { 5.36 + Assert.assertTrue(x.length == 3); 5.37 + Assert.assertTrue(x[0] == 1); 5.38 + Assert.assertTrue(x[1] == 2); 5.39 + Assert.assertTrue(x[2] == 3); 5.40 + } 5.41 +); 5.42 + 5.43 +vc(1, 2, 3);
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/src/jdk/nashorn/test/models/VarArgConsumer.java Tue Sep 01 18:28:11 2015 +0530 6.3 @@ -0,0 +1,35 @@ 6.4 +/* 6.5 + * Copyright (c) 2015, 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.test.models; 6.30 + 6.31 +/** 6.32 + * Simple function interface with a varargs SAM method. 6.33 + */ 6.34 +@FunctionalInterface 6.35 +public interface VarArgConsumer { 6.36 + public void apply(Object... o); 6.37 +} 6.38 +