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

Print this page
rev 17253 : imported patch 8183131.patch
rev 17240 : Dump classes from LambdaFormBuilder is triggered using
MethodHandleStatics.DUMP_CLASS_FILES. Class names are
extended by the LF invoker name (which should be unique)
when debugging (dumping triggers debugging).
rev 17235 : Add support for Q-types to lambda forms
Note: support is optional, and can be enabled using the flag:
-Dvalhalla.enableValueLambdaForms=true


  66     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
  67         String invokerName = form.lambdaName();
  68         int p = invokerName.indexOf('.');
  69         boolean overrideNames = p != -1;
  70         String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName;
  71         String className = overrideNames ?
  72                 CLASS_PREFIX + invokerName.substring(0, p) :
  73                 CLASS_PREFIX + DEFAULT_CLASS;
  74         if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
  75             // When DUMP_CLASS_FILES is true methodName will have a unique id
  76             className = className + "_" + methodName;
  77         }
  78         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
  79                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
  80                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
  81     }
  82 
  83     LambdaFormCodeBuilder builder;
  84     LambdaForm lambdaForm;
  85     MethodType invokerType;


  86 
  87     LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) {
  88         this.builder = builder;
  89         this.lambdaForm = lambdaForm;
  90         this.invokerType = invokerType;















  91     }
  92 
  93     void generateLambdaFormBody() {
  94         // iterate over the form's names, generating bytecode instructions for each
  95         // start iterating at the first name following the arguments
  96         Name onStack = null;
  97         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
  98             Name name = lambdaForm.names[i];
  99 
 100             if (onStack != null && onStack.type != V_TYPE) {
 101                 // non-void: actually assign
 102                 builder.store(fromBasicType(onStack.type), onStack.index());
 103             }
 104             onStack = name;  // unless otherwise modified below
 105             MemberName member = name.function.member();
 106             if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) {
 107                 emitStaticInvoke(member, name);
 108             } else {
 109                 emitInvoke(name);
 110             }
 111         }
 112         emitReturn(onStack);
 113     }
 114 
 115     /**
 116      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 117      */
 118     private void emitReturn(Name onStack) {
 119         // return statement
 120         Class<?> rclass = invokerType.returnType();
 121         BasicType rtype = lambdaForm.returnType();
 122         assert(rtype == basicType(rclass));  // must agree
 123         if (rtype == V_TYPE) {
 124             // void
 125             builder.return_();
 126             // it doesn't matter what rclass is; the JVM will discard any value
 127         } else {
 128             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 129 
 130             // put return value on the stack if it is not already there
 131             if (rn != onStack) {
 132                 builder.load(lambdaForm.result);
 133             }
 134 
 135             emitImplicitConversion(rtype, rclass, rn);
 136 
 137             // generate actual return statement
 138             builder.return_(fromBasicType(rtype));
 139         }
 140     }
 141 
 142     /**
 143      * Emit an implicit conversion for an argument which must be of the given pclass.
 144      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 145      *
 146      * @param ptype type of value present on stack
 147      * @param pclass type of value required on stack
 148      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 149      */
 150     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 151         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 152         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)


 162                 return;
 163             case I_TYPE:
 164                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 165                     builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass)));
 166                 return;
 167             case Q_TYPE:
 168                 if (!MinimalValueTypes_1_0.isValueType(pclass)) {
 169                     builder.vbox(Object.class);
 170                     return;
 171                 }
 172                 assert pclass == arg.getClass();
 173                 return; //assume they are equal
 174         }
 175         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 176     }
 177 
 178     private void emitReferenceCast(Class<?> cls, Object arg) {
 179         Name writeBack = null;  // local to write back result
 180         if (arg instanceof Name) {
 181             Name n = (Name) arg;
 182             if (cls.isAssignableFrom(builder.typeOfLocal(n.index())))
 183                 return;  // this cast was already performed
 184             if (lambdaForm.useCount(n) > 1) {
 185                 // This guy gets used more than once.
 186                 writeBack = n;
 187             }
 188         }
 189         if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) {
 190             builder.checkcast(cls);
 191         } else {
 192             builder.ldc(cls)
 193                     .checkcast(Class.class)
 194                     .swap()
 195                     .invokevirtual(Class.class, "cast", LL_SIG, false);
 196             if (Object[].class.isAssignableFrom(cls))
 197                 builder.checkcast(Object[].class);
 198             else if (PROFILE_LEVEL > 0)
 199                 builder.checkcast(Object.class);
 200         }
 201         if (writeBack != null) {
 202             builder.dup().astore(writeBack.index());
 203         }
 204     }
 205 
 206     /**
 207      * Emit an invoke for the given name, using the MemberName directly.
 208      */
 209     void emitStaticInvoke(MemberName member, Name name) {
 210         assert(member.equals(name.function.member()));
 211         Class<?> defc = member.getDeclaringClass();
 212         String mname = member.getName();
 213         String mtype;
 214         byte refKind = member.getReferenceKind();
 215         if (refKind == REF_invokeSpecial) {
 216             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 217             assert(member.canBeStaticallyBound()) : member;
 218             refKind = REF_invokeVirtual;
 219         }
 220 
 221         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 222 


 263     private void emitPushArguments(Name args) {
 264         emitPushArguments(args, 0);
 265     }
 266 
 267     private void emitPushArguments(Name args, int start) {
 268         for (int i = start; i < args.arguments.length; i++) {
 269             emitPushArgument(args, i);
 270         }
 271     }
 272 
 273     private void emitPushArgument(Name name, int paramIndex) {
 274         Object arg = name.arguments[paramIndex];
 275         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
 276         emitPushArgument(ptype, arg);
 277     }
 278 
 279     private void emitPushArgument(Class<?> ptype, Object arg) {
 280         BasicType bptype = basicType(ptype);
 281         if (arg instanceof Name) {
 282             Name n = (Name) arg;
 283             builder.load(fromBasicType(n.type), n.index());
 284             emitImplicitConversion(n.type, ptype, n);
 285         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
 286             builder.ldc(arg);
 287         } else {
 288             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
 289                 builder.ldc(arg);
 290             } else {
 291                 builder.ldc(arg);
 292                 emitImplicitConversion(L_TYPE, ptype, arg);
 293             }
 294         }
 295     }
 296 
 297     TypeTag fromBasicType(BasicType type) {
 298         switch (type) {
 299             case I_TYPE:  return TypeTag.I;
 300             case J_TYPE:  return TypeTag.J;
 301             case F_TYPE:  return TypeTag.F;
 302             case D_TYPE:  return TypeTag.D;
 303             case L_TYPE:  return TypeTag.A;




  66     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
  67         String invokerName = form.lambdaName();
  68         int p = invokerName.indexOf('.');
  69         boolean overrideNames = p != -1;
  70         String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName;
  71         String className = overrideNames ?
  72                 CLASS_PREFIX + invokerName.substring(0, p) :
  73                 CLASS_PREFIX + DEFAULT_CLASS;
  74         if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
  75             // When DUMP_CLASS_FILES is true methodName will have a unique id
  76             className = className + "_" + methodName;
  77         }
  78         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
  79                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
  80                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
  81     }
  82 
  83     LambdaFormCodeBuilder builder;
  84     LambdaForm lambdaForm;
  85     MethodType invokerType;
  86     int maxLocals;
  87     int[] localsMap;
  88 
  89     LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) {
  90         this.builder = builder;
  91         this.lambdaForm = lambdaForm;
  92         this.invokerType = invokerType;
  93         this.maxLocals = lambdaForm.names.length;
  94         this.localsMap = computeLocalsMap(lambdaForm);
  95     }
  96 
  97     static int[] computeLocalsMap(LambdaForm lform) {
  98         int localsMapSize = lform.names.length;
  99         int[] localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 100         for (int i = 0, index = 0; i < localsMap.length; i++) {
 101             localsMap[i] = index;
 102             if (i < lform.names.length) {
 103                 BasicType type = lform.names[i].type();
 104                 index += type.basicTypeSlots();
 105             }
 106         }
 107         return localsMap;
 108     }
 109 
 110     void generateLambdaFormBody() {
 111         // iterate over the form's names, generating bytecode instructions for each
 112         // start iterating at the first name following the arguments
 113         Name onStack = null;
 114         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 115             Name name = lambdaForm.names[i];
 116 
 117             if (onStack != null && onStack.type != V_TYPE) {
 118                 // non-void: actually assign
 119                 builder.store(fromBasicType(onStack.type), localsMap[onStack.index()]);
 120             }
 121             onStack = name;  // unless otherwise modified below
 122             MemberName member = name.function.member();
 123             if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) {
 124                 emitStaticInvoke(member, name);
 125             } else {
 126                 emitInvoke(name);
 127             }
 128         }
 129         emitReturn(onStack);
 130     }
 131 
 132     /**
 133      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 134      */
 135     private void emitReturn(Name onStack) {
 136         // return statement
 137         Class<?> rclass = invokerType.returnType();
 138         BasicType rtype = lambdaForm.returnType();
 139         assert(rtype == basicType(rclass));  // must agree
 140         if (rtype == V_TYPE) {
 141             // void
 142             builder.return_();
 143             // it doesn't matter what rclass is; the JVM will discard any value
 144         } else {
 145             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 146 
 147             // put return value on the stack if it is not already there
 148             if (rn != onStack) {
 149                 builder.load(localsMap[lambdaForm.result]);
 150             }
 151 
 152             emitImplicitConversion(rtype, rclass, rn);
 153 
 154             // generate actual return statement
 155             builder.return_(fromBasicType(rtype));
 156         }
 157     }
 158 
 159     /**
 160      * Emit an implicit conversion for an argument which must be of the given pclass.
 161      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 162      *
 163      * @param ptype type of value present on stack
 164      * @param pclass type of value required on stack
 165      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 166      */
 167     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 168         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 169         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)


 179                 return;
 180             case I_TYPE:
 181                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 182                     builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass)));
 183                 return;
 184             case Q_TYPE:
 185                 if (!MinimalValueTypes_1_0.isValueType(pclass)) {
 186                     builder.vbox(Object.class);
 187                     return;
 188                 }
 189                 assert pclass == arg.getClass();
 190                 return; //assume they are equal
 191         }
 192         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 193     }
 194 
 195     private void emitReferenceCast(Class<?> cls, Object arg) {
 196         Name writeBack = null;  // local to write back result
 197         if (arg instanceof Name) {
 198             Name n = (Name) arg;
 199             if (cls.isAssignableFrom(builder.typeOfLocal(localsMap[n.index()])))
 200                 return;  // this cast was already performed
 201             if (lambdaForm.useCount(n) > 1) {
 202                 // This guy gets used more than once.
 203                 writeBack = n;
 204             }
 205         }
 206         if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) {
 207             builder.checkcast(cls);
 208         } else {
 209             builder.ldc(cls)
 210                     .checkcast(Class.class)
 211                     .swap()
 212                     .invokevirtual(Class.class, "cast", LL_SIG, false);
 213             if (Object[].class.isAssignableFrom(cls))
 214                 builder.checkcast(Object[].class);
 215             else if (PROFILE_LEVEL > 0)
 216                 builder.checkcast(Object.class);
 217         }
 218         if (writeBack != null) {
 219             builder.dup().astore(localsMap[writeBack.index()]);
 220         }
 221     }
 222 
 223     /**
 224      * Emit an invoke for the given name, using the MemberName directly.
 225      */
 226     void emitStaticInvoke(MemberName member, Name name) {
 227         assert(member.equals(name.function.member()));
 228         Class<?> defc = member.getDeclaringClass();
 229         String mname = member.getName();
 230         String mtype;
 231         byte refKind = member.getReferenceKind();
 232         if (refKind == REF_invokeSpecial) {
 233             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 234             assert(member.canBeStaticallyBound()) : member;
 235             refKind = REF_invokeVirtual;
 236         }
 237 
 238         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 239 


 280     private void emitPushArguments(Name args) {
 281         emitPushArguments(args, 0);
 282     }
 283 
 284     private void emitPushArguments(Name args, int start) {
 285         for (int i = start; i < args.arguments.length; i++) {
 286             emitPushArgument(args, i);
 287         }
 288     }
 289 
 290     private void emitPushArgument(Name name, int paramIndex) {
 291         Object arg = name.arguments[paramIndex];
 292         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
 293         emitPushArgument(ptype, arg);
 294     }
 295 
 296     private void emitPushArgument(Class<?> ptype, Object arg) {
 297         BasicType bptype = basicType(ptype);
 298         if (arg instanceof Name) {
 299             Name n = (Name) arg;
 300             builder.load(fromBasicType(n.type), localsMap[n.index()]);
 301             emitImplicitConversion(n.type, ptype, n);
 302         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
 303             builder.ldc(arg);
 304         } else {
 305             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
 306                 builder.ldc(arg);
 307             } else {
 308                 builder.ldc(arg);
 309                 emitImplicitConversion(L_TYPE, ptype, arg);
 310             }
 311         }
 312     }
 313 
 314     TypeTag fromBasicType(BasicType type) {
 315         switch (type) {
 316             case I_TYPE:  return TypeTag.I;
 317             case J_TYPE:  return TypeTag.J;
 318             case F_TYPE:  return TypeTag.F;
 319             case D_TYPE:  return TypeTag.D;
 320             case L_TYPE:  return TypeTag.A;