< prev index next >

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java

Print this page

  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.constant.ClassOrInterfaceDescImpl;

 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 import java.lang.constant.ClassDesc;

 42 import java.lang.constant.MethodTypeDesc;


 43 import java.lang.reflect.Modifier;


 44 import java.util.LinkedHashSet;
 45 import java.util.List;
 46 import java.util.Set;
 47 import java.util.function.Consumer;
 48 
 49 import static java.lang.classfile.ClassFile.*;
 50 import java.lang.classfile.attribute.ExceptionsAttribute;

 51 import java.lang.classfile.constantpool.ClassEntry;
 52 import java.lang.classfile.constantpool.ConstantPoolBuilder;

 53 
 54 import static java.lang.constant.ConstantDescs.*;
 55 import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
 56 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
 57 import jdk.internal.constant.ConstantUtils;
 58 import jdk.internal.constant.MethodTypeDescImpl;
 59 import jdk.internal.vm.annotation.Stable;
 60 import sun.invoke.util.Wrapper;
 61 
 62 /**
 63  * Lambda metafactory implementation which dynamically creates an
 64  * inner-class-like class per lambda callsite.
 65  *
 66  * @see LambdaMetafactory
 67  */
 68 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 69     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
 70     private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"};
 71     private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC;
 72 

293     private Class<?> generateInnerClass() throws LambdaConversionException {
294         List<ClassDesc> interfaces;
295         ClassDesc interfaceDesc = classDesc(interfaceClass);
296         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
297         if (altInterfaces.length == 0) {
298             interfaces = List.of(interfaceDesc);
299         } else {
300             // Assure no duplicate interfaces (ClassFormatError)
301             Set<ClassDesc> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
302             itfs.add(interfaceDesc);
303             for (Class<?> i : altInterfaces) {
304                 itfs.add(classDesc(i));
305                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
306             }
307             interfaces = List.copyOf(itfs);
308         }
309         final boolean finalAccidentallySerializable = accidentallySerializable;
310         final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer<ClassBuilder>() {
311             @Override
312             public void accept(ClassBuilder clb) {
313                 clb.withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC)

314                    .withInterfaceSymbols(interfaces);






315                 // Generate final fields to be filled in by constructor
316                 for (int i = 0; i < argDescs.length; i++) {
317                     clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL);
318                 }
319 
320                 generateConstructor(clb);
321 
322                 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
323                     generateClassInitializer(clb);
324                 }
325 
326                 // Forward the SAM method
327                 clb.withMethodBody(interfaceMethodName,
328                         methodDesc(interfaceMethodType),
329                         ACC_PUBLIC,
330                         forwardingMethod(interfaceMethodType));
331 
332                 // Forward the bridges
333                 if (altMethods != null) {
334                     for (MethodType mt : altMethods) {

527                 // Note: if adapting from non-void to void, the 'return'
528                 // instruction will pop the unneeded result
529                 Class<?> implReturnClass = implMethodType.returnType();
530                 Class<?> samReturnClass = methodType.returnType();
531                 TypeConvertingMethodAdapter.convertType(cob, implReturnClass, samReturnClass, samReturnClass);
532                 cob.return_(TypeKind.from(samReturnClass));
533             }
534         };
535     }
536 
537     private void convertArgumentTypes(CodeBuilder cob, MethodType samType) {
538         int samParametersLength = samType.parameterCount();
539         int captureArity = factoryType.parameterCount();
540         for (int i = 0; i < samParametersLength; i++) {
541             Class<?> argType = samType.parameterType(i);
542             cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
543             TypeConvertingMethodAdapter.convertType(cob, argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
544         }
545     }
546 



































































547     private Opcode invocationOpcode() throws InternalError {
548         return switch (implKind) {
549             case MethodHandleInfo.REF_invokeStatic     -> Opcode.INVOKESTATIC;
550             case MethodHandleInfo.REF_newInvokeSpecial -> Opcode.INVOKESPECIAL;
551             case MethodHandleInfo.REF_invokeVirtual    -> Opcode.INVOKEVIRTUAL;
552             case MethodHandleInfo.REF_invokeInterface  -> Opcode.INVOKEINTERFACE;
553             case MethodHandleInfo.REF_invokeSpecial    -> Opcode.INVOKESPECIAL;
554             default -> throw new InternalError("Unexpected invocation kind: " + implKind);
555         };
556     }
557 
558     static ClassDesc implClassDesc(Class<?> cls) {
559         return cls.isHidden() ? null : ConstantUtils.referenceClassDesc(cls.descriptorString());
560     }
561 
562     static ClassDesc classDesc(Class<?> cls) {
563         return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
564                                  : ConstantUtils.referenceClassDesc(cls.descriptorString());
565     }
566 

  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.constant.ClassOrInterfaceDescImpl;
 29 import jdk.internal.misc.PreviewFeatures;
 30 import jdk.internal.misc.CDS;
 31 import jdk.internal.util.ClassFileDumper;
 32 import sun.invoke.util.VerifyAccess;
 33 import sun.security.action.GetBooleanAction;
 34 
 35 import java.io.Serializable;
 36 import java.lang.classfile.ClassBuilder;
 37 import java.lang.classfile.ClassFile;
 38 import java.lang.classfile.CodeBuilder;
 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.MethodTypeDesc;
 46 import java.lang.reflect.AccessFlag;
 47 import java.lang.reflect.ClassFileFormatVersion;
 48 import java.lang.reflect.Modifier;
 49 import java.util.ArrayList;
 50 import java.util.HashSet;
 51 import java.util.LinkedHashSet;
 52 import java.util.List;
 53 import java.util.Set;
 54 import java.util.function.Consumer;
 55 
 56 import static java.lang.classfile.ClassFile.*;
 57 import java.lang.classfile.attribute.ExceptionsAttribute;
 58 import java.lang.classfile.attribute.LoadableDescriptorsAttribute;
 59 import java.lang.classfile.constantpool.ClassEntry;
 60 import java.lang.classfile.constantpool.ConstantPoolBuilder;
 61 import java.lang.classfile.constantpool.Utf8Entry;
 62 
 63 import static java.lang.constant.ConstantDescs.*;
 64 import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
 65 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
 66 import jdk.internal.constant.ConstantUtils;
 67 import jdk.internal.constant.MethodTypeDescImpl;
 68 import jdk.internal.vm.annotation.Stable;
 69 import sun.invoke.util.Wrapper;
 70 
 71 /**
 72  * Lambda metafactory implementation which dynamically creates an
 73  * inner-class-like class per lambda callsite.
 74  *
 75  * @see LambdaMetafactory
 76  */
 77 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 78     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
 79     private static final @Stable String[] ARG_NAME_CACHE = {"arg$1", "arg$2", "arg$3", "arg$4", "arg$5", "arg$6", "arg$7", "arg$8"};
 80     private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC;
 81 

302     private Class<?> generateInnerClass() throws LambdaConversionException {
303         List<ClassDesc> interfaces;
304         ClassDesc interfaceDesc = classDesc(interfaceClass);
305         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
306         if (altInterfaces.length == 0) {
307             interfaces = List.of(interfaceDesc);
308         } else {
309             // Assure no duplicate interfaces (ClassFormatError)
310             Set<ClassDesc> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
311             itfs.add(interfaceDesc);
312             for (Class<?> i : altInterfaces) {
313                 itfs.add(classDesc(i));
314                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
315             }
316             interfaces = List.copyOf(itfs);
317         }
318         final boolean finalAccidentallySerializable = accidentallySerializable;
319         final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer<ClassBuilder>() {
320             @Override
321             public void accept(ClassBuilder clb) {
322                 clb.withVersion(ClassFileFormatVersion.latest().major(), (PreviewFeatures.isEnabled() ? 0xFFFF0000 : 0))
323                    .withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC)
324                    .withInterfaceSymbols(interfaces);
325 
326                 // generate LoadableDescriptors attribute if it references any value class
327                 if (PreviewFeatures.isEnabled()) {
328                     generateLoadableDescriptors(clb);
329                 }
330 
331                 // Generate final fields to be filled in by constructor
332                 for (int i = 0; i < argDescs.length; i++) {
333                     clb.withField(argName(i), argDescs[i], ACC_PRIVATE | ACC_FINAL);
334                 }
335 
336                 generateConstructor(clb);
337 
338                 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
339                     generateClassInitializer(clb);
340                 }
341 
342                 // Forward the SAM method
343                 clb.withMethodBody(interfaceMethodName,
344                         methodDesc(interfaceMethodType),
345                         ACC_PUBLIC,
346                         forwardingMethod(interfaceMethodType));
347 
348                 // Forward the bridges
349                 if (altMethods != null) {
350                     for (MethodType mt : altMethods) {

543                 // Note: if adapting from non-void to void, the 'return'
544                 // instruction will pop the unneeded result
545                 Class<?> implReturnClass = implMethodType.returnType();
546                 Class<?> samReturnClass = methodType.returnType();
547                 TypeConvertingMethodAdapter.convertType(cob, implReturnClass, samReturnClass, samReturnClass);
548                 cob.return_(TypeKind.from(samReturnClass));
549             }
550         };
551     }
552 
553     private void convertArgumentTypes(CodeBuilder cob, MethodType samType) {
554         int samParametersLength = samType.parameterCount();
555         int captureArity = factoryType.parameterCount();
556         for (int i = 0; i < samParametersLength; i++) {
557             Class<?> argType = samType.parameterType(i);
558             cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
559             TypeConvertingMethodAdapter.convertType(cob, argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
560         }
561     }
562 
563     /*
564      * LoadableDescriptors attribute builder
565      */
566     static class LoadableDescriptorsAttributeBuilder {
567         private final Set<String> loadableDescriptors = new HashSet<>();
568         LoadableDescriptorsAttributeBuilder(Class<?> targetClass) {
569             if (requiresLoadableDescriptors(targetClass)) {
570                 loadableDescriptors.add(targetClass.descriptorString());
571             }
572         }
573 
574         /*
575          * Add the value types referenced in the given MethodType.
576          */
577         LoadableDescriptorsAttributeBuilder add(MethodType mt) {
578             // parameter types
579             for (Class<?> paramType : mt.ptypes()) {
580                 if (requiresLoadableDescriptors(paramType)) {
581                     loadableDescriptors.add(paramType.descriptorString());
582                 }
583             }
584             // return type
585             if (requiresLoadableDescriptors(mt.returnType())) {
586                 loadableDescriptors.add(mt.returnType().descriptorString());
587             }
588             return this;
589         }
590 
591         LoadableDescriptorsAttributeBuilder add(MethodType... mtypes) {
592             for (MethodType mt : mtypes) {
593                 add(mt);
594             }
595             return this;
596         }
597 
598         boolean requiresLoadableDescriptors(Class<?> cls) {
599             return cls.isValue() && cls.accessFlags().contains(AccessFlag.FINAL);
600         }
601 
602         boolean isEmpty() {
603             return loadableDescriptors.isEmpty();
604         }
605 
606         void build(ClassBuilder clb) {
607             if (!isEmpty()) {
608                 List<Utf8Entry> lds = new ArrayList<Utf8Entry>(loadableDescriptors.size());
609                 for (String ld : loadableDescriptors) {
610                     lds.add(clb.constantPool().utf8Entry(ld));
611                 }
612                 clb.with(LoadableDescriptorsAttribute.of(lds));
613             }
614         }
615     }
616 
617     /**
618      * Generate LoadableDescriptors attribute if it references any value class
619      */
620     private void generateLoadableDescriptors(ClassBuilder clb) {
621         LoadableDescriptorsAttributeBuilder builder = new LoadableDescriptorsAttributeBuilder(targetClass);
622         builder.add(factoryType)
623                .add(interfaceMethodType)
624                .add(implMethodType)
625                .add(dynamicMethodType)
626                .add(altMethods)
627           .build(clb);
628     }
629 
630     private Opcode invocationOpcode() throws InternalError {
631         return switch (implKind) {
632             case MethodHandleInfo.REF_invokeStatic     -> Opcode.INVOKESTATIC;
633             case MethodHandleInfo.REF_newInvokeSpecial -> Opcode.INVOKESPECIAL;
634             case MethodHandleInfo.REF_invokeVirtual    -> Opcode.INVOKEVIRTUAL;
635             case MethodHandleInfo.REF_invokeInterface  -> Opcode.INVOKEINTERFACE;
636             case MethodHandleInfo.REF_invokeSpecial    -> Opcode.INVOKESPECIAL;
637             default -> throw new InternalError("Unexpected invocation kind: " + implKind);
638         };
639     }
640 
641     static ClassDesc implClassDesc(Class<?> cls) {
642         return cls.isHidden() ? null : ConstantUtils.referenceClassDesc(cls.descriptorString());
643     }
644 
645     static ClassDesc classDesc(Class<?> cls) {
646         return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
647                                  : ConstantUtils.referenceClassDesc(cls.descriptorString());
648     }
649 
< prev index next >