< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  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.org.objectweb.asm.*;
 30 import sun.invoke.util.BytecodeDescriptor;
 31 import sun.invoke.util.VerifyAccess;
 32 import sun.security.action.GetPropertyAction;
 33 import sun.security.action.GetBooleanAction;
 34 
 35 import java.io.FilePermission;
 36 import java.io.Serializable;
 37 import java.lang.constant.ConstantDescs;
 38 import java.lang.invoke.MethodHandles.Lookup;
 39 import java.lang.reflect.Modifier;
 40 import java.security.AccessController;
 41 import java.security.PrivilegedAction;

 42 import java.util.LinkedHashSet;
 43 import java.util.concurrent.atomic.AtomicInteger;
 44 import java.util.PropertyPermission;
 45 import java.util.Set;
 46 
 47 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
 48 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 49 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 50 import static java.lang.invoke.MethodType.methodType;
 51 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 52 
 53 /**
 54  * Lambda metafactory implementation which dynamically creates an
 55  * inner-class-like class per lambda callsite.
 56  *
 57  * @see LambdaMetafactory
 58  */
 59 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 60     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
 61     private static final String JAVA_LANG_OBJECT = "java/lang/Object";

302      * is not found
303      */
304     @SuppressWarnings("removal")
305     private Class<?> generateInnerClass() throws LambdaConversionException {
306         String[] interfaceNames;
307         String interfaceName = interfaceClass.getName().replace('.', '/');
308         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
309         if (altInterfaces.length == 0) {
310             interfaceNames = new String[]{interfaceName};
311         } else {
312             // Assure no duplicate interfaces (ClassFormatError)
313             Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
314             itfs.add(interfaceName);
315             for (Class<?> i : altInterfaces) {
316                 itfs.add(i.getName().replace('.', '/'));
317                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
318             }
319             interfaceNames = itfs.toArray(new String[itfs.size()]);
320         }
321 
322         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,

323                  lambdaClassName, null,
324                  JAVA_LANG_OBJECT, interfaceNames);
325 
326         // Generate final fields to be filled in by constructor
327         for (int i = 0; i < argDescs.length; i++) {
328             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
329                                             argNames[i],
330                                             argDescs[i],
331                                             null, null);
332             fv.visitEnd();
333         }
334 
335         generateConstructor();
336 
337         if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
338             generateClassInitializer();
339         }
340 
341         // Forward the SAM method
342         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
343                                           interfaceMethodType.toMethodDescriptorString(), null, null);
344         new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
345 
346         // Forward the altMethods
347         if (altMethods != null) {
348             for (MethodType mt : altMethods) {
349                 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
350                                     mt.toMethodDescriptorString(), null, null);
351                 new ForwardingMethodGenerator(mv).generate(mt);
352             }
353         }
354 
355         if (isSerializable)
356             generateSerializationFriendlyMethods();
357         else if (accidentallySerializable)
358             generateSerializationHostileMethods();
359 










360         cw.visitEnd();
361 
362         // Define the generated class in this VM.
363 
364         final byte[] classBytes = cw.toByteArray();
365         // If requested, dump out to a file for debugging purposes
366         if (dumper != null) {
367             AccessController.doPrivileged(new PrivilegedAction<>() {
368                 @Override
369                 public Void run() {
370                     dumper.dumpClass(lambdaClassName, classBytes);
371                     return null;
372                 }
373             }, null,
374             new FilePermission("<<ALL FILES>>", "read, write"),
375             // createDirectories may need it
376             new PropertyPermission("user.dir", "read"));
377         }
378         try {
379             // this class is linked at the indy callsite; so define a hidden nestmate

573             for (int i = 0; i < samParametersLength; i++) {
574                 Class<?> argType = samType.parameterType(i);
575                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
576                 lvIndex += getParameterSize(argType);
577                 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
578             }
579         }
580 
581         private int invocationOpcode() throws InternalError {
582             return switch (implKind) {
583                 case MethodHandleInfo.REF_invokeStatic     -> INVOKESTATIC;
584                 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
585                 case MethodHandleInfo.REF_invokeVirtual    -> INVOKEVIRTUAL;
586                 case MethodHandleInfo.REF_invokeInterface  -> INVOKEINTERFACE;
587                 case MethodHandleInfo.REF_invokeSpecial    -> INVOKESPECIAL;
588                 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
589             };
590         }
591     }
592 


































































593     static int getParameterSize(Class<?> c) {
594         if (c == Void.TYPE) {
595             return 0;
596         } else if (c == Long.TYPE || c == Double.TYPE) {
597             return 2;
598         }
599         return 1;
600     }
601 
602     static int getLoadOpcode(Class<?> c) {
603         if(c == Void.TYPE) {
604             throw new InternalError("Unexpected void type of load opcode");
605         }
606         return ILOAD + getOpcodeOffset(c);
607     }
608 
609     static int getReturnOpcode(Class<?> c) {
610         if(c == Void.TYPE) {
611             return RETURN;
612         }

  1 /*
  2  * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  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.org.objectweb.asm.*;
 31 import sun.invoke.util.BytecodeDescriptor;
 32 import sun.invoke.util.VerifyAccess;
 33 import sun.security.action.GetPropertyAction;
 34 import sun.security.action.GetBooleanAction;
 35 
 36 import java.io.FilePermission;
 37 import java.io.Serializable;
 38 import java.lang.constant.ConstantDescs;
 39 import java.lang.invoke.MethodHandles.Lookup;
 40 import java.lang.reflect.Modifier;
 41 import java.security.AccessController;
 42 import java.security.PrivilegedAction;
 43 import java.util.HashSet;
 44 import java.util.LinkedHashSet;
 45 import java.util.concurrent.atomic.AtomicInteger;
 46 import java.util.PropertyPermission;
 47 import java.util.Set;
 48 
 49 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
 50 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 51 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 52 import static java.lang.invoke.MethodType.methodType;
 53 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 54 
 55 /**
 56  * Lambda metafactory implementation which dynamically creates an
 57  * inner-class-like class per lambda callsite.
 58  *
 59  * @see LambdaMetafactory
 60  */
 61 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 62     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
 63     private static final String JAVA_LANG_OBJECT = "java/lang/Object";

304      * is not found
305      */
306     @SuppressWarnings("removal")
307     private Class<?> generateInnerClass() throws LambdaConversionException {
308         String[] interfaceNames;
309         String interfaceName = interfaceClass.getName().replace('.', '/');
310         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
311         if (altInterfaces.length == 0) {
312             interfaceNames = new String[]{interfaceName};
313         } else {
314             // Assure no duplicate interfaces (ClassFormatError)
315             Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
316             itfs.add(interfaceName);
317             for (Class<?> i : altInterfaces) {
318                 itfs.add(i.getName().replace('.', '/'));
319                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
320             }
321             interfaceNames = itfs.toArray(new String[itfs.size()]);
322         }
323 
324         int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
325         cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
326                  lambdaClassName, null,
327                  JAVA_LANG_OBJECT, interfaceNames);
328 
329         // Generate final fields to be filled in by constructor
330         for (int i = 0; i < argDescs.length; i++) {
331             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
332                                             argNames[i],
333                                             argDescs[i],
334                                             null, null);
335             fv.visitEnd();
336         }
337 
338         generateConstructor();
339 
340         if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
341             generateClassInitializer();
342         }
343 
344         // Forward the SAM method
345         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
346                                           interfaceMethodType.toMethodDescriptorString(), null, null);
347         new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
348 
349         // Forward the altMethods
350         if (altMethods != null) {
351             for (MethodType mt : altMethods) {
352                 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
353                                     mt.toMethodDescriptorString(), null, null);
354                 new ForwardingMethodGenerator(mv).generate(mt);
355             }
356         }
357 
358         if (isSerializable)
359             generateSerializationFriendlyMethods();
360         else if (accidentallySerializable)
361             generateSerializationHostileMethods();
362 
363         // generate Preload attribute if it references any value class
364         PreloadAttributeBuilder builder = new PreloadAttributeBuilder(targetClass);
365         builder.add(factoryType)
366                .add(interfaceMethodType)
367                .add(implMethodType)
368                .add(dynamicMethodType)
369                .add(altMethods);
370         if (!builder.isEmpty())
371             cw.visitAttribute(builder.build());
372 
373         cw.visitEnd();
374 
375         // Define the generated class in this VM.
376 
377         final byte[] classBytes = cw.toByteArray();
378         // If requested, dump out to a file for debugging purposes
379         if (dumper != null) {
380             AccessController.doPrivileged(new PrivilegedAction<>() {
381                 @Override
382                 public Void run() {
383                     dumper.dumpClass(lambdaClassName, classBytes);
384                     return null;
385                 }
386             }, null,
387             new FilePermission("<<ALL FILES>>", "read, write"),
388             // createDirectories may need it
389             new PropertyPermission("user.dir", "read"));
390         }
391         try {
392             // this class is linked at the indy callsite; so define a hidden nestmate

586             for (int i = 0; i < samParametersLength; i++) {
587                 Class<?> argType = samType.parameterType(i);
588                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
589                 lvIndex += getParameterSize(argType);
590                 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
591             }
592         }
593 
594         private int invocationOpcode() throws InternalError {
595             return switch (implKind) {
596                 case MethodHandleInfo.REF_invokeStatic     -> INVOKESTATIC;
597                 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
598                 case MethodHandleInfo.REF_invokeVirtual    -> INVOKEVIRTUAL;
599                 case MethodHandleInfo.REF_invokeInterface  -> INVOKEINTERFACE;
600                 case MethodHandleInfo.REF_invokeSpecial    -> INVOKESPECIAL;
601                 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
602             };
603         }
604     }
605 
606     /*
607      * Preload attribute builder
608      */
609     static class PreloadAttributeBuilder {
610         private final Set<Class<?>> preloadClasses = new HashSet<>();
611         PreloadAttributeBuilder(Class<?> targetClass) {
612             if (requiresPreload(targetClass)) {
613                 preloadClasses.add(targetClass);
614             }
615         }
616 
617         /*
618          * Add the value types referenced in the given MethodType.
619          */
620         PreloadAttributeBuilder add(MethodType mt) {
621             // parameter types
622             for (Class<?> paramType : mt.ptypes()) {
623                 if (requiresPreload(paramType)) {
624                     preloadClasses.add(paramType);
625                 }
626             }
627             // return type
628             if (requiresPreload(mt.returnType())) {
629                 preloadClasses.add(mt.returnType());
630             }
631             return this;
632         }
633 
634         PreloadAttributeBuilder add(MethodType... mtypes) {
635             for (MethodType mt : mtypes) {
636                 add(mt);
637             }
638             return this;
639         }
640 
641         boolean requiresPreload(Class<?> cls) {
642             Class<?> c = cls;
643             while (c.isArray()) {
644                 c = c.getComponentType();
645             }
646             return c.isValue();
647         }
648 
649         boolean isEmpty() {
650             return preloadClasses.isEmpty();
651         }
652 
653         Attribute build() {
654             return new Attribute("Preload") {
655                 @Override
656                 protected ByteVector write(ClassWriter cw,
657                                            byte[] code,
658                                            int len,
659                                            int maxStack,
660                                            int maxLocals) {
661                     ByteVector attr = new ByteVector();
662                     attr.putShort(preloadClasses.size());
663                     for (Class<?> c : preloadClasses) {
664                         attr.putShort(cw.newClass(Type.getInternalName(c)));
665                     }
666                     return attr;
667                 }
668             };
669         }
670     }
671 
672     static int getParameterSize(Class<?> c) {
673         if (c == Void.TYPE) {
674             return 0;
675         } else if (c == Long.TYPE || c == Double.TYPE) {
676             return 2;
677         }
678         return 1;
679     }
680 
681     static int getLoadOpcode(Class<?> c) {
682         if(c == Void.TYPE) {
683             throw new InternalError("Unexpected void type of load opcode");
684         }
685         return ILOAD + getOpcodeOffset(c);
686     }
687 
688     static int getReturnOpcode(Class<?> c) {
689         if(c == Void.TYPE) {
690             return RETURN;
691         }
< prev index next >