nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
changeset 28437 b9b1042592e6
parent 26649 1d7a917a35e2
child 30394 72a59e4dffea
equal deleted inserted replaced
28344:722378bc599e 28437:b9b1042592e6
    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 }