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