< prev index next >

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

Print this page
@@ -32,13 +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.LinkedHashSet;
- import java.util.Set;
+ 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 +113,24 @@
  
          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);
+         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 +191,16 @@
                                         MethodType interfaceMethodType,
                                         MethodHandle implementation,
                                         MethodType dynamicMethodType,
                                         boolean isSerializable,
                                         Class<?>[] altInterfaces,
-                                        MethodType[] altMethods)
+                                        MethodType[] altMethods,
+                                        MethodHandle reflectiveField)
              throws LambdaConversionException {
          super(caller, factoryType, interfaceMethodName, interfaceMethodType,
                implementation, dynamicMethodType,
-               isSerializable, altInterfaces, altMethods);
+               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 +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
-             var classdata = useImplMethodHandle? implementation : null;
+             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 +623,11 @@
                  visitInsn(DUP);
              }
              if (useImplMethodHandle) {
                  visitLdcInsn(implMethodCondy);
              }
-             for (int i = 0; i < argNames.length; i++) {
+             for (int i = 0; i < argNames.length - reflectiveCaptureCount(); i++) {
                  visitVarInsn(ALOAD, 0);
                  visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
              }
  
              convertArgumentTypes(methodType);

@@ -545,11 +658,11 @@
          }
  
          private void convertArgumentTypes(MethodType samType) {
              int lvIndex = 0;
              int samParametersLength = samType.parameterCount();
-             int captureArity = factoryType.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 >