34 /**
35 * Abstract implementation of a lambda metafactory which provides parameter
36 * unrolling and input validation.
37 *
38 * @see LambdaMetafactory
39 */
40 /* package */ abstract class AbstractValidatingLambdaMetafactory {
41
42 /*
43 * For context, the comments for the following fields are marked in quotes
44 * with their values, given this program:
45 * interface II<T> { Object foo(T x); }
46 * interface JJ<R extends Number> extends II<R> { }
47 * class CC { String impl(int i) { return "impl:"+i; }}
48 * class X {
49 * public static void main(String[] args) {
50 * JJ<Integer> iii = (new CC())::impl;
51 * System.out.printf(">>> %s\n", iii.foo(44));
52 * }}
53 */
54 final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X"
55 final MethodType invokedType; // The type of the invoked method "(CC)II"
56 final Class<?> samBase; // The type of the returned instance "interface JJ"
57 final String samMethodName; // Name of the SAM method "foo"
58 final MethodType samMethodType; // Type of the SAM method "(Object)Object"
59 final MethodHandle implMethod; // Raw method handle for the implementation method
60 final MethodType implMethodType; // Type of the implMethod MethodHandle "(CC,int)String"
61 final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
62 final int implKind; // Invocation kind for implementation "5"=invokevirtual
63 final boolean implIsInstanceMethod; // Is the implementation an instance method "true"
64 final Class<?> implClass; // Class for referencing the implementation method "class CC"
65 final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
66 final boolean isSerializable; // Should the returned instance be serializable
67 final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
68 final MethodType[] additionalBridges; // Signatures of additional methods to bridge
69
70
71 /**
72 * Meta-factory constructor.
73 *
103 * @param additionalBridges Method types for additional signatures to be
104 * bridged to the implementation method
105 * @throws LambdaConversionException If any of the meta-factory protocol
106 * invariants are violated
107 */
108 AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
109 MethodType invokedType,
110 String samMethodName,
111 MethodType samMethodType,
112 MethodHandle implMethod,
113 MethodType instantiatedMethodType,
114 boolean isSerializable,
115 Class<?>[] markerInterfaces,
116 MethodType[] additionalBridges)
117 throws LambdaConversionException {
118 if ((caller.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
119 throw new LambdaConversionException(String.format(
120 "Invalid caller: %s",
121 caller.lookupClass().getName()));
122 }
123 this.targetClass = caller.lookupClass();
124 this.invokedType = invokedType;
125
126 this.samBase = invokedType.returnType();
127
128 this.samMethodName = samMethodName;
129 this.samMethodType = samMethodType;
130
131 this.implMethod = implMethod;
132 this.implMethodType = implMethod.type();
133 this.implInfo = caller.revealDirect(implMethod);
134 switch (implInfo.getReferenceKind()) {
135 case REF_invokeVirtual:
136 case REF_invokeInterface:
137 this.implClass = implMethodType.parameterType(0);
138 // reference kind reported by implInfo may not match implMethodType's first param
139 // Example: implMethodType is (Cloneable)String, implInfo is for Object.toString
140 this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
141 this.implIsInstanceMethod = true;
142 break;
143 case REF_invokeSpecial:
144 // JDK-8172817: should use referenced class here, but we don't know what it was
145 this.implClass = implInfo.getDeclaringClass();
146 this.implKind = REF_invokeSpecial;
147 this.implIsInstanceMethod = true;
148 break;
149 case REF_invokeStatic:
150 case REF_newInvokeSpecial:
151 // JDK-8172817: should use referenced class here for invokestatic, but we don't know what it was
152 this.implClass = implInfo.getDeclaringClass();
153 this.implKind = implInfo.getReferenceKind();
154 this.implIsInstanceMethod = false;
155 break;
156 default:
157 throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", implInfo));
158 }
159
160 this.instantiatedMethodType = instantiatedMethodType;
161 this.isSerializable = isSerializable;
162 this.markerInterfaces = markerInterfaces;
163 this.additionalBridges = additionalBridges;
164
165 if (samMethodName.isEmpty() ||
166 samMethodName.indexOf('.') >= 0 ||
167 samMethodName.indexOf(';') >= 0 ||
|
34 /**
35 * Abstract implementation of a lambda metafactory which provides parameter
36 * unrolling and input validation.
37 *
38 * @see LambdaMetafactory
39 */
40 /* package */ abstract class AbstractValidatingLambdaMetafactory {
41
42 /*
43 * For context, the comments for the following fields are marked in quotes
44 * with their values, given this program:
45 * interface II<T> { Object foo(T x); }
46 * interface JJ<R extends Number> extends II<R> { }
47 * class CC { String impl(int i) { return "impl:"+i; }}
48 * class X {
49 * public static void main(String[] args) {
50 * JJ<Integer> iii = (new CC())::impl;
51 * System.out.printf(">>> %s\n", iii.foo(44));
52 * }}
53 */
54 final MethodHandles.Lookup caller;
55 final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X"
56 final MethodType invokedType; // The type of the invoked method "(CC)II"
57 final Class<?> samBase; // The type of the returned instance "interface JJ"
58 final String samMethodName; // Name of the SAM method "foo"
59 final MethodType samMethodType; // Type of the SAM method "(Object)Object"
60 final MethodHandle implMethod; // Raw method handle for the implementation method
61 final MethodType implMethodType; // Type of the implMethod MethodHandle "(CC,int)String"
62 final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
63 final int implKind; // Invocation kind for implementation "5"=invokevirtual
64 final boolean implIsInstanceMethod; // Is the implementation an instance method "true"
65 final Class<?> implClass; // Class for referencing the implementation method "class CC"
66 final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
67 final boolean isSerializable; // Should the returned instance be serializable
68 final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
69 final MethodType[] additionalBridges; // Signatures of additional methods to bridge
70
71
72 /**
73 * Meta-factory constructor.
74 *
104 * @param additionalBridges Method types for additional signatures to be
105 * bridged to the implementation method
106 * @throws LambdaConversionException If any of the meta-factory protocol
107 * invariants are violated
108 */
109 AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
110 MethodType invokedType,
111 String samMethodName,
112 MethodType samMethodType,
113 MethodHandle implMethod,
114 MethodType instantiatedMethodType,
115 boolean isSerializable,
116 Class<?>[] markerInterfaces,
117 MethodType[] additionalBridges)
118 throws LambdaConversionException {
119 if ((caller.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
120 throw new LambdaConversionException(String.format(
121 "Invalid caller: %s",
122 caller.lookupClass().getName()));
123 }
124 this.caller = caller;
125 this.targetClass = caller.lookupClass();
126 this.invokedType = invokedType;
127
128 this.samBase = invokedType.returnType();
129
130 this.samMethodName = samMethodName;
131 this.samMethodType = samMethodType;
132
133 this.implMethod = implMethod;
134 this.implMethodType = implMethod.type();
135 this.implInfo = caller.revealDirect(implMethod);
136 switch (implInfo.getReferenceKind()) {
137 case REF_invokeVirtual:
138 case REF_invokeInterface:
139 this.implClass = implMethodType.parameterType(0);
140 // reference kind reported by implInfo may not match implMethodType's first param
141 // Example: implMethodType is (Cloneable)String, implInfo is for Object.toString
142 this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
143 this.implIsInstanceMethod = true;
144 break;
145 case REF_invokeSpecial:
146 // JDK-8172817: should use referenced class here, but we don't know what it was
147 this.implClass = implInfo.getDeclaringClass();
148 this.implIsInstanceMethod = true;
149
150 // Classes compiled prior to dynamic nestmate support invokes a private instance
151 // method with REF_invokeSpecial.
152 //
153 // invokespecial should only be used to invoke private nestmate constructors.
154 // The lambda proxy class will be defined as a nestmate of targetClass.
155 // If the method to be invoked is an instance method of targetClass, then
156 // convert to use invokevirtual or invokeinterface.
157 if (targetClass == implClass && !implInfo.getName().equals("<init>")) {
158 this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
159 } else {
160 this.implKind = REF_invokeSpecial;
161 }
162 break;
163 case REF_invokeStatic:
164 case REF_newInvokeSpecial:
165 // JDK-8172817: should use referenced class here for invokestatic, but we don't know what it was
166 this.implClass = implInfo.getDeclaringClass();
167 this.implKind = implInfo.getReferenceKind();
168 this.implIsInstanceMethod = false;
169 break;
170 default:
171 throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", implInfo));
172 }
173
174 this.instantiatedMethodType = instantiatedMethodType;
175 this.isSerializable = isSerializable;
176 this.markerInterfaces = markerInterfaces;
177 this.additionalBridges = additionalBridges;
178
179 if (samMethodName.isEmpty() ||
180 samMethodName.indexOf('.') >= 0 ||
181 samMethodName.indexOf(';') >= 0 ||
|