src/jdk/internal/dynalink/beans/AbstractJavaLinker.java

changeset 963
e2497b11a021
parent 962
ac62e33a99b0
child 1081
a54684572f14
     1.1 --- a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Wed Aug 20 10:25:28 2014 +0200
     1.2 +++ b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Wed Aug 20 10:26:01 2014 +0200
     1.3 @@ -106,6 +106,7 @@
     1.4  import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
     1.5  import jdk.internal.dynalink.support.Guards;
     1.6  import jdk.internal.dynalink.support.Lookup;
     1.7 +import jdk.internal.dynalink.support.TypeUtilities;
     1.8  
     1.9  /**
    1.10   * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property
    1.11 @@ -289,7 +290,7 @@
    1.12              return new CallerSensitiveDynamicMethod(m);
    1.13          }
    1.14          final Member member = (Member)m;
    1.15 -        return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
    1.16 +        return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName(), m instanceof Constructor);
    1.17      }
    1.18  
    1.19      /**
    1.20 @@ -389,6 +390,10 @@
    1.21          return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
    1.22      }
    1.23  
    1.24 +    SingleDynamicMethod getConstructorMethod(final String signature) {
    1.25 +        return null;
    1.26 +    }
    1.27 +
    1.28      private MethodHandle getAssignableGuard(final MethodType type) {
    1.29          return Guards.asType(assignableGuard, type);
    1.30      }
    1.31 @@ -411,18 +416,18 @@
    1.32          return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
    1.33      }
    1.34  
    1.35 -    private static MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
    1.36 +    private MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
    1.37              final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap) {
    1.38          final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
    1.39          return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
    1.40      }
    1.41  
    1.42 -    private static DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) {
    1.43 +    private DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) {
    1.44          final DynamicMethod dynaMethod = methodMap.get(methodName);
    1.45          return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
    1.46      }
    1.47  
    1.48 -    private static SingleDynamicMethod getExplicitSignatureDynamicMethod(final String methodName,
    1.49 +    private SingleDynamicMethod getExplicitSignatureDynamicMethod(final String fullName,
    1.50              final Map<String, DynamicMethod> methodsMap) {
    1.51          // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
    1.52          // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
    1.53 @@ -432,23 +437,33 @@
    1.54          // for performance reasons.
    1.55  
    1.56          // Is the method name lexically of the form "name(types)"?
    1.57 -        final int lastChar = methodName.length() - 1;
    1.58 -        if(methodName.charAt(lastChar) != ')') {
    1.59 +        final int lastChar = fullName.length() - 1;
    1.60 +        if(fullName.charAt(lastChar) != ')') {
    1.61              return null;
    1.62          }
    1.63 -        final int openBrace = methodName.indexOf('(');
    1.64 +        final int openBrace = fullName.indexOf('(');
    1.65          if(openBrace == -1) {
    1.66              return null;
    1.67          }
    1.68  
    1.69 +        final String name = fullName.substring(0, openBrace);
    1.70 +        final String signature = fullName.substring(openBrace + 1, lastChar);
    1.71 +
    1.72          // Find an existing method for the "name" part
    1.73 -        final DynamicMethod simpleNamedMethod = methodsMap.get(methodName.substring(0, openBrace));
    1.74 +        final DynamicMethod simpleNamedMethod = methodsMap.get(name);
    1.75          if(simpleNamedMethod == null) {
    1.76 +            // explicit signature constructor access
    1.77 +            // Java.type("java.awt.Color")["(int,int,int)"]
    1.78 +            // will get Color(int,int,int) constructor of Color class.
    1.79 +            if (name.isEmpty()) {
    1.80 +                return getConstructorMethod(signature);
    1.81 +            }
    1.82 +
    1.83              return null;
    1.84          }
    1.85  
    1.86          // Try to get a narrowed dynamic method for the explicit parameter types.
    1.87 -        return simpleNamedMethod.getMethodForExactParamTypes(methodName.substring(openBrace + 1, lastChar));
    1.88 +        return simpleNamedMethod.getMethodForExactParamTypes(signature);
    1.89      }
    1.90  
    1.91      private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
    1.92 @@ -458,12 +473,16 @@
    1.93  
    1.94      private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
    1.95              final LinkerServices linkerServices, final List<String> operations) throws Exception {
    1.96 -        final MethodType type = callSiteDescriptor.getMethodType();
    1.97          switch(callSiteDescriptor.getNameTokenCount()) {
    1.98              case 2: {
    1.99                  // Must have three arguments: target object, property name, and property value.
   1.100                  assertParameterCount(callSiteDescriptor, 3);
   1.101  
   1.102 +                // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
   1.103 +                // valid for us to convert return values proactively. Also, since we don't know what setters will be
   1.104 +                // invoked, we'll conservatively presume Object return type.
   1.105 +                final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
   1.106 +
   1.107                  // What's below is basically:
   1.108                  //   foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
   1.109                  //     get_setter_handle(type, linkerServices))
   1.110 @@ -472,8 +491,8 @@
   1.111                  // component's invocation.
   1.112  
   1.113                  // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
   1.114 -                // abbreviate to R(O, N, V) going forward.
   1.115 -                // We want setters that conform to "R(O, V)"
   1.116 +                // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
   1.117 +                // Object return type).
   1.118                  final MethodType setterType = type.dropParameterTypes(1, 2);
   1.119                  // Bind property setter handle to the expected setter type and linker services. Type is
   1.120                  // MethodHandle(Object, String, Object)
   1.121 @@ -494,11 +513,11 @@
   1.122  
   1.123                  final MethodHandle fallbackFolded;
   1.124                  if(nextComponent == null) {
   1.125 -                    // Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null
   1.126 +                    // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
   1.127                      fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
   1.128                              type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
   1.129                  } else {
   1.130 -                    // R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the
   1.131 +                    // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
   1.132                      // extra argument resulting from fold
   1.133                      fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
   1.134                              0, MethodHandle.class);
   1.135 @@ -544,9 +563,12 @@
   1.136  
   1.137      private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
   1.138              final LinkerServices linkerServices, final List<String> ops) throws Exception {
   1.139 -        final MethodType type = callSiteDescriptor.getMethodType();
   1.140          switch(callSiteDescriptor.getNameTokenCount()) {
   1.141              case 2: {
   1.142 +                // Since we can't know what kind of a getter we'll get back on different invocations, we'll just
   1.143 +                // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
   1.144 +                // runtime might not allow coercing at that call site.
   1.145 +                final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
   1.146                  // Must have exactly two arguments: receiver and name
   1.147                  assertParameterCount(callSiteDescriptor, 2);
   1.148  
   1.149 @@ -562,11 +584,11 @@
   1.150                          GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
   1.151                  final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
   1.152                          callSiteBoundMethodGetter);
   1.153 -                // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
   1.154 +                // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
   1.155                  final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
   1.156                          MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
   1.157                  // Since it's in the target of a fold, drop the unnecessary second argument
   1.158 -                // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
   1.159 +                // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
   1.160                  final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
   1.161                          type.parameterType(1));
   1.162                  final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
   1.163 @@ -574,17 +596,19 @@
   1.164  
   1.165                  final MethodHandle fallbackFolded;
   1.166                  if(nextComponent == null) {
   1.167 -                    // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
   1.168 +                    // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
   1.169                      fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
   1.170                              type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
   1.171                  } else {
   1.172 -                    // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
   1.173 -                    // extra argument resulting from fold
   1.174 -                    fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
   1.175 -                            0, AnnotatedDynamicMethod.class);
   1.176 +                    // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
   1.177 +                    // drop the extra argument resulting from fold and to change its return type to Object.
   1.178 +                    final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
   1.179 +                    final MethodType nextType = nextInvocation.type();
   1.180 +                    fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
   1.181 +                            nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
   1.182                  }
   1.183  
   1.184 -                // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
   1.185 +                // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
   1.186                  final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
   1.187                              IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
   1.188                  if(nextComponent == null) {
   1.189 @@ -611,8 +635,8 @@
   1.190                  // value is null.
   1.191                  final ValidationType validationType = annGetter.validationType;
   1.192                  // TODO: we aren't using the type that declares the most generic getter here!
   1.193 -                return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
   1.194 -                        type), clazz, validationType);
   1.195 +                return new GuardedInvocationComponent(getter, getGuard(validationType,
   1.196 +                        callSiteDescriptor.getMethodType()), clazz, validationType);
   1.197              }
   1.198              default: {
   1.199                  // Can't do anything with more than 3 name components
   1.200 @@ -641,21 +665,25 @@
   1.201          }
   1.202      }
   1.203  
   1.204 -    private static final MethodHandle IS_DYNAMIC_METHOD_NOT_NULL = Guards.asType(Guards.isNotNull(),
   1.205 -            MethodType.methodType(boolean.class, DynamicMethod.class));
   1.206 -    private static final MethodHandle DYNAMIC_METHOD_IDENTITY = MethodHandles.identity(DynamicMethod.class);
   1.207 +    private static final MethodHandle IS_DYNAMIC_METHOD = Guards.isInstance(DynamicMethod.class,
   1.208 +            MethodType.methodType(boolean.class, Object.class));
   1.209 +    private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
   1.210  
   1.211      private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
   1.212              final LinkerServices linkerServices, final List<String> ops) throws Exception {
   1.213 -        final MethodType type = callSiteDescriptor.getMethodType();
   1.214 +        // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
   1.215 +        // be visible outside of this linker, declare it to return Object.
   1.216 +        final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
   1.217          switch(callSiteDescriptor.getNameTokenCount()) {
   1.218              case 2: {
   1.219                  // Must have exactly two arguments: receiver and name
   1.220                  assertParameterCount(callSiteDescriptor, 2);
   1.221                  final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
   1.222                          linkerServices, ops);
   1.223 -                if(nextComponent == null) {
   1.224 -                    // No next component operation; just return a component for this operation.
   1.225 +                if(nextComponent == null || !TypeUtilities.areAssignable(DynamicMethod.class,
   1.226 +                        nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
   1.227 +                    // No next component operation, or it can never produce a dynamic method; just return a component
   1.228 +                    // for this operation.
   1.229                      return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
   1.230                  }
   1.231  
   1.232 @@ -664,21 +692,20 @@
   1.233                  // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
   1.234                  // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
   1.235  
   1.236 -                final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type.changeReturnType(
   1.237 -                        DynamicMethod.class));
   1.238 +                final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
   1.239                  // Since it is part of the foldArgument() target, it will have extra args that we need to drop.
   1.240                  final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
   1.241 -                        DYNAMIC_METHOD_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0,
   1.242 -                                DynamicMethod.class));
   1.243 +                        OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
   1.244                  final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
   1.245 -                // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly
   1.246 -                assert nextComponentInvocation.type().equals(type);
   1.247 +                // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
   1.248 +                // return type.
   1.249 +                assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
   1.250                  // Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
   1.251                  final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
   1.252 -                        DynamicMethod.class);
   1.253 +                        Object.class);
   1.254                  // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
   1.255                  final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
   1.256 -                        IS_DYNAMIC_METHOD_NOT_NULL, returnMethodHandle, nextCombinedInvocation), typedGetter);
   1.257 +                        IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
   1.258  
   1.259                  return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
   1.260              }
   1.261 @@ -694,7 +721,7 @@
   1.262                  // No delegation to the next component of the composite operation; if we have a method with that name,
   1.263                  // we'll always return it at this point.
   1.264                  return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
   1.265 -                        MethodHandles.constant(DynamicMethod.class, method), 0, type.parameterType(0)), type), type);
   1.266 +                        MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
   1.267              }
   1.268              default: {
   1.269                  // Can't do anything with more than 3 name components
   1.270 @@ -703,6 +730,30 @@
   1.271          }
   1.272      }
   1.273  
   1.274 +    static class MethodPair {
   1.275 +        final MethodHandle method1;
   1.276 +        final MethodHandle method2;
   1.277 +
   1.278 +        MethodPair(final MethodHandle method1, final MethodHandle method2) {
   1.279 +            this.method1 = method1;
   1.280 +            this.method2 = method2;
   1.281 +        }
   1.282 +
   1.283 +        MethodHandle guardWithTest(final MethodHandle test) {
   1.284 +            return MethodHandles.guardWithTest(test, method1, method2);
   1.285 +        }
   1.286 +    }
   1.287 +
   1.288 +    static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) {
   1.289 +        final MethodType type1 = m1.type();
   1.290 +        final MethodType type2 = m2.type();
   1.291 +        final Class<?> commonRetType = TypeUtilities.getCommonLosslessConversionType(type1.returnType(),
   1.292 +                type2.returnType());
   1.293 +        return new MethodPair(
   1.294 +                m1.asType(type1.changeReturnType(commonRetType)),
   1.295 +                m2.asType(type2.changeReturnType(commonRetType)));
   1.296 +    }
   1.297 +
   1.298      private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
   1.299          if(descriptor.getMethodType().parameterCount() != paramCount) {
   1.300              throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
   1.301 @@ -738,11 +789,14 @@
   1.302      }
   1.303  
   1.304      private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
   1.305 -            "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class);
   1.306 +            "getDynamicMethod", Object.class, Object.class), 1, Object.class);
   1.307      private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this);
   1.308  
   1.309      @SuppressWarnings("unused")
   1.310 -    private DynamicMethod getDynamicMethod(final Object name) {
   1.311 +    // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
   1.312 +    // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
   1.313 +    // "dyn:getMethod" linking).
   1.314 +    private Object getDynamicMethod(final Object name) {
   1.315          return getDynamicMethod(String.valueOf(name), methods);
   1.316      }
   1.317  

mercurial