8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.CDS;
29 import jdk.internal.org.objectweb.asm.*;
30 import jdk.internal.util.ClassFileDumper;
31 import sun.invoke.util.BytecodeDescriptor;
32 import sun.invoke.util.VerifyAccess;
33 import sun.security.action.GetBooleanAction;
34
35 import java.io.Serializable;
36 import java.lang.constant.ConstantDescs;
37 import java.lang.reflect.Modifier;
38 import java.util.LinkedHashSet;
39 import java.util.Set;
40
41 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
42 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
43 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
44 import static java.lang.invoke.MethodType.methodType;
45 import static jdk.internal.org.objectweb.asm.Opcodes.*;
46
47 /**
48 * Lambda metafactory implementation which dynamically creates an
49 * inner-class-like class per lambda callsite.
50 *
51 * @see LambdaMetafactory
52 */
53 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
54 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
55 private static final String JAVA_LANG_OBJECT = "java/lang/Object";
56 private static final String NAME_CTOR = "<init>";
57 private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
297 * @throws LambdaConversionException If properly formed functional interface
298 * is not found
299 */
300 private Class<?> generateInnerClass() throws LambdaConversionException {
301 String[] interfaceNames;
302 String interfaceName = interfaceClass.getName().replace('.', '/');
303 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
304 if (altInterfaces.length == 0) {
305 interfaceNames = new String[]{interfaceName};
306 } else {
307 // Assure no duplicate interfaces (ClassFormatError)
308 Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
309 itfs.add(interfaceName);
310 for (Class<?> i : altInterfaces) {
311 itfs.add(i.getName().replace('.', '/'));
312 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
313 }
314 interfaceNames = itfs.toArray(new String[itfs.size()]);
315 }
316
317 cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
318 lambdaClassName, null,
319 JAVA_LANG_OBJECT, interfaceNames);
320
321 // Generate final fields to be filled in by constructor
322 for (int i = 0; i < argDescs.length; i++) {
323 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
324 argNames[i],
325 argDescs[i],
326 null, null);
327 fv.visitEnd();
328 }
329
330 generateConstructor();
331
332 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
333 generateClassInitializer();
334 }
335
336 // Forward the SAM method
337 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
338 interfaceMethodType.toMethodDescriptorString(), null, null);
339 new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
340
341 // Forward the altMethods
342 if (altMethods != null) {
343 for (MethodType mt : altMethods) {
344 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
345 mt.toMethodDescriptorString(), null, null);
346 new ForwardingMethodGenerator(mv).generate(mt);
347 }
348 }
349
350 if (isSerializable)
351 generateSerializationFriendlyMethods();
352 else if (accidentallySerializable)
353 generateSerializationHostileMethods();
354
355 cw.visitEnd();
356
357 // Define the generated class in this VM.
358
359 final byte[] classBytes = cw.toByteArray();
360 try {
361 // this class is linked at the indy callsite; so define a hidden nestmate
362 var classdata = useImplMethodHandle? implementation : null;
363 return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
364 .defineClass(!disableEagerInitialization, classdata);
365
366 } catch (Throwable t) {
367 throw new InternalError(t);
368 }
369 }
370
371 /**
372 * Generate a static field and a static initializer that sets this field to an instance of the lambda
373 */
374 private void generateClassInitializer() {
549 for (int i = 0; i < samParametersLength; i++) {
550 Class<?> argType = samType.parameterType(i);
551 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
552 lvIndex += getParameterSize(argType);
553 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
554 }
555 }
556
557 private int invocationOpcode() throws InternalError {
558 return switch (implKind) {
559 case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
560 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
561 case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
562 case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
563 case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
564 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
565 };
566 }
567 }
568
569 static int getParameterSize(Class<?> c) {
570 if (c == Void.TYPE) {
571 return 0;
572 } else if (c == Long.TYPE || c == Double.TYPE) {
573 return 2;
574 }
575 return 1;
576 }
577
578 static int getLoadOpcode(Class<?> c) {
579 if(c == Void.TYPE) {
580 throw new InternalError("Unexpected void type of load opcode");
581 }
582 return ILOAD + getOpcodeOffset(c);
583 }
584
585 static int getReturnOpcode(Class<?> c) {
586 if(c == Void.TYPE) {
587 return RETURN;
588 }
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.PreviewFeatures;
29 import jdk.internal.misc.CDS;
30 import jdk.internal.org.objectweb.asm.*;
31 import jdk.internal.util.ClassFileDumper;
32 import sun.invoke.util.BytecodeDescriptor;
33 import sun.invoke.util.VerifyAccess;
34 import sun.security.action.GetBooleanAction;
35
36 import java.io.Serializable;
37 import java.lang.constant.ConstantDescs;
38 import java.lang.reflect.Modifier;
39 import java.util.HashSet;
40 import java.util.LinkedHashSet;
41 import java.util.Set;
42
43 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
44 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
45 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
46 import static java.lang.invoke.MethodType.methodType;
47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
48
49 /**
50 * Lambda metafactory implementation which dynamically creates an
51 * inner-class-like class per lambda callsite.
52 *
53 * @see LambdaMetafactory
54 */
55 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
56 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
57 private static final String JAVA_LANG_OBJECT = "java/lang/Object";
58 private static final String NAME_CTOR = "<init>";
59 private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
299 * @throws LambdaConversionException If properly formed functional interface
300 * is not found
301 */
302 private Class<?> generateInnerClass() throws LambdaConversionException {
303 String[] interfaceNames;
304 String interfaceName = interfaceClass.getName().replace('.', '/');
305 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
306 if (altInterfaces.length == 0) {
307 interfaceNames = new String[]{interfaceName};
308 } else {
309 // Assure no duplicate interfaces (ClassFormatError)
310 Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
311 itfs.add(interfaceName);
312 for (Class<?> i : altInterfaces) {
313 itfs.add(i.getName().replace('.', '/'));
314 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
315 }
316 interfaceNames = itfs.toArray(new String[itfs.size()]);
317 }
318
319 int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
320 cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
321 lambdaClassName, null,
322 JAVA_LANG_OBJECT, interfaceNames);
323
324 // Generate final fields to be filled in by constructor
325 for (int i = 0; i < argDescs.length; i++) {
326 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
327 argNames[i],
328 argDescs[i],
329 null, null);
330 fv.visitEnd();
331 }
332
333 generateConstructor();
334
335 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
336 generateClassInitializer();
337 }
338
339 // Forward the SAM method
340 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
341 interfaceMethodType.toMethodDescriptorString(), null, null);
342 new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
343
344 // Forward the altMethods
345 if (altMethods != null) {
346 for (MethodType mt : altMethods) {
347 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
348 mt.toMethodDescriptorString(), null, null);
349 new ForwardingMethodGenerator(mv).generate(mt);
350 }
351 }
352
353 if (isSerializable)
354 generateSerializationFriendlyMethods();
355 else if (accidentallySerializable)
356 generateSerializationHostileMethods();
357
358 // generate Preload attribute if it references any value class
359 PreloadAttributeBuilder builder = new PreloadAttributeBuilder(targetClass);
360 builder.add(factoryType)
361 .add(interfaceMethodType)
362 .add(implMethodType)
363 .add(dynamicMethodType)
364 .add(altMethods);
365 if (!builder.isEmpty())
366 cw.visitAttribute(builder.build());
367
368 cw.visitEnd();
369
370 // Define the generated class in this VM.
371
372 final byte[] classBytes = cw.toByteArray();
373 try {
374 // this class is linked at the indy callsite; so define a hidden nestmate
375 var classdata = useImplMethodHandle? implementation : null;
376 return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
377 .defineClass(!disableEagerInitialization, classdata);
378
379 } catch (Throwable t) {
380 throw new InternalError(t);
381 }
382 }
383
384 /**
385 * Generate a static field and a static initializer that sets this field to an instance of the lambda
386 */
387 private void generateClassInitializer() {
562 for (int i = 0; i < samParametersLength; i++) {
563 Class<?> argType = samType.parameterType(i);
564 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
565 lvIndex += getParameterSize(argType);
566 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
567 }
568 }
569
570 private int invocationOpcode() throws InternalError {
571 return switch (implKind) {
572 case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
573 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
574 case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
575 case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
576 case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
577 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
578 };
579 }
580 }
581
582 /*
583 * Preload attribute builder
584 */
585 static class PreloadAttributeBuilder {
586 private final Set<Class<?>> preloadClasses = new HashSet<>();
587 PreloadAttributeBuilder(Class<?> targetClass) {
588 if (requiresPreload(targetClass)) {
589 preloadClasses.add(targetClass);
590 }
591 }
592
593 /*
594 * Add the value types referenced in the given MethodType.
595 */
596 PreloadAttributeBuilder add(MethodType mt) {
597 // parameter types
598 for (Class<?> paramType : mt.ptypes()) {
599 if (requiresPreload(paramType)) {
600 preloadClasses.add(paramType);
601 }
602 }
603 // return type
604 if (requiresPreload(mt.returnType())) {
605 preloadClasses.add(mt.returnType());
606 }
607 return this;
608 }
609
610 PreloadAttributeBuilder add(MethodType... mtypes) {
611 for (MethodType mt : mtypes) {
612 add(mt);
613 }
614 return this;
615 }
616
617 boolean requiresPreload(Class<?> cls) {
618 Class<?> c = cls;
619 while (c.isArray()) {
620 c = c.getComponentType();
621 }
622 return c.isValue();
623 }
624
625 boolean isEmpty() {
626 return preloadClasses.isEmpty();
627 }
628
629 Attribute build() {
630 return new Attribute("Preload") {
631 @Override
632 protected ByteVector write(ClassWriter cw,
633 byte[] code,
634 int len,
635 int maxStack,
636 int maxLocals) {
637 ByteVector attr = new ByteVector();
638 attr.putShort(preloadClasses.size());
639 for (Class<?> c : preloadClasses) {
640 attr.putShort(cw.newClass(Type.getInternalName(c)));
641 }
642 return attr;
643 }
644 };
645 }
646 }
647
648 static int getParameterSize(Class<?> c) {
649 if (c == Void.TYPE) {
650 return 0;
651 } else if (c == Long.TYPE || c == Double.TYPE) {
652 return 2;
653 }
654 return 1;
655 }
656
657 static int getLoadOpcode(Class<?> c) {
658 if(c == Void.TYPE) {
659 throw new InternalError("Unexpected void type of load opcode");
660 }
661 return ILOAD + getOpcodeOffset(c);
662 }
663
664 static int getReturnOpcode(Class<?> c) {
665 if(c == Void.TYPE) {
666 return RETURN;
667 }
|