< 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.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 
< prev index next >