< 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.org.objectweb.asm.*;
  29 import sun.invoke.util.BytecodeDescriptor;
  30 import jdk.internal.misc.Unsafe;
  31 import sun.security.action.GetPropertyAction;
  32 
  33 import java.io.FilePermission;
  34 import java.io.Serializable;

  35 import java.lang.reflect.Constructor;
  36 import java.security.AccessController;
  37 import java.security.PrivilegedAction;
  38 import java.util.LinkedHashSet;
  39 import java.util.concurrent.atomic.AtomicInteger;
  40 import java.util.PropertyPermission;
  41 import java.util.Set;
  42 

  43 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  44 
  45 /**
  46  * Lambda metafactory implementation which dynamically creates an
  47  * inner-class-like class per lambda callsite.
  48  *
  49  * @see LambdaMetafactory
  50  */
  51 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  52     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  53 
  54     private static final int CLASSFILE_VERSION = 52;
  55     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  56     private static final String JAVA_LANG_OBJECT = "java/lang/Object";
  57     private static final String NAME_CTOR = "<init>";
  58     private static final String NAME_FACTORY = "get$Lambda";
  59 
  60     //Serialization support
  61     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  62     private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
  63     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  64     private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
  65     private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
  66     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  67     private static final String NAME_METHOD_READ_OBJECT = "readObject";
  68     private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
  69 
  70     private static final String DESCR_CLASS = "Ljava/lang/Class;";
  71     private static final String DESCR_STRING = "Ljava/lang/String;";
  72     private static final String DESCR_OBJECT = "Ljava/lang/Object;";
  73     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  74             = "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
  75             + DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
  76 
  77     private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
  78     private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};


 199                         ctrs[0].setAccessible(true);
 200                     }
 201                     return ctrs;
 202                 }
 203                     });
 204             if (ctrs.length != 1) {
 205                 throw new LambdaConversionException("Expected one lambda constructor for "
 206                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 207             }
 208 
 209             try {
 210                 Object inst = ctrs[0].newInstance();
 211                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 212             }
 213             catch (ReflectiveOperationException e) {
 214                 throw new LambdaConversionException("Exception instantiating lambda object", e);
 215             }
 216         } else {
 217             try {
 218                 UNSAFE.ensureClassInitialized(innerClass);
 219                 return new ConstantCallSite(
 220                         MethodHandles.Lookup.IMPL_LOOKUP
 221                              .findStatic(innerClass, NAME_FACTORY, invokedType));
 222             }
 223             catch (ReflectiveOperationException e) {
 224                 throw new LambdaConversionException("Exception finding constructor", e);
 225             }
 226         }
 227     }
 228 
 229     /**
 230      * Generate a class file which implements the functional
 231      * interface, define and return the class.
 232      *
 233      * @implNote The class that is generated does not include signature
 234      * information for exceptions that may be present on the SAM method.
 235      * This is to reduce classfile size, and is harmless as checked exceptions
 236      * are erased anyway, no one will ever compile against this classfile,
 237      * and we make no guarantees about the reflective properties of lambda
 238      * objects.
 239      *
 240      * @return a Class which implements the functional interface
 241      * @throws LambdaConversionException If properly formed functional interface
 242      * is not found
 243      */


 256                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
 257             }
 258             interfaces = itfs.toArray(new String[itfs.size()]);
 259         }
 260 
 261         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 262                  lambdaClassName, null,
 263                  JAVA_LANG_OBJECT, interfaces);
 264 
 265         // Generate final fields to be filled in by constructor
 266         for (int i = 0; i < argDescs.length; i++) {
 267             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
 268                                             argNames[i],
 269                                             argDescs[i],
 270                                             null, null);
 271             fv.visitEnd();
 272         }
 273 
 274         generateConstructor();
 275 
 276         if (invokedType.parameterCount() != 0) {
 277             generateFactory();
 278         }
 279 
 280         // Forward the SAM method
 281         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
 282                                           samMethodType.toMethodDescriptorString(), null, null);
 283         mv.visitAnnotation(DESCR_HIDDEN, true);
 284         new ForwardingMethodGenerator(mv).generate(samMethodType);
 285 
 286         // Forward the bridges
 287         if (additionalBridges != null) {
 288             for (MethodType mt : additionalBridges) {
 289                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
 290                                     mt.toMethodDescriptorString(), null, null);
 291                 mv.visitAnnotation(DESCR_HIDDEN, true);
 292                 new ForwardingMethodGenerator(mv).generate(mt);
 293             }
 294         }
 295 
 296         if (isSerializable)
 297             generateSerializationFriendlyMethods();
 298         else if (accidentallySerializable)
 299             generateSerializationHostileMethods();
 300 
 301         cw.visitEnd();
 302 
 303         // Define the generated class in this VM.
 304 
 305         final byte[] classBytes = cw.toByteArray();
 306 
 307         // If requested, dump out to a file for debugging purposes
 308         if (dumper != null) {
 309             AccessController.doPrivileged(new PrivilegedAction<>() {
 310                 @Override
 311                 public Void run() {
 312                     dumper.dumpClass(lambdaClassName, classBytes);
 313                     return null;
 314                 }
 315             }, null,
 316             new FilePermission("<<ALL FILES>>", "read, write"),
 317             // createDirectories may need it
 318             new PropertyPermission("user.dir", "read"));
 319         }
 320 
 321         return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
 322     }
 323 
 324     /**
 325      * Generate the factory method for the class
 326      */
 327     private void generateFactory() {
 328         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
 329         m.visitCode();
 330         m.visitTypeInsn(NEW, lambdaClassName);
 331         m.visitInsn(Opcodes.DUP);
 332         int parameterCount = invokedType.parameterCount();
 333         for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
 334             Class<?> argType = invokedType.parameterType(typeIndex);
 335             m.visitVarInsn(getLoadOpcode(argType), varIndex);
 336             varIndex += getParameterSize(argType);
 337         }
 338         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
 339         m.visitInsn(ARETURN);
 340         m.visitMaxs(-1, -1);
 341         m.visitEnd();
 342     }
 343 
 344     /**
 345      * Generate the constructor for the class
 346      */
 347     private void generateConstructor() {
 348         // Generate constructor
 349         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
 350                                             constructorType.toMethodDescriptorString(), null, null);
 351         ctor.visitCode();
 352         ctor.visitVarInsn(ALOAD, 0);
 353         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
 354                              METHOD_DESCRIPTOR_VOID, false);
 355         int parameterCount = invokedType.parameterCount();
 356         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
 357             ctor.visitVarInsn(ALOAD, 0);
 358             Class<?> argType = invokedType.parameterType(i);
 359             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
 360             lvIndex += getParameterSize(argType);
 361             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);




   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.Unsafe;
  29 import jdk.internal.org.objectweb.asm.*;
  30 import sun.invoke.util.BytecodeDescriptor;

  31 import sun.security.action.GetPropertyAction;
  32 
  33 import java.io.FilePermission;
  34 import java.io.Serializable;
  35 import java.lang.invoke.MethodHandles.Lookup;
  36 import java.lang.reflect.Constructor;
  37 import java.security.AccessController;
  38 import java.security.PrivilegedAction;
  39 import java.util.LinkedHashSet;
  40 import java.util.concurrent.atomic.AtomicInteger;
  41 import java.util.PropertyPermission;
  42 import java.util.Set;
  43 
  44 import static java.lang.invoke.MethodHandles.Lookup.*;
  45 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  46 
  47 /**
  48  * Lambda metafactory implementation which dynamically creates an
  49  * inner-class-like class per lambda callsite.
  50  *
  51  * @see LambdaMetafactory
  52  */
  53 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  54     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  55 
  56     private static final int CLASSFILE_VERSION = 52;
  57     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  58     private static final String JAVA_LANG_OBJECT = "java/lang/Object";
  59     private static final String NAME_CTOR = "<init>";

  60 
  61     //Serialization support
  62     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  63     private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
  64     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  65     private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
  66     private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
  67     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  68     private static final String NAME_METHOD_READ_OBJECT = "readObject";
  69     private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
  70 
  71     private static final String DESCR_CLASS = "Ljava/lang/Class;";
  72     private static final String DESCR_STRING = "Ljava/lang/String;";
  73     private static final String DESCR_OBJECT = "Ljava/lang/Object;";
  74     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  75             = "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
  76             + DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
  77 
  78     private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
  79     private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};


 200                         ctrs[0].setAccessible(true);
 201                     }
 202                     return ctrs;
 203                 }
 204                     });
 205             if (ctrs.length != 1) {
 206                 throw new LambdaConversionException("Expected one lambda constructor for "
 207                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 208             }
 209 
 210             try {
 211                 Object inst = ctrs[0].newInstance();
 212                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 213             }
 214             catch (ReflectiveOperationException e) {
 215                 throw new LambdaConversionException("Exception instantiating lambda object", e);
 216             }
 217         } else {
 218             try {
 219                 UNSAFE.ensureClassInitialized(innerClass);
 220                 Lookup lookup = MethodHandles.privateLookupIn(innerClass, Lookup.IMPL_LOOKUP);
 221                 MethodHandle mh = lookup.findConstructor(innerClass, invokedType.changeReturnType(void.class));
 222                 return new ConstantCallSite(mh.asType(invokedType));
 223             } catch (ReflectiveOperationException e) {

 224                 throw new LambdaConversionException("Exception finding constructor", e);
 225             }
 226         }
 227     }
 228 
 229     /**
 230      * Generate a class file which implements the functional
 231      * interface, define and return the class.
 232      *
 233      * @implNote The class that is generated does not include signature
 234      * information for exceptions that may be present on the SAM method.
 235      * This is to reduce classfile size, and is harmless as checked exceptions
 236      * are erased anyway, no one will ever compile against this classfile,
 237      * and we make no guarantees about the reflective properties of lambda
 238      * objects.
 239      *
 240      * @return a Class which implements the functional interface
 241      * @throws LambdaConversionException If properly formed functional interface
 242      * is not found
 243      */


 256                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
 257             }
 258             interfaces = itfs.toArray(new String[itfs.size()]);
 259         }
 260 
 261         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 262                  lambdaClassName, null,
 263                  JAVA_LANG_OBJECT, interfaces);
 264 
 265         // Generate final fields to be filled in by constructor
 266         for (int i = 0; i < argDescs.length; i++) {
 267             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
 268                                             argNames[i],
 269                                             argDescs[i],
 270                                             null, null);
 271             fv.visitEnd();
 272         }
 273 
 274         generateConstructor();
 275 




 276         // Forward the SAM method
 277         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
 278                                           samMethodType.toMethodDescriptorString(), null, null);
 279         mv.visitAnnotation(DESCR_HIDDEN, true);
 280         new ForwardingMethodGenerator(mv).generate(samMethodType);
 281 
 282         // Forward the bridges
 283         if (additionalBridges != null) {
 284             for (MethodType mt : additionalBridges) {
 285                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
 286                                     mt.toMethodDescriptorString(), null, null);
 287                 mv.visitAnnotation(DESCR_HIDDEN, true);
 288                 new ForwardingMethodGenerator(mv).generate(mt);
 289             }
 290         }
 291 
 292         if (isSerializable)
 293             generateSerializationFriendlyMethods();
 294         else if (accidentallySerializable)
 295             generateSerializationHostileMethods();
 296 
 297         cw.visitEnd();
 298 
 299         // Define the generated class in this VM.
 300 
 301         final byte[] classBytes = cw.toByteArray();
 302 
 303         // If requested, dump out to a file for debugging purposes
 304         if (dumper != null) {
 305             AccessController.doPrivileged(new PrivilegedAction<>() {
 306                 @Override
 307                 public Void run() {
 308                     dumper.dumpClass(lambdaClassName, classBytes);
 309                     return null;
 310                 }
 311             }, null,
 312             new FilePermission("<<ALL FILES>>", "read, write"),
 313             // createDirectories may need it
 314             new PropertyPermission("user.dir", "read"));
 315         }
 316         try {
 317             Lookup lookup = MethodHandles.privateLookupIn(targetClass, IMPL_LOOKUP);
 318             // this class is linked at the indy callsite.  No need to be weak class
 319             return lookup.defineClassWithNoCheck(classBytes, HIDDEN_NESTMATE);
 320         } catch (ReflectiveOperationException e) {
 321             throw new LambdaConversionException(e);











 322         }




 323     }
 324 
 325     /**
 326      * Generate the constructor for the class
 327      */
 328     private void generateConstructor() {
 329         // Generate constructor
 330         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
 331                                             constructorType.toMethodDescriptorString(), null, null);
 332         ctor.visitCode();
 333         ctor.visitVarInsn(ALOAD, 0);
 334         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
 335                              METHOD_DESCRIPTOR_VOID, false);
 336         int parameterCount = invokedType.parameterCount();
 337         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
 338             ctor.visitVarInsn(ALOAD, 0);
 339             Class<?> argType = invokedType.parameterType(i);
 340             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
 341             lvIndex += getParameterSize(argType);
 342             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);


< prev index next >