< prev index next >

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

Print this page

  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.MethodHandleNatives.Constants.NESTMATE_CLASS;
 57 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
 58 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 59 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 60 import static java.lang.invoke.MethodType.methodType;
 61 import jdk.internal.constant.ConstantUtils;
 62 import jdk.internal.constant.MethodTypeDescImpl;
 63 import jdk.internal.constant.ReferenceClassDescImpl;
 64 import sun.invoke.util.Wrapper;
 65 
 66 /**
 67  * Lambda metafactory implementation which dynamically creates an
 68  * inner-class-like class per lambda callsite.
 69  *
 70  * @see LambdaMetafactory
 71  */
 72 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 73     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
 74     private static final String[] EMPTY_STRING_ARRAY = new String[0];

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

313                    .withInterfaceSymbols(interfaces);






314                 // Generate final fields to be filled in by constructor
315                 for (int i = 0; i < argDescs.length; i++) {
316                     clb.withField(argNames[i], argDescs[i], ACC_PRIVATE | ACC_FINAL);
317                 }
318 
319                 generateConstructor(clb);
320 
321                 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
322                     generateClassInitializer(clb);
323                 }
324 
325                 // Forward the SAM method
326                 clb.withMethodBody(interfaceMethodName,
327                         methodDesc(interfaceMethodType),
328                         ACC_PUBLIC,
329                         forwardingMethod(interfaceMethodType));
330 
331                 // Forward the bridges
332                 if (altMethods != null) {
333                     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 : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
560     }
561 
562     static ClassDesc classDesc(Class<?> cls) {
563         return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
564                                  : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
565     }
566 

  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.MethodHandleNatives.Constants.NESTMATE_CLASS;
 66 import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
 67 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 68 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 69 import static java.lang.invoke.MethodType.methodType;
 70 import jdk.internal.constant.ConstantUtils;
 71 import jdk.internal.constant.MethodTypeDescImpl;
 72 import jdk.internal.constant.ReferenceClassDescImpl;
 73 import sun.invoke.util.Wrapper;
 74 
 75 /**
 76  * Lambda metafactory implementation which dynamically creates an
 77  * inner-class-like class per lambda callsite.
 78  *
 79  * @see LambdaMetafactory
 80  */
 81 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 82     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
 83     private static final String[] EMPTY_STRING_ARRAY = new String[0];

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