nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
changeset 16245 6a1c6c8bc113
parent 16234 86cb162cec6c
child 18841 9bbc4b8832b2
equal deleted inserted replaced
16244:12f06c992c3a 16245:6a1c6c8bc113
    89 import java.util.LinkedList;
    89 import java.util.LinkedList;
    90 import java.util.List;
    90 import java.util.List;
    91 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
    91 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
    92 import jdk.internal.dynalink.linker.LinkerServices;
    92 import jdk.internal.dynalink.linker.LinkerServices;
    93 import jdk.internal.dynalink.support.TypeUtilities;
    93 import jdk.internal.dynalink.support.TypeUtilities;
    94 
       
    95 
    94 
    96 /**
    95 /**
    97  * Represents an overloaded method.
    96  * Represents an overloaded method.
    98  *
    97  *
    99  * @author Attila Szegedi
    98  * @author Attila Szegedi
   202                 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we
   201                 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we
   203                 // can link it very simply by delegating to a SimpleDynamicMethod.
   202                 // can link it very simply by delegating to a SimpleDynamicMethod.
   204                 final MethodHandle mh = invokables.iterator().next();
   203                 final MethodHandle mh = invokables.iterator().next();
   205                 return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices);
   204                 return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices);
   206             }
   205             }
   207         }
   206             default: {
   208 
   207                 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on
   209         // We have more than one candidate. We have no choice but to link to a method that resolves overloads on every
   208                 // every invocation (alternatively, we could opportunistically link the one method that resolves for the
   210         // invocation (alternatively, we could opportunistically link the one method that resolves for the current
   209                 // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd
   211         // arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd go back all the
   210                 // go back all the way to candidate selection.
   212         // way to candidate selection.
   211                 // TODO: cache per call site type
   213         // TODO: cache per call site type
   212                 return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker();
   214         return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker();
   213             }
       
   214         }
       
   215 
   215     }
   216     }
   216 
   217 
   217     @Override
   218     @Override
   218     public boolean contains(MethodHandle mh) {
   219     public boolean contains(MethodHandle mh) {
   219         final MethodType type = mh.type();
   220         final MethodType type = mh.type();
   246             MethodHandle m) {
   247             MethodHandle m) {
   247         final MethodType methodType = m.type();
   248         final MethodType methodType = m.type();
   248         final boolean varArgs = m.isVarargsCollector();
   249         final boolean varArgs = m.isVarargsCollector();
   249         final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
   250         final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
   250         final int callSiteArgLen = callSiteType.parameterCount();
   251         final int callSiteArgLen = callSiteType.parameterCount();
       
   252 
       
   253         // Arity checks
   251         if(varArgs) {
   254         if(varArgs) {
   252             if(callSiteArgLen < fixedArgLen) {
   255             if(callSiteArgLen < fixedArgLen) {
   253                 return false;
   256                 return false;
   254             }
   257             }
   255         } else if(callSiteArgLen != fixedArgLen) {
   258         } else if(callSiteArgLen != fixedArgLen) {
   256             return false;
   259             return false;
   257         }
   260         }
   258         // Starting from 1, as receiver type doesn't participate
   261 
       
   262         // Fixed arguments type checks, starting from 1, as receiver type doesn't participate
   259         for(int i = 1; i < fixedArgLen; ++i) {
   263         for(int i = 1; i < fixedArgLen; ++i) {
   260             if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) {
   264             if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) {
   261                 return false;
   265                 return false;
   262             }
   266             }
   263         }
   267         }
   264         if(varArgs) {
   268         if(!varArgs) {
   265             final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen);
   269             // Not vararg; both arity and types matched.
   266             final Class<?> varArgType = varArgArrayType.getComponentType();
       
   267             if(fixedArgLen == callSiteArgLen - 1) {
       
   268                 final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen);
       
   269                 // Exactly one vararg; check both exact matching and component
       
   270                 // matching.
       
   271                 return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType)
       
   272                         || isApplicableDynamically(linkerServices, callSiteArgType, varArgType);
       
   273             } else {
       
   274                 for(int i = fixedArgLen; i < callSiteArgLen; ++i) {
       
   275                     if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) {
       
   276                         return false;
       
   277                     }
       
   278                 }
       
   279                 return true;
       
   280             }
       
   281         } else {
       
   282             return true;
   270             return true;
   283         }
   271         }
       
   272 
       
   273         final Class<?> varArgArrayType = methodType.parameterType(fixedArgLen);
       
   274         final Class<?> varArgType = varArgArrayType.getComponentType();
       
   275 
       
   276         if(fixedArgLen == callSiteArgLen - 1) {
       
   277             // Exactly one vararg; check both array type matching and array component type matching.
       
   278             final Class<?> callSiteArgType = callSiteType.parameterType(fixedArgLen);
       
   279             return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType)
       
   280                     || isApplicableDynamically(linkerServices, callSiteArgType, varArgType);
       
   281         }
       
   282 
       
   283         // Either zero, or more than one vararg; check if all actual vararg types match the vararg array component type.
       
   284         for(int i = fixedArgLen; i < callSiteArgLen; ++i) {
       
   285             if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) {
       
   286                 return false;
       
   287             }
       
   288         }
       
   289 
       
   290         return true;
   284     }
   291     }
   285 
   292 
   286     private static boolean isApplicableDynamically(LinkerServices linkerServices, Class<?> callSiteType,
   293     private static boolean isApplicableDynamically(LinkerServices linkerServices, Class<?> callSiteType,
   287             Class<?> methodType) {
   294             Class<?> methodType) {
   288         return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType)
   295         return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType)
   296     /**
   303     /**
   297      * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set.
   304      * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set.
   298      *
   305      *
   299      * @param method the method to add.
   306      * @param method the method to add.
   300      */
   307      */
   301     public void addMethod(SimpleDynamicMethod method) {
   308     void addMethod(SimpleDynamicMethod method) {
   302         addMethod(method.getTarget());
   309         addMethod(method.getTarget());
   303     }
   310     }
   304 
   311 
   305     /**
   312     /**
   306      * Add a method to this overloaded method's set.
   313      * Add a method to this overloaded method's set.