< 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";

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.value.PrimitiveClass;
 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";

342 
343         // Forward the SAM method
344         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
345                                           interfaceMethodType.toMethodDescriptorString(), null, null);
346         new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
347 
348         // Forward the altMethods
349         if (altMethods != null) {
350             for (MethodType mt : altMethods) {
351                 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
352                                     mt.toMethodDescriptorString(), null, null);
353                 new ForwardingMethodGenerator(mv).generate(mt);
354             }
355         }
356 
357         if (isSerializable)
358             generateSerializationFriendlyMethods();
359         else if (accidentallySerializable)
360             generateSerializationHostileMethods();
361 
362         // generate Preload attribute if it references any value class
363         PreloadAttributeBuilder builder = new PreloadAttributeBuilder(targetClass);
364         builder.add(factoryType)
365                .add(interfaceMethodType)
366                .add(implMethodType)
367                .add(dynamicMethodType)
368                .add(altMethods);
369         if (!builder.isEmpty())
370             cw.visitAttribute(builder.build());
371 
372         cw.visitEnd();
373 
374         // Define the generated class in this VM.
375 
376         final byte[] classBytes = cw.toByteArray();
377         // If requested, dump out to a file for debugging purposes
378         if (dumper != null) {
379             AccessController.doPrivileged(new PrivilegedAction<>() {
380                 @Override
381                 public Void run() {
382                     dumper.dumpClass(lambdaClassName, classBytes);
383                     return null;
384                 }
385             }, null,
386             new FilePermission("<<ALL FILES>>", "read, write"),
387             // createDirectories may need it
388             new PropertyPermission("user.dir", "read"));
389         }
390         try {
391             // this class is linked at the indy callsite; so define a hidden nestmate

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