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