32 import java.security.AccessController;
33 import java.security.PrivilegedAction;
34 import java.security.ProtectionDomain;
35 import java.util.concurrent.atomic.AtomicInteger;
36
37 import static jdk.internal.org.objectweb.asm.Opcodes.*;
38
39 /**
40 * Lambda metafactory implementation which dynamically creates an
41 * inner-class-like class per lambda callsite.
42 *
43 * @see LambdaMetafactory
44 */
45 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
46 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
47
48 private static final int CLASSFILE_VERSION = 51;
49 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
50 private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
51 private static final String NAME_CTOR = "<init>";
52
53 //Serialization support
54 private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
55 private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
56 private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
57 private static final String NAME_OBJECT = "java/lang/Object";
58 private static final String DESCR_CTOR_SERIALIZED_LAMBDA
59 = MethodType.methodType(void.class,
60 Class.class,
61 String.class, String.class, String.class,
62 int.class, String.class, String.class, String.class,
63 String.class,
64 Object[].class).toMethodDescriptorString();
65
66 // Used to ensure that each spun class name is unique
67 private static final AtomicInteger counter = new AtomicInteger(0);
68
69 // See context values in AbstractValidatingLambdaMetafactory
70 private final String implMethodClassName; // Name of type containing implementation "CC"
71 private final String implMethodName; // Name of implementation method "impl"
175 return innerClass.getDeclaredConstructors();
176 }
177 });
178 if (ctrs.length != 1) {
179 throw new ReflectiveOperationException("Expected one lambda constructor for "
180 + innerClass.getCanonicalName() + ", got " + ctrs.length);
181 }
182 // The lambda implementing inner class constructor is private, set
183 // it accessible (by us) before creating the constant sole instance
184 AccessController.doPrivileged(new PrivilegedAction<Void>() {
185 @Override
186 public Void run() {
187 ctrs[0].setAccessible(true);
188 return null;
189 }
190 });
191 Object inst = ctrs[0].newInstance();
192 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
193 } else {
194 return new ConstantCallSite(
195 MethodHandles.Lookup.IMPL_LOOKUP
196 .findConstructor(innerClass, constructorType)
197 .asType(constructorType.changeReturnType(samBase)));
198 }
199 }
200
201 /**
202 * Generate a class file which implements the functional
203 * interface, define and return the class.
204 *
205 * @implNote The class that is generated does not include signature
206 * information for exceptions that may be present on the SAM method.
207 * This is to reduce classfile size, and is harmless as checked exceptions
208 * are erased anyway, no one will ever compile against this classfile,
209 * and we make no guarantees about the reflective properties of lambda
210 * objects.
211 *
212 * @return a Class which implements the functional interface
213 * @throws LambdaConversionException If properly formed functional interface
214 * is not found
215 */
216 private Class<?> spinInnerClass() throws LambdaConversionException {
217 String[] interfaces = new String[markerInterfaces.length + 1];
218 interfaces[0] = samBase.getName().replace('.', '/');
219 for (int i=0; i<markerInterfaces.length; i++) {
220 interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
221 }
222 cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
223 lambdaClassName, null,
224 NAME_MAGIC_ACCESSOR_IMPL, interfaces);
225
226 // Generate final fields to be filled in by constructor
227 for (int i = 0; i < argTypes.length; i++) {
228 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
229 argNames[i],
230 argTypes[i].getDescriptor(),
231 null, null);
232 fv.visitEnd();
233 }
234
235 generateConstructor();
236
237 // Forward the SAM method
238 String methodDescriptor = samMethodType.toMethodDescriptorString();
239 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
240 methodDescriptor, null, null);
241 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
242
243 // Forward the bridges
244 if (additionalBridges != null) {
245 for (MethodType mt : additionalBridges) {
246 methodDescriptor = mt.toMethodDescriptorString();
247 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
248 methodDescriptor, null, null);
249 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
250 }
251 }
252
253 if (isSerializable)
254 generateWriteReplace();
255
256 cw.visitEnd();
269 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class
270 .getName()).severe(ex.getMessage(), ex);
271 }
272 ***/
273
274 ClassLoader loader = targetClass.getClassLoader();
275 ProtectionDomain pd = (loader == null)
276 ? null
277 : AccessController.doPrivileged(
278 new PrivilegedAction<ProtectionDomain>() {
279 @Override
280 public ProtectionDomain run() {
281 return targetClass.getProtectionDomain();
282 }
283 }
284 );
285
286 return UNSAFE.defineClass(lambdaClassName,
287 classBytes, 0, classBytes.length,
288 loader, pd);
289 }
290
291 /**
292 * Generate the constructor for the class
293 */
294 private void generateConstructor() {
295 // Generate constructor
296 MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
297 constructorDesc, null, null);
298 ctor.visitCode();
299 ctor.visitVarInsn(ALOAD, 0);
300 ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR,
301 METHOD_DESCRIPTOR_VOID);
302 int lvIndex = 0;
303 for (int i = 0; i < argTypes.length; i++) {
304 ctor.visitVarInsn(ALOAD, 0);
305 ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
306 lvIndex += argTypes[i].getSize();
307 ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
308 argTypes[i].getDescriptor());
|
32 import java.security.AccessController;
33 import java.security.PrivilegedAction;
34 import java.security.ProtectionDomain;
35 import java.util.concurrent.atomic.AtomicInteger;
36
37 import static jdk.internal.org.objectweb.asm.Opcodes.*;
38
39 /**
40 * Lambda metafactory implementation which dynamically creates an
41 * inner-class-like class per lambda callsite.
42 *
43 * @see LambdaMetafactory
44 */
45 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
46 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
47
48 private static final int CLASSFILE_VERSION = 51;
49 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
50 private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
51 private static final String NAME_CTOR = "<init>";
52 private static final String NAME_FACTORY = "get$Lambda";
53
54 //Serialization support
55 private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
56 private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
57 private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
58 private static final String NAME_OBJECT = "java/lang/Object";
59 private static final String DESCR_CTOR_SERIALIZED_LAMBDA
60 = MethodType.methodType(void.class,
61 Class.class,
62 String.class, String.class, String.class,
63 int.class, String.class, String.class, String.class,
64 String.class,
65 Object[].class).toMethodDescriptorString();
66
67 // Used to ensure that each spun class name is unique
68 private static final AtomicInteger counter = new AtomicInteger(0);
69
70 // See context values in AbstractValidatingLambdaMetafactory
71 private final String implMethodClassName; // Name of type containing implementation "CC"
72 private final String implMethodName; // Name of implementation method "impl"
176 return innerClass.getDeclaredConstructors();
177 }
178 });
179 if (ctrs.length != 1) {
180 throw new ReflectiveOperationException("Expected one lambda constructor for "
181 + innerClass.getCanonicalName() + ", got " + ctrs.length);
182 }
183 // The lambda implementing inner class constructor is private, set
184 // it accessible (by us) before creating the constant sole instance
185 AccessController.doPrivileged(new PrivilegedAction<Void>() {
186 @Override
187 public Void run() {
188 ctrs[0].setAccessible(true);
189 return null;
190 }
191 });
192 Object inst = ctrs[0].newInstance();
193 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
194 } else {
195 return new ConstantCallSite(
196 MethodHandles.Lookup.IMPL_LOOKUP.findStatic(innerClass, NAME_FACTORY, invokedType));
197 }
198 }
199
200 /**
201 * Generate a class file which implements the functional
202 * interface, define and return the class.
203 *
204 * @implNote The class that is generated does not include signature
205 * information for exceptions that may be present on the SAM method.
206 * This is to reduce classfile size, and is harmless as checked exceptions
207 * are erased anyway, no one will ever compile against this classfile,
208 * and we make no guarantees about the reflective properties of lambda
209 * objects.
210 *
211 * @return a Class which implements the functional interface
212 * @throws LambdaConversionException If properly formed functional interface
213 * is not found
214 */
215 private Class<?> spinInnerClass() throws LambdaConversionException {
216 String[] interfaces = new String[markerInterfaces.length + 1];
217 interfaces[0] = samBase.getName().replace('.', '/');
218 for (int i=0; i<markerInterfaces.length; i++) {
219 interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
220 }
221 cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
222 lambdaClassName, null,
223 NAME_MAGIC_ACCESSOR_IMPL, interfaces);
224
225 // Generate final fields to be filled in by constructor
226 for (int i = 0; i < argTypes.length; i++) {
227 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
228 argNames[i],
229 argTypes[i].getDescriptor(),
230 null, null);
231 fv.visitEnd();
232 }
233
234 generateConstructor();
235
236 if (invokedType.parameterCount() != 0) {
237 generateFactory();
238 }
239
240 // Forward the SAM method
241 String methodDescriptor = samMethodType.toMethodDescriptorString();
242 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
243 methodDescriptor, null, null);
244 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
245
246 // Forward the bridges
247 if (additionalBridges != null) {
248 for (MethodType mt : additionalBridges) {
249 methodDescriptor = mt.toMethodDescriptorString();
250 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
251 methodDescriptor, null, null);
252 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
253 }
254 }
255
256 if (isSerializable)
257 generateWriteReplace();
258
259 cw.visitEnd();
272 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class
273 .getName()).severe(ex.getMessage(), ex);
274 }
275 ***/
276
277 ClassLoader loader = targetClass.getClassLoader();
278 ProtectionDomain pd = (loader == null)
279 ? null
280 : AccessController.doPrivileged(
281 new PrivilegedAction<ProtectionDomain>() {
282 @Override
283 public ProtectionDomain run() {
284 return targetClass.getProtectionDomain();
285 }
286 }
287 );
288
289 return UNSAFE.defineClass(lambdaClassName,
290 classBytes, 0, classBytes.length,
291 loader, pd);
292 }
293
294 /**
295 * Generate the factory method for the class
296 */
297 private void generateFactory() {
298 MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
299 m.visitCode();
300 m.visitTypeInsn(NEW, lambdaClassName);
301 m.visitInsn(Opcodes.DUP);
302 for (int typeIndex = 0, varIndex = 0; typeIndex < argTypes.length; typeIndex++) {
303 m.visitVarInsn(argTypes[typeIndex].getOpcode(ILOAD), varIndex);
304 varIndex += argTypes[typeIndex].getSize();
305 }
306 m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorDesc);
307 m.visitInsn(ARETURN);
308 m.visitMaxs(-1, -1);
309 m.visitEnd();
310 }
311
312 /**
313 * Generate the constructor for the class
314 */
315 private void generateConstructor() {
316 // Generate constructor
317 MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
318 constructorDesc, null, null);
319 ctor.visitCode();
320 ctor.visitVarInsn(ALOAD, 0);
321 ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR,
322 METHOD_DESCRIPTOR_VOID);
323 int lvIndex = 0;
324 for (int i = 0; i < argTypes.length; i++) {
325 ctor.visitVarInsn(ALOAD, 0);
326 ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
327 lvIndex += argTypes[i].getSize();
328 ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
329 argTypes[i].getDescriptor());
|