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.util.ClassFileDumper;
30 import sun.invoke.util.VerifyAccess;
31 import sun.security.action.GetBooleanAction;
32
33 import java.io.Serializable;
34 import java.lang.classfile.ClassBuilder;
35 import java.lang.classfile.ClassFile;
36 import java.lang.classfile.CodeBuilder;
37 import java.lang.classfile.MethodBuilder;
38 import java.lang.classfile.Opcode;
39 import java.lang.classfile.TypeKind;
40 import java.lang.constant.ClassDesc;
41 import java.lang.constant.MethodTypeDesc;
42 import java.lang.reflect.Modifier;
43 import java.util.LinkedHashSet;
44 import java.util.List;
45 import java.util.Set;
46 import java.util.function.Consumer;
47
48 import static java.lang.classfile.ClassFile.*;
49 import java.lang.classfile.attribute.ExceptionsAttribute;
50 import java.lang.classfile.constantpool.ClassEntry;
51 import java.lang.classfile.constantpool.ConstantPoolBuilder;
52
53 import static java.lang.constant.ConstantDescs.*;
54 import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
55 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
56 import static java.lang.invoke.MethodType.methodType;
57 import jdk.internal.constant.ConstantUtils;
58 import jdk.internal.constant.MethodTypeDescImpl;
59 import jdk.internal.constant.ReferenceClassDescImpl;
60 import jdk.internal.vm.annotation.Stable;
61 import sun.invoke.util.Wrapper;
62
63 /**
64 * Lambda metafactory implementation which dynamically creates an
65 * inner-class-like class per lambda callsite.
66 *
67 * @see LambdaMetafactory
68 */
69 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
70 private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
71 private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"};
294 private Class<?> generateInnerClass() throws LambdaConversionException {
295 List<ClassDesc> interfaces;
296 ClassDesc interfaceDesc = classDesc(interfaceClass);
297 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
298 if (altInterfaces.length == 0) {
299 interfaces = List.of(interfaceDesc);
300 } else {
301 // Assure no duplicate interfaces (ClassFormatError)
302 Set<ClassDesc> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
303 itfs.add(interfaceDesc);
304 for (Class<?> i : altInterfaces) {
305 itfs.add(classDesc(i));
306 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
307 }
308 interfaces = List.copyOf(itfs);
309 }
310 final boolean finalAccidentallySerializable = accidentallySerializable;
311 final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer<ClassBuilder>() {
312 @Override
313 public void accept(ClassBuilder clb) {
314 clb.withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC)
315 .withInterfaceSymbols(interfaces);
316 // Generate final fields to be filled in by constructor
317 for (int i = 0; i < argDescs.length; i++) {
318 clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL);
319 }
320
321 generateConstructor(clb);
322
323 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
324 generateClassInitializer(clb);
325 }
326
327 // Forward the SAM method
328 clb.withMethodBody(interfaceMethodName,
329 methodDesc(interfaceMethodType),
330 ACC_PUBLIC,
331 forwardingMethod(interfaceMethodType));
332
333 // Forward the bridges
334 if (altMethods != null) {
335 for (MethodType mt : altMethods) {
528 // Note: if adapting from non-void to void, the 'return'
529 // instruction will pop the unneeded result
530 Class<?> implReturnClass = implMethodType.returnType();
531 Class<?> samReturnClass = methodType.returnType();
532 TypeConvertingMethodAdapter.convertType(cob, implReturnClass, samReturnClass, samReturnClass);
533 cob.return_(TypeKind.from(samReturnClass));
534 }
535 };
536 }
537
538 private void convertArgumentTypes(CodeBuilder cob, MethodType samType) {
539 int samParametersLength = samType.parameterCount();
540 int captureArity = factoryType.parameterCount();
541 for (int i = 0; i < samParametersLength; i++) {
542 Class<?> argType = samType.parameterType(i);
543 cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
544 TypeConvertingMethodAdapter.convertType(cob, argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
545 }
546 }
547
548 private Opcode invocationOpcode() throws InternalError {
549 return switch (implKind) {
550 case MethodHandleInfo.REF_invokeStatic -> Opcode.INVOKESTATIC;
551 case MethodHandleInfo.REF_newInvokeSpecial -> Opcode.INVOKESPECIAL;
552 case MethodHandleInfo.REF_invokeVirtual -> Opcode.INVOKEVIRTUAL;
553 case MethodHandleInfo.REF_invokeInterface -> Opcode.INVOKEINTERFACE;
554 case MethodHandleInfo.REF_invokeSpecial -> Opcode.INVOKESPECIAL;
555 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
556 };
557 }
558
559 static ClassDesc implClassDesc(Class<?> cls) {
560 return cls.isHidden() ? null : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
561 }
562
563 static ClassDesc classDesc(Class<?> cls) {
564 return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
565 : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
566 }
567
|
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.util.ClassFileDumper;
31 import sun.invoke.util.VerifyAccess;
32 import sun.security.action.GetBooleanAction;
33
34 import java.io.Serializable;
35 import java.lang.classfile.ClassBuilder;
36 import java.lang.classfile.ClassFile;
37 import java.lang.classfile.CodeBuilder;
38 import java.lang.classfile.MethodBuilder;
39 import java.lang.classfile.Opcode;
40 import java.lang.classfile.TypeKind;
41
42 import java.lang.constant.ClassDesc;
43 import java.lang.constant.ConstantDescs;
44 import java.lang.constant.MethodTypeDesc;
45 import java.lang.reflect.AccessFlag;
46 import java.lang.reflect.ClassFileFormatVersion;
47 import java.lang.reflect.Modifier;
48 import java.util.ArrayList;
49 import java.util.HashSet;
50 import java.util.LinkedHashSet;
51 import java.util.List;
52 import java.util.Set;
53 import java.util.function.Consumer;
54
55 import static java.lang.classfile.ClassFile.*;
56 import java.lang.classfile.attribute.ExceptionsAttribute;
57 import java.lang.classfile.attribute.LoadableDescriptorsAttribute;
58 import java.lang.classfile.constantpool.ClassEntry;
59 import java.lang.classfile.constantpool.ConstantPoolBuilder;
60 import java.lang.classfile.constantpool.Utf8Entry;
61
62 import static java.lang.constant.ConstantDescs.*;
63 import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
64 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
65 import static java.lang.invoke.MethodType.methodType;
66 import jdk.internal.constant.ConstantUtils;
67 import jdk.internal.constant.MethodTypeDescImpl;
68 import jdk.internal.constant.ReferenceClassDescImpl;
69 import jdk.internal.vm.annotation.Stable;
70 import sun.invoke.util.Wrapper;
71
72 /**
73 * Lambda metafactory implementation which dynamically creates an
74 * inner-class-like class per lambda callsite.
75 *
76 * @see LambdaMetafactory
77 */
78 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
79 private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
80 private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"};
303 private Class<?> generateInnerClass() throws LambdaConversionException {
304 List<ClassDesc> interfaces;
305 ClassDesc interfaceDesc = classDesc(interfaceClass);
306 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
307 if (altInterfaces.length == 0) {
308 interfaces = List.of(interfaceDesc);
309 } else {
310 // Assure no duplicate interfaces (ClassFormatError)
311 Set<ClassDesc> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
312 itfs.add(interfaceDesc);
313 for (Class<?> i : altInterfaces) {
314 itfs.add(classDesc(i));
315 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
316 }
317 interfaces = List.copyOf(itfs);
318 }
319 final boolean finalAccidentallySerializable = accidentallySerializable;
320 final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer<ClassBuilder>() {
321 @Override
322 public void accept(ClassBuilder clb) {
323 clb.withVersion(ClassFileFormatVersion.latest().major(), (PreviewFeatures.isEnabled() ? 0xFFFF0000 : 0))
324 .withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC)
325 .withInterfaceSymbols(interfaces);
326
327 // generate LoadableDescriptors attribute if it references any value class
328 if (PreviewFeatures.isEnabled()) {
329 generateLoadableDescriptors(clb);
330 }
331
332 // Generate final fields to be filled in by constructor
333 for (int i = 0; i < argDescs.length; i++) {
334 clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL);
335 }
336
337 generateConstructor(clb);
338
339 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
340 generateClassInitializer(clb);
341 }
342
343 // Forward the SAM method
344 clb.withMethodBody(interfaceMethodName,
345 methodDesc(interfaceMethodType),
346 ACC_PUBLIC,
347 forwardingMethod(interfaceMethodType));
348
349 // Forward the bridges
350 if (altMethods != null) {
351 for (MethodType mt : altMethods) {
544 // Note: if adapting from non-void to void, the 'return'
545 // instruction will pop the unneeded result
546 Class<?> implReturnClass = implMethodType.returnType();
547 Class<?> samReturnClass = methodType.returnType();
548 TypeConvertingMethodAdapter.convertType(cob, implReturnClass, samReturnClass, samReturnClass);
549 cob.return_(TypeKind.from(samReturnClass));
550 }
551 };
552 }
553
554 private void convertArgumentTypes(CodeBuilder cob, MethodType samType) {
555 int samParametersLength = samType.parameterCount();
556 int captureArity = factoryType.parameterCount();
557 for (int i = 0; i < samParametersLength; i++) {
558 Class<?> argType = samType.parameterType(i);
559 cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
560 TypeConvertingMethodAdapter.convertType(cob, argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
561 }
562 }
563
564 /*
565 * LoadableDescriptors attribute builder
566 */
567 static class LoadableDescriptorsAttributeBuilder {
568 private final Set<String> loadableDescriptors = new HashSet<>();
569 LoadableDescriptorsAttributeBuilder(Class<?> targetClass) {
570 if (requiresLoadableDescriptors(targetClass)) {
571 loadableDescriptors.add(targetClass.descriptorString());
572 }
573 }
574
575 /*
576 * Add the value types referenced in the given MethodType.
577 */
578 LoadableDescriptorsAttributeBuilder add(MethodType mt) {
579 // parameter types
580 for (Class<?> paramType : mt.ptypes()) {
581 if (requiresLoadableDescriptors(paramType)) {
582 loadableDescriptors.add(paramType.descriptorString());
583 }
584 }
585 // return type
586 if (requiresLoadableDescriptors(mt.returnType())) {
587 loadableDescriptors.add(mt.returnType().descriptorString());
588 }
589 return this;
590 }
591
592 LoadableDescriptorsAttributeBuilder add(MethodType... mtypes) {
593 for (MethodType mt : mtypes) {
594 add(mt);
595 }
596 return this;
597 }
598
599 boolean requiresLoadableDescriptors(Class<?> cls) {
600 return cls.isValue() && cls.accessFlags().contains(AccessFlag.FINAL);
601 }
602
603 boolean isEmpty() {
604 return loadableDescriptors.isEmpty();
605 }
606
607 void build(ClassBuilder clb) {
608 if (!isEmpty()) {
609 List<Utf8Entry> lds = new ArrayList<Utf8Entry>(loadableDescriptors.size());
610 for (String ld : loadableDescriptors) {
611 lds.add(clb.constantPool().utf8Entry(ld));
612 }
613 clb.with(LoadableDescriptorsAttribute.of(lds));
614 }
615 }
616 }
617
618 /**
619 * Generate LoadableDescriptors attribute if it references any value class
620 */
621 private void generateLoadableDescriptors(ClassBuilder clb) {
622 LoadableDescriptorsAttributeBuilder builder = new LoadableDescriptorsAttributeBuilder(targetClass);
623 builder.add(factoryType)
624 .add(interfaceMethodType)
625 .add(implMethodType)
626 .add(dynamicMethodType)
627 .add(altMethods)
628 .build(clb);
629 }
630
631 private Opcode invocationOpcode() throws InternalError {
632 return switch (implKind) {
633 case MethodHandleInfo.REF_invokeStatic -> Opcode.INVOKESTATIC;
634 case MethodHandleInfo.REF_newInvokeSpecial -> Opcode.INVOKESPECIAL;
635 case MethodHandleInfo.REF_invokeVirtual -> Opcode.INVOKEVIRTUAL;
636 case MethodHandleInfo.REF_invokeInterface -> Opcode.INVOKEINTERFACE;
637 case MethodHandleInfo.REF_invokeSpecial -> Opcode.INVOKESPECIAL;
638 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
639 };
640 }
641
642 static ClassDesc implClassDesc(Class<?> cls) {
643 return cls.isHidden() ? null : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
644 }
645
646 static ClassDesc classDesc(Class<?> cls) {
647 return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
648 : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
649 }
650
|