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.AccessFlag;
39 import java.lang.reflect.Modifier;
40 import java.util.HashSet;
41 import java.util.LinkedHashSet;
42 import java.util.Set;
43
44 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
45 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
46 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
47 import static java.lang.invoke.MethodType.methodType;
48 import static jdk.internal.org.objectweb.asm.Opcodes.*;
49
50 /**
51 * Lambda metafactory implementation which dynamically creates an
52 * inner-class-like class per lambda callsite.
53 *
54 * @see LambdaMetafactory
55 */
56 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
57 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
58 private static final String JAVA_LANG_OBJECT = "java/lang/Object";
59 private static final String NAME_CTOR = "<init>";
60 private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
300 * @throws LambdaConversionException If properly formed functional interface
301 * is not found
302 */
303 private Class<?> generateInnerClass() throws LambdaConversionException {
304 String[] interfaceNames;
305 String interfaceName = interfaceClass.getName().replace('.', '/');
306 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
307 if (altInterfaces.length == 0) {
308 interfaceNames = new String[]{interfaceName};
309 } else {
310 // Assure no duplicate interfaces (ClassFormatError)
311 Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
312 itfs.add(interfaceName);
313 for (Class<?> i : altInterfaces) {
314 itfs.add(i.getName().replace('.', '/'));
315 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
316 }
317 interfaceNames = itfs.toArray(new String[itfs.size()]);
318 }
319
320 int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
321 cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
322 lambdaClassName, null,
323 JAVA_LANG_OBJECT, interfaceNames);
324
325 // Generate final fields to be filled in by constructor
326 for (int i = 0; i < argDescs.length; i++) {
327 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
328 argNames[i],
329 argDescs[i],
330 null, null);
331 fv.visitEnd();
332 }
333
334 generateConstructor();
335
336 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
337 generateClassInitializer();
338 }
339
340 // Forward the SAM method
341 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
342 interfaceMethodType.toMethodDescriptorString(), null, null);
343 new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
344
345 // Forward the altMethods
346 if (altMethods != null) {
347 for (MethodType mt : altMethods) {
348 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
349 mt.toMethodDescriptorString(), null, null);
350 new ForwardingMethodGenerator(mv).generate(mt);
351 }
352 }
353
354 if (isSerializable)
355 generateSerializationFriendlyMethods();
356 else if (accidentallySerializable)
357 generateSerializationHostileMethods();
358
359 // generate LoadableDescriptors attribute if it references any value class
360 if (PreviewFeatures.isEnabled()) {
361 LoadableDescriptorsAttributeBuilder builder = new LoadableDescriptorsAttributeBuilder(targetClass);
362 builder.add(factoryType)
363 .add(interfaceMethodType)
364 .add(implMethodType)
365 .add(dynamicMethodType)
366 .add(altMethods);
367 if (!builder.isEmpty())
368 cw.visitAttribute(builder.build());
369 }
370
371 cw.visitEnd();
372
373 // Define the generated class in this VM.
374
375 final byte[] classBytes = cw.toByteArray();
376 try {
377 // this class is linked at the indy callsite; so define a hidden nestmate
378 var classdata = useImplMethodHandle? implementation : null;
379 return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
380 .defineClass(!disableEagerInitialization, classdata);
381
382 } catch (Throwable t) {
383 throw new InternalError(t);
384 }
385 }
386
387 /**
388 * Generate a static field and a static initializer that sets this field to an instance of the lambda
389 */
390 private void generateClassInitializer() {
565 for (int i = 0; i < samParametersLength; i++) {
566 Class<?> argType = samType.parameterType(i);
567 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
568 lvIndex += getParameterSize(argType);
569 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
570 }
571 }
572
573 private int invocationOpcode() throws InternalError {
574 return switch (implKind) {
575 case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
576 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
577 case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
578 case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
579 case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
580 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
581 };
582 }
583 }
584
585 /*
586 * LoadableDescriptors attribute builder
587 */
588 static class LoadableDescriptorsAttributeBuilder {
589 private final Set<String> loadableDescriptors = new HashSet<>();
590 LoadableDescriptorsAttributeBuilder(Class<?> targetClass) {
591 if (requiresLoadableDescriptors(targetClass)) {
592 loadableDescriptors.add(Type.getDescriptor(targetClass));
593 }
594 }
595
596 /*
597 * Add the value types referenced in the given MethodType.
598 */
599 LoadableDescriptorsAttributeBuilder add(MethodType mt) {
600 // parameter types
601 for (Class<?> paramType : mt.ptypes()) {
602 if (requiresLoadableDescriptors(paramType)) {
603 loadableDescriptors.add(Type.getDescriptor(paramType));
604 }
605 }
606 // return type
607 if (requiresLoadableDescriptors(mt.returnType())) {
608 loadableDescriptors.add(Type.getDescriptor(mt.returnType()));
609 }
610 return this;
611 }
612
613 LoadableDescriptorsAttributeBuilder add(MethodType... mtypes) {
614 for (MethodType mt : mtypes) {
615 add(mt);
616 }
617 return this;
618 }
619
620 boolean requiresLoadableDescriptors(Class<?> cls) {
621 return cls.isValue() && cls.accessFlags().contains(AccessFlag.FINAL);
622 }
623
624 boolean isEmpty() {
625 return loadableDescriptors.isEmpty();
626 }
627
628 Attribute build() {
629 return new Attribute("LoadableDescriptors") {
630 @Override
631 protected ByteVector write(ClassWriter cw,
632 byte[] code,
633 int len,
634 int maxStack,
635 int maxLocals) {
636 ByteVector attr = new ByteVector();
637 attr.putShort(loadableDescriptors.size());
638 for (String s : loadableDescriptors) {
639 attr.putShort(cw.newUTF8(s));
640 }
641 return attr;
642 }
643 };
644 }
645 }
646
647 static int getParameterSize(Class<?> c) {
648 if (c == Void.TYPE) {
649 return 0;
650 } else if (c == Long.TYPE || c == Double.TYPE) {
651 return 2;
652 }
653 return 1;
654 }
655
656 static int getLoadOpcode(Class<?> c) {
657 if(c == Void.TYPE) {
658 throw new InternalError("Unexpected void type of load opcode");
659 }
660 return ILOAD + getOpcodeOffset(c);
661 }
662
663 static int getReturnOpcode(Class<?> c) {
664 if(c == Void.TYPE) {
665 return RETURN;
666 }
|