< prev index next >

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

Print this page
*** 32,13 ***
  import sun.invoke.util.VerifyAccess;
  import sun.security.action.GetBooleanAction;
  
  import java.io.Serializable;
  import java.lang.constant.ConstantDescs;
  import java.lang.reflect.Modifier;
! import java.util.LinkedHashSet;
- import java.util.Set;
  
  import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
  import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
  import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
  import static java.lang.invoke.MethodType.methodType;
--- 32,17 ---
  import sun.invoke.util.VerifyAccess;
  import sun.security.action.GetBooleanAction;
  
  import java.io.Serializable;
  import java.lang.constant.ConstantDescs;
+ import java.lang.reflect.code.op.CoreOp.FuncOp;
+ import java.lang.reflect.code.Quoted;
+ import java.lang.reflect.code.interpreter.Interpreter;
+ import java.lang.reflect.code.parser.OpParser;
+ import java.lang.invoke.MethodHandles.Lookup;
  import java.lang.reflect.Modifier;
! import java.util.*;
  
  import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
  import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
  import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
  import static java.lang.invoke.MethodType.methodType;

*** 60,14 ***
--- 64,16 ---
      private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
      private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
      private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
      private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
      private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
+     private static final String DESCR_METHOD_QUOTED = "()Ljava/lang/reflect/code/Quoted;";
  
      private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
      private static final String NAME_METHOD_READ_OBJECT = "readObject";
      private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
+     private static final String NAME_METHOD_QUOTED = "quoted";
  
      private static final String DESCR_CLASS = "Ljava/lang/Class;";
      private static final String DESCR_STRING = "Ljava/lang/String;";
      private static final String DESCR_OBJECT = "Ljava/lang/Object;";
      private static final String DESCR_CTOR_SERIALIZED_LAMBDA

*** 85,10 ***
--- 91,21 ---
      private static final boolean disableEagerInitialization;
  
      // condy to load implMethod from class data
      private static final ConstantDynamic implMethodCondy;
  
+     // condy to load reflective field from class data
+     private static final ConstantDynamic reflectiveFieldCondy;
+ 
+     private static final ConstantDynamic makeQuotedMethodCondy;
+ 
+     private static final MethodHandle HANDLE_MAKE_QUOTED;
+ 
+     private static final String quotedInstanceFieldName = "quoted";
+     private static final String quotedInstanceFieldDesc = Quoted.class.descriptorString();
+ 
+ 
      static {
          // To dump the lambda proxy classes, set this system property:
          //    -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles
          // or -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles=true
          final String dumpProxyClassesKey = "jdk.invoke.LambdaMetafactory.dumpProxyClassFiles";

*** 96,14 ***
  
          final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
          disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
  
          // condy to load implMethod from class data
!         MethodType classDataMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
!         Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classData",
!                                          classDataMType.descriptorString(), false);
!         implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm);
      }
  
      // See context values in AbstractValidatingLambdaMetafactory
      private final String implMethodClassName;        // Name of type containing implementation "CC"
      private final String implMethodName;             // Name of implementation method "impl"
--- 113,24 ---
  
          final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
          disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
  
          // condy to load implMethod from class data
!         MethodType classDataAtMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class, int.class);
!         Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classDataAt",
!                                          classDataAtMType.descriptorString(), false);
!         implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 0);
+         reflectiveFieldCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 1);
+         makeQuotedMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 2);
+ 
+         try {
+             HANDLE_MAKE_QUOTED = MethodHandles.lookup().findStatic(
+                     InnerClassLambdaMetafactory.class, "makeQuoted",
+                     MethodType.methodType(Quoted.class, String.class, Object[].class));
+         } catch (Throwable ex) {
+             throw new AssertionError(ex);
+         }
      }
  
      // See context values in AbstractValidatingLambdaMetafactory
      private final String implMethodClassName;        // Name of type containing implementation "CC"
      private final String implMethodName;             // Name of implementation method "impl"

*** 147,10 ***
--- 174,13 ---
       *                       types must extend {@code Serializable}.
       * @param altInterfaces Additional interfaces which the lambda object
       *                      should implement.
       * @param altMethods Method types for additional signatures to be
       *                   implemented by invoking the implementation method
+      * @param reflectiveField a {@linkplain MethodHandles.Lookup#findGetter(Class, String, Class) getter}
+      *                   method handle that is used to retrieve the string representation of the
+      *                   quotable lambda's associated intermediate representation.
       * @throws LambdaConversionException If any of the meta-factory protocol
       *         invariants are violated
       * @throws SecurityException If a security manager is present, and it
       *         <a href="MethodHandles.Lookup.html#secmgr">denies access</a>
       *         from {@code caller} to the package of {@code implementation}.

*** 161,15 ***
                                         MethodType interfaceMethodType,
                                         MethodHandle implementation,
                                         MethodType dynamicMethodType,
                                         boolean isSerializable,
                                         Class<?>[] altInterfaces,
!                                        MethodType[] altMethods)
              throws LambdaConversionException {
          super(caller, factoryType, interfaceMethodName, interfaceMethodType,
                implementation, dynamicMethodType,
!               isSerializable, altInterfaces, altMethods);
          implMethodClassName = implClass.getName().replace('.', '/');
          implMethodName = implInfo.getName();
          implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
          constructorType = factoryType.changeReturnType(Void.TYPE);
          lambdaClassName = lambdaClassName(targetClass);
--- 191,16 ---
                                         MethodType interfaceMethodType,
                                         MethodHandle implementation,
                                         MethodType dynamicMethodType,
                                         boolean isSerializable,
                                         Class<?>[] altInterfaces,
!                                        MethodType[] altMethods,
+                                        MethodHandle reflectiveField)
              throws LambdaConversionException {
          super(caller, factoryType, interfaceMethodName, interfaceMethodType,
                implementation, dynamicMethodType,
!               isSerializable, altInterfaces, altMethods, reflectiveField);
          implMethodClassName = implClass.getName().replace('.', '/');
          implMethodName = implInfo.getName();
          implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
          constructorType = factoryType.changeReturnType(Void.TYPE);
          lambdaClassName = lambdaClassName(targetClass);

*** 327,10 ***
--- 358,18 ---
                                              argDescs[i],
                                              null, null);
              fv.visitEnd();
          }
  
+         // if quotable, generate the field that will hold the value of quoted
+         if (quotableOpField != null) {
+             cw.visitField(ACC_PRIVATE + ACC_FINAL,
+                           quotedInstanceFieldName,
+                           quotedInstanceFieldDesc,
+                           null, null);
+         }
+ 
          generateConstructor();
  
          if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
              generateClassInitializer();
          }

*** 352,18 ***
          if (isSerializable)
              generateSerializationFriendlyMethods();
          else if (accidentallySerializable)
              generateSerializationHostileMethods();
  
          cw.visitEnd();
  
          // Define the generated class in this VM.
  
          final byte[] classBytes = cw.toByteArray();
          try {
              // this class is linked at the indy callsite; so define a hidden nestmate
!             var classdata = useImplMethodHandle? implementation : null;
              return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
                           .defineClass(!disableEagerInitialization, classdata);
  
          } catch (Throwable t) {
              throw new InternalError(t);
--- 391,29 ---
          if (isSerializable)
              generateSerializationFriendlyMethods();
          else if (accidentallySerializable)
              generateSerializationHostileMethods();
  
+         if (quotableOpField != null) {
+             generateQuotableMethod();
+         }
+ 
          cw.visitEnd();
  
          // Define the generated class in this VM.
  
          final byte[] classBytes = cw.toByteArray();
          try {
              // this class is linked at the indy callsite; so define a hidden nestmate
!             List<?> classdata;
+             if (useImplMethodHandle || quotableOpField != null) {
+                 classdata = quotableOpField == null ?
+                         List.of(implementation) :
+                         List.of(implementation, quotableOpField, HANDLE_MAKE_QUOTED);
+             } else {
+                 classdata = null;
+             }
              return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
                           .defineClass(!disableEagerInitialization, classdata);
  
          } catch (Throwable t) {
              throw new InternalError(t);

*** 413,16 ***
--- 463,62 ---
              Class<?> argType = factoryType.parameterType(i);
              ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
              lvIndex += getParameterSize(argType);
              ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
          }
+ 
+         if (quotableOpField != null) {
+             generateQuotedFieldInitializer(ctor);
+         }
+ 
          ctor.visitInsn(RETURN);
          // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
          ctor.visitMaxs(-1, -1);
          ctor.visitEnd();
      }
  
+     private void generateQuotedFieldInitializer(MethodVisitor ctor) {
+         ctor.visitCode();
+ 
+         // push the receiver on the stack for operand of put field instruction
+         ctor.visitVarInsn(ALOAD, 0);
+ 
+         ctor.visitLdcInsn(makeQuotedMethodCondy);
+ 
+         // load op string from field
+ 
+         ctor.visitLdcInsn(reflectiveFieldCondy);
+         MethodType mtype = quotableOpFieldInfo.getMethodType();
+         if (quotableOpFieldInfo.getReferenceKind() != MethodHandleInfo.REF_getStatic) {
+             mtype = mtype.insertParameterTypes(0, implClass);
+         }
+         ctor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
+                 "invokeExact", mtype.descriptorString(), false);
+ 
+         // load captured args in array
+ 
+         ctor.visitLdcInsn(quotableOpType.parameterCount());
+         ctor.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
+         int capturedArity = factoryType.parameterCount() - reflectiveCaptureCount();
+         // initialize quoted captures
+         TypeConvertingMethodAdapter tcmv = new TypeConvertingMethodAdapter(ctor);
+         for (int i = 0; i < reflectiveCaptureCount(); i++) {
+             ctor.visitInsn(DUP);
+             ctor.visitIntInsn(BIPUSH, i); // is it possible that i can be greater than Byte.MAX_VALUE ?
+             ctor.visitVarInsn(ALOAD, 0);
+             ctor.visitFieldInsn(GETFIELD, lambdaClassName, argNames[capturedArity + i], argDescs[capturedArity + i]);
+             tcmv.boxIfTypePrimitive(Type.getType(argDescs[capturedArity + i]));
+             ctor.visitInsn(AASTORE);
+         }
+ 
+         // now create a Quoted from String and captured args Object[]
+ 
+         ctor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
+                 "invokeExact", HANDLE_MAKE_QUOTED.type().toMethodDescriptorString(), false);
+         ctor.visitFieldInsn(PUTFIELD, lambdaClassName, quotedInstanceFieldName, quotedInstanceFieldDesc);
+     }
+ 
      /**
       * Generate a writeReplace method that supports serialization
       */
      private void generateSerializationFriendlyMethods() {
          TypeConvertingMethodAdapter mv

*** 459,10 ***
--- 555,27 ---
          // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
          mv.visitMaxs(-1, -1);
          mv.visitEnd();
      }
  
+     /**
+      * Generate a writeReplace method that supports serialization
+      */
+     private void generateQuotableMethod() {
+         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL,
+                                           NAME_METHOD_QUOTED, DESCR_METHOD_QUOTED,
+                                           null, null);
+ 
+         mv.visitVarInsn(ALOAD, 0);
+         mv.visitFieldInsn(GETFIELD, lambdaClassName, quotedInstanceFieldName, quotedInstanceFieldDesc);
+         mv.visitInsn(ARETURN);
+ 
+         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
+         mv.visitMaxs(-1, -1);
+         mv.visitEnd();
+     }
+ 
      /**
       * Generate a readObject/writeObject method that is hostile to serialization
       */
      private void generateSerializationHostileMethods() {
          MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,

*** 510,11 ***
                  visitInsn(DUP);
              }
              if (useImplMethodHandle) {
                  visitLdcInsn(implMethodCondy);
              }
!             for (int i = 0; i < argNames.length; i++) {
                  visitVarInsn(ALOAD, 0);
                  visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
              }
  
              convertArgumentTypes(methodType);
--- 623,11 ---
                  visitInsn(DUP);
              }
              if (useImplMethodHandle) {
                  visitLdcInsn(implMethodCondy);
              }
!             for (int i = 0; i < argNames.length - reflectiveCaptureCount(); i++) {
                  visitVarInsn(ALOAD, 0);
                  visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
              }
  
              convertArgumentTypes(methodType);

*** 545,11 ***
          }
  
          private void convertArgumentTypes(MethodType samType) {
              int lvIndex = 0;
              int samParametersLength = samType.parameterCount();
!             int captureArity = factoryType.parameterCount();
              for (int i = 0; i < samParametersLength; i++) {
                  Class<?> argType = samType.parameterType(i);
                  visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
                  lvIndex += getParameterSize(argType);
                  convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
--- 658,11 ---
          }
  
          private void convertArgumentTypes(MethodType samType) {
              int lvIndex = 0;
              int samParametersLength = samType.parameterCount();
!             int captureArity = factoryType.parameterCount() - reflectiveCaptureCount();
              for (int i = 0; i < samParametersLength; i++) {
                  Class<?> argType = samType.parameterType(i);
                  visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
                  lvIndex += getParameterSize(argType);
                  convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));

*** 604,6 ***
--- 717,10 ---
          } else {
              return 4;
          }
      }
  
+     private static Quoted makeQuoted(String opText, Object[] args) {
+         FuncOp op = (FuncOp)OpParser.fromStringOfFuncOp(opText);
+         return (Quoted)Interpreter.invoke(Lookup.IMPL_LOOKUP, op, args);
+     }
  }
< prev index next >