28 import static jdk.nashorn.internal.lookup.Lookup.MH; |
28 import static jdk.nashorn.internal.lookup.Lookup.MH; |
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; |
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; |
30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; |
30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; |
31 |
31 |
32 import java.lang.invoke.MethodHandle; |
32 import java.lang.invoke.MethodHandle; |
33 import java.lang.invoke.MethodType; |
|
34 import java.lang.reflect.Method; |
|
35 import java.lang.reflect.Modifier; |
|
36 import java.util.HashMap; |
33 import java.util.HashMap; |
37 import java.util.Map; |
34 import java.util.Map; |
38 import jdk.internal.dynalink.CallSiteDescriptor; |
35 import jdk.internal.dynalink.CallSiteDescriptor; |
39 import jdk.internal.dynalink.beans.BeansLinker; |
36 import jdk.internal.dynalink.beans.BeansLinker; |
40 import jdk.internal.dynalink.linker.GuardedInvocation; |
37 import jdk.internal.dynalink.linker.GuardedInvocation; |
43 import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; |
40 import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; |
44 import jdk.internal.dynalink.linker.LinkRequest; |
41 import jdk.internal.dynalink.linker.LinkRequest; |
45 import jdk.internal.dynalink.linker.LinkerServices; |
42 import jdk.internal.dynalink.linker.LinkerServices; |
46 import jdk.internal.dynalink.support.Guards; |
43 import jdk.internal.dynalink.support.Guards; |
47 import jdk.nashorn.internal.codegen.types.Type; |
44 import jdk.nashorn.internal.codegen.types.Type; |
48 import jdk.nashorn.internal.runtime.Context; |
|
49 import jdk.nashorn.internal.runtime.JSType; |
45 import jdk.nashorn.internal.runtime.JSType; |
50 import jdk.nashorn.internal.runtime.ScriptRuntime; |
46 import jdk.nashorn.internal.runtime.ScriptRuntime; |
51 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException; |
47 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException; |
52 |
48 |
53 /** |
49 /** |
93 if(BeansLinker.isDynamicMethod(self)) { |
89 if(BeansLinker.isDynamicMethod(self)) { |
94 throw typeError("method.not.constructor", ScriptRuntime.safeToString(self)); |
90 throw typeError("method.not.constructor", ScriptRuntime.safeToString(self)); |
95 } |
91 } |
96 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); |
92 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); |
97 case "call": |
93 case "call": |
98 // Support dyn:call on any object that supports some @FunctionalInterface |
|
99 // annotated interface. This way Java method, constructor references or |
|
100 // implementations of java.util.function.* interfaces can be called as though |
|
101 // those are script functions. |
|
102 final Method m = getFunctionalInterfaceMethod(self.getClass()); |
|
103 if (m != null) { |
|
104 final MethodType callType = desc.getMethodType(); |
|
105 // 'callee' and 'thiz' passed from script + actual arguments |
|
106 if (callType.parameterCount() != m.getParameterCount() + 2) { |
|
107 throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); |
|
108 } |
|
109 return Bootstrap.asTypeSafeReturn(new GuardedInvocation( |
|
110 // drop 'thiz' passed from the script. |
|
111 MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)), |
|
112 Guards.getInstanceOfGuard(m.getDeclaringClass())), linkerServices, desc); |
|
113 } |
|
114 if(BeansLinker.isDynamicConstructor(self)) { |
94 if(BeansLinker.isDynamicConstructor(self)) { |
115 throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self)); |
95 throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self)); |
116 } |
96 } |
117 if(BeansLinker.isDynamicMethod(self)) { |
97 if(BeansLinker.isDynamicMethod(self)) { |
118 throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); |
98 throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); |
216 if (desc.getNameTokenCount() > 2) { |
196 if (desc.getNameTokenCount() > 2) { |
217 return desc.getNameToken(2); |
197 return desc.getNameToken(2); |
218 } |
198 } |
219 return ScriptRuntime.safeToString(linkRequest.getArguments()[1]); |
199 return ScriptRuntime.safeToString(linkRequest.getArguments()[1]); |
220 } |
200 } |
221 |
|
222 // cache of @FunctionalInterface method of implementor classes |
|
223 private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() { |
|
224 @Override |
|
225 protected Method computeValue(final Class<?> type) { |
|
226 return findFunctionalInterfaceMethod(type); |
|
227 } |
|
228 |
|
229 private Method findFunctionalInterfaceMethod(final Class<?> clazz) { |
|
230 if (clazz == null) { |
|
231 return null; |
|
232 } |
|
233 |
|
234 for (final Class<?> iface : clazz.getInterfaces()) { |
|
235 // check accessiblity up-front |
|
236 if (! Context.isAccessibleClass(iface)) { |
|
237 continue; |
|
238 } |
|
239 |
|
240 // check for @FunctionalInterface |
|
241 if (iface.isAnnotationPresent(FunctionalInterface.class)) { |
|
242 // return the first abstract method |
|
243 for (final Method m : iface.getMethods()) { |
|
244 if (Modifier.isAbstract(m.getModifiers())) { |
|
245 return m; |
|
246 } |
|
247 } |
|
248 } |
|
249 } |
|
250 |
|
251 // did not find here, try super class |
|
252 return findFunctionalInterfaceMethod(clazz.getSuperclass()); |
|
253 } |
|
254 }; |
|
255 |
|
256 // Returns @FunctionalInterface annotated interface's single abstract |
|
257 // method. If not found, returns null. |
|
258 static Method getFunctionalInterfaceMethod(final Class<?> clazz) { |
|
259 return FUNCTIONAL_IFACE_METHOD.get(clazz); |
|
260 } |
|
261 } |
201 } |