nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
changeset 18841 9bbc4b8832b2
parent 16267 cd471d62bb6a
child 18876 ada98218aaae
equal deleted inserted replaced
18840:3e7bff1b7b59 18841:9bbc4b8832b2
    84 package jdk.internal.dynalink.beans;
    84 package jdk.internal.dynalink.beans;
    85 
    85 
    86 import java.lang.invoke.MethodHandle;
    86 import java.lang.invoke.MethodHandle;
    87 import java.lang.invoke.MethodHandles;
    87 import java.lang.invoke.MethodHandles;
    88 import java.lang.invoke.MethodType;
    88 import java.lang.invoke.MethodType;
       
    89 import java.lang.reflect.AccessibleObject;
       
    90 import java.lang.reflect.Constructor;
    89 import java.lang.reflect.Field;
    91 import java.lang.reflect.Field;
       
    92 import java.lang.reflect.Member;
    90 import java.lang.reflect.Method;
    93 import java.lang.reflect.Method;
    91 import java.lang.reflect.Modifier;
    94 import java.lang.reflect.Modifier;
    92 import java.util.HashMap;
    95 import java.util.HashMap;
    93 import java.util.List;
    96 import java.util.List;
    94 import java.util.Map;
    97 import java.util.Map;
   107  * exposure and method calls for both static and instance facets of a class.
   110  * exposure and method calls for both static and instance facets of a class.
   108  *
   111  *
   109  * @author Attila Szegedi
   112  * @author Attila Szegedi
   110  */
   113  */
   111 abstract class AbstractJavaLinker implements GuardingDynamicLinker {
   114 abstract class AbstractJavaLinker implements GuardingDynamicLinker {
       
   115 
   112     final Class<?> clazz;
   116     final Class<?> clazz;
   113     private final MethodHandle classGuard;
   117     private final MethodHandle classGuard;
   114     private final MethodHandle assignableGuard;
   118     private final MethodHandle assignableGuard;
   115     private final Map<String, AnnotatedMethodHandle> propertyGetters = new HashMap<>();
   119     private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>();
   116     private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
   120     private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
   117     private final Map<String, DynamicMethod> methods = new HashMap<>();
   121     private final Map<String, DynamicMethod> methods = new HashMap<>();
   118 
   122 
   119     AbstractJavaLinker(Class<?> clazz, MethodHandle classGuard) {
   123     AbstractJavaLinker(Class<?> clazz, MethodHandle classGuard) {
   120         this(clazz, classGuard, classGuard);
   124         this(clazz, classGuard, classGuard);
   127 
   131 
   128         final FacetIntrospector introspector = createFacetIntrospector();
   132         final FacetIntrospector introspector = createFacetIntrospector();
   129         // Add methods and properties
   133         // Add methods and properties
   130         for(Method method: introspector.getMethods()) {
   134         for(Method method: introspector.getMethods()) {
   131             final String name = method.getName();
   135             final String name = method.getName();
   132             final MethodHandle methodHandle = introspector.unreflect(method);
       
   133             // Add method
   136             // Add method
   134             addMember(name, methodHandle, methods);
   137             addMember(name, method, methods);
   135             // Add the method as a property getter and/or setter
   138             // Add the method as a property getter and/or setter
   136             if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
   139             if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
   137                 // Property getter
   140                 // Property getter
   138                 setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect(
   141                 setPropertyGetter(method, 3);
   139                         getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
       
   140             } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
   142             } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
   141                     method.getReturnType() == boolean.class) {
   143                     method.getReturnType() == boolean.class) {
   142                 // Boolean property getter
   144                 // Boolean property getter
   143                 setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect(
   145                 setPropertyGetter(method, 2);
   144                         getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
       
   145             } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
   146             } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
   146                 // Property setter
   147                 // Property setter
   147                 addMember(decapitalize(name.substring(3)), methodHandle, propertySetters);
   148                 addMember(decapitalize(name.substring(3)), method, propertySetters);
   148             }
   149             }
   149         }
   150         }
   150 
   151 
   151         // Add field getter/setters as property getters/setters.
   152         // Add field getter/setters as property getters/setters.
   152         for(Field field: introspector.getFields()) {
   153         for(Field field: introspector.getFields()) {
   154             // Only add a property getter when one is not defined already as a getXxx()/isXxx() method.
   155             // Only add a property getter when one is not defined already as a getXxx()/isXxx() method.
   155             if(!propertyGetters.containsKey(name)) {
   156             if(!propertyGetters.containsKey(name)) {
   156                 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
   157                 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
   157             }
   158             }
   158             if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
   159             if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
   159                 addMember(name, introspector.unreflectSetter(field), propertySetters);
   160                 addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
       
   161                         propertySetters);
   160             }
   162             }
   161         }
   163         }
   162 
   164 
   163         // Add inner classes, but only those for which we don't hide a property with it
   165         // Add inner classes, but only those for which we don't hide a property with it
   164         for(Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) {
   166         for(Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) {
   190         return new String(c);
   192         return new String(c);
   191     }
   193     }
   192 
   194 
   193     abstract FacetIntrospector createFacetIntrospector();
   195     abstract FacetIntrospector createFacetIntrospector();
   194 
   196 
       
   197     /**
       
   198      * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
       
   199      * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
       
   200      * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
       
   201      * instead.
       
   202      * @param name name of the property
       
   203      * @param handle the method handle that implements the property getter
       
   204      * @param validationType the validation type for the property
       
   205      */
       
   206     private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) {
       
   207         propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
       
   208     }
       
   209 
       
   210     /**
       
   211      * Sets the specified reflective method to be the property getter for the specified property.
       
   212      * @param getter the getter method
       
   213      * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
       
   214      * names starting with "is".
       
   215      */
       
   216     private void setPropertyGetter(Method getter, int prefixLen) {
       
   217         setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
       
   218                 getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
       
   219     }
       
   220 
       
   221     /**
       
   222      * Sets the specified method handle to be the property getter for the specified property. Note that you can only
       
   223      * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
       
   224      * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
       
   225      * instead.
       
   226      * @param name name of the property
       
   227      * @param handle the method handle that implements the property getter
       
   228      * @param validationType the validation type for the property
       
   229      */
   195     void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
   230     void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
   196         propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType));
   231         setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
   197     }
   232     }
   198 
   233 
   199     private void addMember(String name, MethodHandle mh, Map<String, DynamicMethod> methodMap) {
   234     private void addMember(String name, AccessibleObject ao, Map<String, DynamicMethod> methodMap) {
       
   235         addMember(name, createDynamicMethod(ao), methodMap);
       
   236     }
       
   237 
       
   238     private void addMember(String name, SingleDynamicMethod method, Map<String, DynamicMethod> methodMap) {
   200         final DynamicMethod existingMethod = methodMap.get(name);
   239         final DynamicMethod existingMethod = methodMap.get(name);
   201         final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name);
   240         final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
   202         if(newMethod != existingMethod) {
   241         if(newMethod != existingMethod) {
   203             methodMap.put(name, newMethod);
   242             methodMap.put(name, newMethod);
   204         }
   243         }
   205     }
   244     }
   206 
   245 
   207     static DynamicMethod createDynamicMethod(Iterable<MethodHandle> methodHandles, Class<?> clazz, String name) {
   246     /**
       
   247      * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
       
   248      * methods should represent all overloads of the same name (or all constructors of the class).
       
   249      * @param members the reflective members
       
   250      * @param clazz the class declaring the reflective members
       
   251      * @param name the common name of the reflective members.
       
   252      * @return a dynamic method representing all the specified reflective members.
       
   253      */
       
   254     static DynamicMethod createDynamicMethod(Iterable<? extends AccessibleObject> members, Class<?> clazz, String name) {
   208         DynamicMethod dynMethod = null;
   255         DynamicMethod dynMethod = null;
   209         for(MethodHandle methodHandle: methodHandles) {
   256         for(AccessibleObject method: members) {
   210             dynMethod = addMember(methodHandle, dynMethod, clazz, name);
   257             dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
   211         }
   258         }
   212         return dynMethod;
   259         return dynMethod;
   213     }
   260     }
   214 
   261 
   215     private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class<?> clazz, String name) {
   262     /**
       
   263      * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
       
   264      * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
       
   265      * dynamic method when needed.
       
   266      * @param m the reflective member
       
   267      * @return the single dynamic method representing the reflective member
       
   268      */
       
   269     private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) {
       
   270         if(CallerSensitiveDetector.isCallerSensitive(m)) {
       
   271             return new CallerSensitiveDynamicMethod(m);
       
   272         }
       
   273         final Member member = (Member)m;
       
   274         return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
       
   275     }
       
   276 
       
   277     /**
       
   278      * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
       
   279      * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
       
   280      * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
       
   281      * unreflector as its caller, and thus completely useless.
       
   282      * @param m the method or constructor
       
   283      * @return the method handle
       
   284      */
       
   285     private static MethodHandle unreflectSafely(AccessibleObject m) {
       
   286         if(m instanceof Method) {
       
   287             final Method reflMethod = (Method)m;
       
   288             final MethodHandle handle = SafeUnreflector.unreflect(reflMethod);
       
   289             if(Modifier.isStatic(reflMethod.getModifiers())) {
       
   290                 return StaticClassIntrospector.editStaticMethodHandle(handle);
       
   291             }
       
   292             return handle;
       
   293         }
       
   294         return StaticClassIntrospector.editConstructorMethodHandle(SafeUnreflector.unreflectConstructor(
       
   295                 (Constructor<?>)m));
       
   296     }
       
   297 
       
   298     private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class<?> clazz, String name) {
   216         if(existing == null) {
   299         if(existing == null) {
   217             return new SimpleDynamicMethod(mh, clazz, name);
   300             return method;
   218         } else if(existing.contains(mh)) {
   301         } else if(existing.contains(method)) {
   219             return existing;
   302             return existing;
   220         } else if(existing instanceof SimpleDynamicMethod) {
   303         } else if(existing instanceof SingleDynamicMethod) {
   221             final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
   304             final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
   222             odm.addMethod(((SimpleDynamicMethod)existing));
   305             odm.addMethod(((SingleDynamicMethod)existing));
   223             odm.addMethod(mh);
   306             odm.addMethod(method);
   224             return odm;
   307             return odm;
   225         } else if(existing instanceof OverloadedDynamicMethod) {
   308         } else if(existing instanceof OverloadedDynamicMethod) {
   226             ((OverloadedDynamicMethod)existing).addMethod(mh);
   309             ((OverloadedDynamicMethod)existing).addMethod(method);
   227             return existing;
   310             return existing;
   228         }
   311         }
   229         throw new AssertionError();
   312         throw new AssertionError();
   230     }
   313     }
   231 
   314 
   294     }
   377     }
   295 
   378 
   296     private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
   379     private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
   297         switch(callSiteDescriptor.getNameTokenCount()) {
   380         switch(callSiteDescriptor.getNameTokenCount()) {
   298             case 3: {
   381             case 3: {
   299                 return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices,
   382                 return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
   300                         callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
   383                         callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
   301             }
   384             }
   302             default: {
   385             default: {
   303                 return null;
   386                 return null;
   304             }
   387             }
   305         }
   388         }
   306     }
   389     }
   307 
   390 
   308     private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType,
   391     private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
   309             LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){
   392             LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){
   310         final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap);
   393         final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
   311         return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType));
   394         return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
   312     }
   395     }
   313 
   396 
   314     private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices,
   397     private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
   315             String methodName, Map<String, DynamicMethod> methodMap) {
   398             LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap) {
   316         final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
   399         final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
   317         return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null;
   400         return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
   318     }
   401     }
   319 
   402 
   320     private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) {
   403     private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) {
   321         final DynamicMethod dynaMethod = methodMap.get(methodName);
   404         final DynamicMethod dynaMethod = methodMap.get(methodName);
   322         return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
   405         return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
   323     }
   406     }
   324 
   407 
   325     private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
   408     private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
   326             Map<String, DynamicMethod> methodsMap) {
   409             Map<String, DynamicMethod> methodsMap) {
   327         // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
   410         // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
   328         // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
   411         // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
   329         // resolution works correctly in almost every situation. However, in presence of many language-specific
   412         // resolution works correctly in almost every situation. However, in presence of many language-specific
   330         // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
   413         // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
   331         // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload
   414         // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
   332         // for performance reasons.
   415         // for performance reasons.
   333 
   416 
   334         // Is the method name lexically of the form "name(types)"?
   417         // Is the method name lexically of the form "name(types)"?
   335         final int lastChar = methodName.length() - 1;
   418         final int lastChar = methodName.length() - 1;
   336         if(methodName.charAt(lastChar) != ')') {
   419         if(methodName.charAt(lastChar) != ')') {
   375                 // abbreviate to R(O, N, V) going forward.
   458                 // abbreviate to R(O, N, V) going forward.
   376                 // We want setters that conform to "R(O, V)"
   459                 // We want setters that conform to "R(O, V)"
   377                 final MethodType setterType = type.dropParameterTypes(1, 2);
   460                 final MethodType setterType = type.dropParameterTypes(1, 2);
   378                 // Bind property setter handle to the expected setter type and linker services. Type is
   461                 // Bind property setter handle to the expected setter type and linker services. Type is
   379                 // MethodHandle(Object, String, Object)
   462                 // MethodHandle(Object, String, Object)
   380                 final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType,
   463                 final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
   381                         linkerServices);
   464                         CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
   382 
   465 
   383                 // Cast getter to MethodHandle(O, N, V)
   466                 // Cast getter to MethodHandle(O, N, V)
   384                 final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
   467                 final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
   385                         MethodHandle.class));
   468                         MethodHandle.class));
   386 
   469 
   413                 return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
   496                 return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
   414             }
   497             }
   415             case 3: {
   498             case 3: {
   416                 // Must have two arguments: target object and property value
   499                 // Must have two arguments: target object and property value
   417                 assertParameterCount(callSiteDescriptor, 2);
   500                 assertParameterCount(callSiteDescriptor, 2);
   418                 final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(),
   501                 final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
   419                         linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND),
   502                         callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
   420                         propertySetters);
       
   421                 // If we have a property setter with this name, this composite operation will always stop here
   503                 // If we have a property setter with this name, this composite operation will always stop here
   422                 if(gi != null) {
   504                 if(gi != null) {
   423                     return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
   505                     return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
   424                 }
   506                 }
   425                 // If we don't have a property setter with this name, always fall back to the next operation in the
   507                 // If we don't have a property setter with this name, always fall back to the next operation in the
   433         }
   515         }
   434     }
   516     }
   435 
   517 
   436     private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
   518     private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
   437 
   519 
   438     private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
   520     private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
   439             boolean.class, AnnotatedMethodHandle.class));
   521             boolean.class, AnnotatedDynamicMethod.class));
   440     private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments(
   522     private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
   441             MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class);
   523             MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
   442     private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class,
   524     private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
   443             "handle", MethodHandle.class);
   525             "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class));
   444     private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments(
   526     private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
   445             MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE);
       
   446 
   527 
   447     private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
   528     private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
   448             LinkerServices linkerServices, List<String> ops) throws Exception {
   529             LinkerServices linkerServices, List<String> ops) throws Exception {
   449         final MethodType type = callSiteDescriptor.getMethodType();
   530         final MethodType type = callSiteDescriptor.getMethodType();
   450         switch(callSiteDescriptor.getNameTokenCount()) {
   531         switch(callSiteDescriptor.getNameTokenCount()) {
   453                 assertParameterCount(callSiteDescriptor, 2);
   534                 assertParameterCount(callSiteDescriptor, 2);
   454 
   535 
   455                 // What's below is basically:
   536                 // What's below is basically:
   456                 //   foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
   537                 //   foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
   457                 // only with a bunch of method signature adjustments. Basically, retrieve method getter
   538                 // only with a bunch of method signature adjustments. Basically, retrieve method getter
   458                 // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null,
   539                 // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
   459                 // or delegate to next component's invocation.
   540                 // or delegate to next component's invocation.
   460 
   541 
   461                 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
   542                 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
   462                         AnnotatedMethodHandle.class));
   543                         AnnotatedDynamicMethod.class));
   463                 // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0)
   544                 final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
   464                 final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER,
   545                         GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
   465                         MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0)));
   546                 final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
       
   547                         callSiteBoundMethodGetter);
       
   548                 // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
       
   549                 final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
       
   550                         MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
   466                 // Since it's in the target of a fold, drop the unnecessary second argument
   551                 // Since it's in the target of a fold, drop the unnecessary second argument
   467                 // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1)
   552                 // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
   468                 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
   553                 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
   469                         type.parameterType(1));
   554                         type.parameterType(1));
   470                 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
   555                 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
   471                         linkerServices, ops);
   556                         linkerServices, ops);
   472 
   557 
   473                 final MethodHandle fallbackFolded;
   558                 final MethodHandle fallbackFolded;
   474                 if(nextComponent == null) {
   559                 if(nextComponent == null) {
   475                     // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null
   560                     // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
   476                     fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1,
   561                     fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
   477                             type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class));
   562                             type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
   478                 } else {
   563                 } else {
   479                     // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the
   564                     // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
   480                     // extra argument resulting from fold
   565                     // extra argument resulting from fold
   481                     fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
   566                     fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
   482                             0, AnnotatedMethodHandle.class);
   567                             0, AnnotatedDynamicMethod.class);
   483                 }
   568                 }
   484 
   569 
   485                 // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1))
   570                 // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
   486                 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
   571                 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
   487                             IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
   572                             IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
   488                 if(nextComponent == null) {
   573                 if(nextComponent == null) {
   489                     return getClassGuardedInvocationComponent(compositeGetter, type);
   574                     return getClassGuardedInvocationComponent(compositeGetter, type);
   490                 }
   575                 }
   491                 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
   576                 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
   492             }
   577             }
   493             case 3: {
   578             case 3: {
   494                 // Must have exactly one argument: receiver
   579                 // Must have exactly one argument: receiver
   495                 assertParameterCount(callSiteDescriptor, 1);
   580                 assertParameterCount(callSiteDescriptor, 1);
   496                 // Fixed name
   581                 // Fixed name
   497                 final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
   582                 final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
   498                         CallSiteDescriptor.NAME_OPERAND));
   583                         CallSiteDescriptor.NAME_OPERAND));
   499                 if(annGetter == null) {
   584                 if(annGetter == null) {
   500                     // We have no such property, always delegate to the next component operation
   585                     // We have no such property, always delegate to the next component operation
   501                     return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
   586                     return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
   502                 }
   587                 }
   503                 final MethodHandle getter = annGetter.handle;
   588                 final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
   504                 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
   589                 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
   505                 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
   590                 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
   506                 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
   591                 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
   507                 // we're linking against a field getter, don't make the assumption.
   592                 // we're linking against a field getter, don't make the assumption.
   508                 // NOTE: No delegation to the next component operation if we have a property with this name, even if its
   593                 // NOTE: No delegation to the next component operation if we have a property with this name, even if its
   509                 // value is null.
   594                 // value is null.
   510                 final ValidationType validationType = annGetter.validationType;
   595                 final ValidationType validationType = annGetter.validationType;
       
   596                 // TODO: we aren't using the type that declares the most generic getter here!
   511                 return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
   597                 return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
   512                         type), clazz, validationType);
   598                         type), clazz, validationType);
   513             }
   599             }
   514             default: {
   600             default: {
   515                 // Can't do anything with more than 3 name components
   601                 // Can't do anything with more than 3 name components
   621 
   707 
   622     // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object"
   708     // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object"
   623     // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
   709     // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
   624     // a typical property setter with variable name signature (target, name, value).
   710     // a typical property setter with variable name signature (target, name, value).
   625     private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
   711     private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
   626             privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class,
   712             privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
   627                     LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
   713                     LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
   628     // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
   714     // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
   629     private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
   715     private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
   630 
   716 
   631     @SuppressWarnings("unused")
   717     @SuppressWarnings("unused")
   632     private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) {
   718     private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices,
   633         return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters);
   719             Object id) {
       
   720         return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
   634     }
   721     }
   635 
   722 
   636     private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
   723     private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
   637             "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class);
   724             "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class);
   638     private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this);
   725     private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this);
   687             }
   774             }
   688         }
   775         }
   689         return null;
   776         return null;
   690     }
   777     }
   691 
   778 
   692     private static final class AnnotatedMethodHandle {
   779     private static final class AnnotatedDynamicMethod {
   693         final MethodHandle handle;
   780         private final SingleDynamicMethod method;
   694         /*private*/ final ValidationType validationType;
   781         /*private*/ final ValidationType validationType;
   695 
   782 
   696         AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) {
   783         AnnotatedDynamicMethod(SingleDynamicMethod method, ValidationType validationType) {
   697             this.handle = handle;
   784             this.method = method;
   698             this.validationType = validationType;
   785             this.validationType = validationType;
   699         }
   786         }
       
   787 
       
   788         MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
       
   789             return method.getInvocation(callSiteDescriptor, linkerServices);
       
   790         }
       
   791 
       
   792         @SuppressWarnings("unused")
       
   793         MethodHandle getTarget(MethodHandles.Lookup lookup) {
       
   794             MethodHandle inv = method.getTarget(lookup);
       
   795             assert inv != null;
       
   796             return inv;
       
   797         }
   700     }
   798     }
   701 }
   799 }