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