23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package java.lang.invoke; |
26 package java.lang.invoke; |
27 |
27 |
|
28 import jdk.internal.org.objectweb.asm.*; |
|
29 import sun.misc.Unsafe; |
|
30 |
28 import java.lang.reflect.Constructor; |
31 import java.lang.reflect.Constructor; |
29 import java.lang.reflect.Method; |
32 import java.security.AccessController; |
|
33 import java.security.PrivilegedAction; |
30 import java.security.ProtectionDomain; |
34 import java.security.ProtectionDomain; |
31 import java.util.concurrent.atomic.AtomicInteger; |
35 import java.util.concurrent.atomic.AtomicInteger; |
32 import jdk.internal.org.objectweb.asm.*; |
36 |
33 import static jdk.internal.org.objectweb.asm.Opcodes.*; |
37 import static jdk.internal.org.objectweb.asm.Opcodes.*; |
34 import sun.misc.Unsafe; |
|
35 import java.security.AccessController; |
|
36 import java.security.PrivilegedAction; |
|
37 |
38 |
38 /** |
39 /** |
39 * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite. |
40 * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite. |
40 * |
41 * |
41 * @see LambdaMetafactory |
42 * @see LambdaMetafactory |
42 */ |
43 */ |
43 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { |
44 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { |
|
45 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); |
|
46 |
44 private static final int CLASSFILE_VERSION = 51; |
47 private static final int CLASSFILE_VERSION = 51; |
45 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); |
48 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); |
46 private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; |
49 private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; |
47 private static final String NAME_CTOR = "<init>"; |
50 private static final String NAME_CTOR = "<init>"; |
48 |
51 |
75 private final String[] argNames; // Generated names for the constructor arguments |
78 private final String[] argNames; // Generated names for the constructor arguments |
76 private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" |
79 private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" |
77 private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments |
80 private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments |
78 |
81 |
79 /** |
82 /** |
80 * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization. |
83 * General meta-factory constructor, supporting both standard cases and |
|
84 * allowing for uncommon options such as serialization or bridging. |
81 * |
85 * |
82 * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges |
86 * @param caller Stacked automatically by VM; represents a lookup context |
83 * of the caller. |
87 * with the accessibility privileges of the caller. |
84 * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the |
88 * @param invokedType Stacked automatically by VM; the signature of the |
85 * expected static type of the returned lambda object, and the static types of the captured |
89 * invoked method, which includes the expected static |
86 * arguments for the lambda. In the event that the implementation method is an instance method, |
90 * type of the returned lambda object, and the static |
87 * the first argument in the invocation signature will correspond to the receiver. |
91 * types of the captured arguments for the lambda. In |
88 * @param samMethod The primary method in the functional interface to which the lambda or method reference is |
92 * the event that the implementation method is an |
89 * being converted, represented as a method handle. |
93 * instance method, the first argument in the invocation |
90 * @param implMethod The implementation method which should be called (with suitable adaptation of argument |
94 * signature will correspond to the receiver. |
91 * types, return types, and adjustment for captured arguments) when methods of the resulting |
95 * @param samMethod The primary method in the functional interface to which |
92 * functional interface instance are invoked. |
96 * the lambda or method reference is being converted, |
93 * @param instantiatedMethodType The signature of the primary functional interface method after type variables |
97 * represented as a method handle. |
94 * are substituted with their instantiation from the capture site |
98 * @param implMethod The implementation method which should be called (with |
95 * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined |
99 * suitable adaptation of argument types, return types, |
96 * fields include FLAG_SERIALIZABLE. |
100 * and adjustment for captured arguments) when methods of |
97 * @param markerInterfaces Additional interfaces which the lambda object should implement. |
101 * the resulting functional interface instance are invoked. |
|
102 * @param instantiatedMethodType The signature of the primary functional |
|
103 * interface method after type variables are |
|
104 * substituted with their instantiation from |
|
105 * the capture site |
|
106 * @param isSerializable Should the lambda be made serializable? If set, |
|
107 * either the target type or one of the additional SAM |
|
108 * types must extend {@code Serializable}. |
|
109 * @param markerInterfaces Additional interfaces which the lambda object |
|
110 * should implement. |
|
111 * @param additionalBridges Method types for additional signatures to be |
|
112 * bridged to the implementation method |
98 * @throws ReflectiveOperationException |
113 * @throws ReflectiveOperationException |
99 * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated |
114 * @throws LambdaConversionException If any of the meta-factory protocol |
|
115 * invariants are violated |
100 */ |
116 */ |
101 public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, |
117 public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, |
102 MethodType invokedType, |
118 MethodType invokedType, |
103 MethodHandle samMethod, |
119 MethodHandle samMethod, |
104 MethodHandle implMethod, |
120 MethodHandle implMethod, |
105 MethodType instantiatedMethodType, |
121 MethodType instantiatedMethodType, |
106 int flags, |
122 boolean isSerializable, |
107 Class<?>[] markerInterfaces) |
123 Class<?>[] markerInterfaces, |
|
124 MethodType[] additionalBridges) |
108 throws ReflectiveOperationException, LambdaConversionException { |
125 throws ReflectiveOperationException, LambdaConversionException { |
109 super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces); |
126 super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, |
|
127 isSerializable, markerInterfaces, additionalBridges); |
110 implMethodClassName = implDefiningClass.getName().replace('.', '/'); |
128 implMethodClassName = implDefiningClass.getName().replace('.', '/'); |
111 implMethodName = implInfo.getName(); |
129 implMethodName = implInfo.getName(); |
112 implMethodDesc = implMethodType.toMethodDescriptorString(); |
130 implMethodDesc = implMethodType.toMethodDescriptorString(); |
113 Type implMethodAsmType = Type.getMethodType(implMethodDesc); |
131 Type implMethodAsmType = Type.getMethodType(implMethodDesc); |
114 implMethodArgumentTypes = implMethodAsmType.getArgumentTypes(); |
132 implMethodArgumentTypes = implMethodAsmType.getArgumentTypes(); |
172 |
191 |
173 /** |
192 /** |
174 * Generate a class file which implements the functional |
193 * Generate a class file which implements the functional |
175 * interface, define and return the class. |
194 * interface, define and return the class. |
176 * |
195 * |
|
196 * @implNote The class that is generated does not include signature |
|
197 * information for exceptions that may be present on the SAM method. |
|
198 * This is to reduce classfile size, and is harmless as checked exceptions |
|
199 * are erased anyway, no one will ever compile against this classfile, |
|
200 * and we make no guarantees about the reflective properties of lambda |
|
201 * objects. |
|
202 * |
177 * @return a Class which implements the functional interface |
203 * @return a Class which implements the functional interface |
178 * @throws LambdaConversionException If properly formed functional interface is not found |
204 * @throws LambdaConversionException If properly formed functional interface |
|
205 * is not found |
179 */ |
206 */ |
180 private Class<?> spinInnerClass() throws LambdaConversionException { |
207 private Class<?> spinInnerClass() throws LambdaConversionException { |
181 String samName = samBase.getName().replace('.', '/'); |
208 String samName = samBase.getName().replace('.', '/'); |
182 String[] interfaces = new String[markerInterfaces.length + 1]; |
209 String[] interfaces = new String[markerInterfaces.length + 1]; |
183 interfaces[0] = samName; |
210 interfaces[0] = samName; |
195 fv.visitEnd(); |
222 fv.visitEnd(); |
196 } |
223 } |
197 |
224 |
198 generateConstructor(); |
225 generateConstructor(); |
199 |
226 |
200 MethodAnalyzer ma = new MethodAnalyzer(); |
|
201 |
|
202 // Forward the SAM method |
227 // Forward the SAM method |
203 if (ma.getSamMethod() == null) { |
228 String methodDescriptor = samMethodType.toMethodDescriptorString(); |
204 throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType)); |
229 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null); |
205 } else { |
230 new ForwardingMethodGenerator(mv).generate(methodDescriptor); |
206 generateForwardingMethod(ma.getSamMethod(), false); |
|
207 } |
|
208 |
231 |
209 // Forward the bridges |
232 // Forward the bridges |
210 // @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request |
233 if (additionalBridges != null) { |
211 // @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate |
234 for (MethodType mt : additionalBridges) { |
212 // @@@ classfile attribute to request custom bridging. See 8002092. |
235 methodDescriptor = mt.toMethodDescriptorString(); |
213 if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) { |
236 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null); |
214 for (Method m : ma.getMethodsToBridge()) { |
237 new ForwardingMethodGenerator(mv).generate(methodDescriptor); |
215 generateForwardingMethod(m, true); |
238 } |
216 } |
239 } |
217 } |
240 |
218 |
241 if (isSerializable) |
219 if (isSerializable) { |
|
220 generateWriteReplace(); |
242 generateWriteReplace(); |
221 } |
|
222 |
243 |
223 cw.visitEnd(); |
244 cw.visitEnd(); |
224 |
245 |
225 // Define the generated class in this VM. |
246 // Define the generated class in this VM. |
226 |
247 |
311 mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
333 mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
312 mv.visitEnd(); |
334 mv.visitEnd(); |
313 } |
335 } |
314 |
336 |
315 /** |
337 /** |
316 * Generate a method which calls the lambda implementation method, |
|
317 * converting arguments, as needed. |
|
318 * @param m The method whose signature should be generated |
|
319 * @param isBridge True if this methods should be flagged as a bridge |
|
320 */ |
|
321 private void generateForwardingMethod(Method m, boolean isBridge) { |
|
322 Class<?>[] exceptionTypes = m.getExceptionTypes(); |
|
323 String[] exceptionNames = new String[exceptionTypes.length]; |
|
324 for (int i = 0; i < exceptionTypes.length; i++) { |
|
325 exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/'); |
|
326 } |
|
327 String methodDescriptor = Type.getMethodDescriptor(m); |
|
328 int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC; |
|
329 MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames); |
|
330 new ForwardingMethodGenerator(mv).generate(m); |
|
331 } |
|
332 |
|
333 /** |
|
334 * This class generates a method body which calls the lambda implementation |
338 * This class generates a method body which calls the lambda implementation |
335 * method, converting arguments, as needed. |
339 * method, converting arguments, as needed. |
336 */ |
340 */ |
337 private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter { |
341 private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter { |
338 |
342 |
339 ForwardingMethodGenerator(MethodVisitor mv) { |
343 ForwardingMethodGenerator(MethodVisitor mv) { |
340 super(mv); |
344 super(mv); |
341 } |
345 } |
342 |
346 |
343 void generate(Method m) throws InternalError { |
347 void generate(String methodDescriptor) { |
344 visitCode(); |
348 visitCode(); |
345 |
349 |
346 if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { |
350 if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { |
347 visitTypeInsn(NEW, implMethodClassName); |
351 visitTypeInsn(NEW, implMethodClassName); |
348 visitInsn(DUP);; |
352 visitInsn(DUP); |
349 } |
353 } |
350 for (int i = 0; i < argTypes.length; i++) { |
354 for (int i = 0; i < argTypes.length; i++) { |
351 visitVarInsn(ALOAD, 0); |
355 visitVarInsn(ALOAD, 0); |
352 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); |
356 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); |
353 } |
357 } |
354 |
358 |
355 convertArgumentTypes(Type.getArgumentTypes(m)); |
359 convertArgumentTypes(Type.getArgumentTypes(methodDescriptor)); |
356 |
360 |
357 // Invoke the method we want to forward to |
361 // Invoke the method we want to forward to |
358 visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); |
362 visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); |
359 |
363 |
360 // Convert the return value (if any) and return it |
364 // Convert the return value (if any) and return it |
361 // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result |
365 // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result |
362 Type samReturnType = Type.getReturnType(m); |
366 Type samReturnType = Type.getReturnType(methodDescriptor); |
363 convertType(implMethodReturnType, samReturnType, samReturnType); |
367 convertType(implMethodReturnType, samReturnType, samReturnType); |
364 visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); |
368 visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); |
365 |
369 |
366 visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
370 visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored |
367 visitEnd(); |
371 visitEnd(); |