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

Print this page
rev 17257 : imported patch 8183130.patch
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


   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.experimental.bytecode.AnnotationsBuilder;
  29 import jdk.experimental.bytecode.MacroCodeBuilder.FieldAccessKind;
  30 import jdk.experimental.bytecode.MacroCodeBuilder.InvocationKind;
  31 import jdk.experimental.bytecode.MethodBuilder;
  32 import jdk.experimental.bytecode.TypeTag;
  33 import jdk.experimental.value.MethodHandleBuilder;
  34 import sun.invoke.util.VerifyType;
  35 import sun.invoke.util.Wrapper;
  36 import valhalla.shady.MinimalValueTypes_1_0;
  37 
  38 import java.lang.invoke.LambdaForm.BasicType;
  39 import java.lang.invoke.LambdaForm.Name;
  40 import java.lang.invoke.MethodHandles.Lookup;


  41 
  42 import static java.lang.invoke.LambdaForm.BasicType.L_TYPE;
  43 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE;
  44 import static java.lang.invoke.LambdaForm.BasicType.basicType;
  45 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getField;
  46 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
  47 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeInterface;
  48 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeSpecial;
  49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
  51 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putField;
  52 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;

  53 import static java.lang.invoke.MethodHandleStatics.PROFILE_LEVEL;
  54 import static java.lang.invoke.MethodHandleStatics.newInternalError;

  55 
  56 /**
  57  * Utility class for spinning classfiles associated with lambda forms.
  58  */
  59 class LambdaFormBuilder extends MethodHandleBuilder {
  60 
  61     private static final String OBJ     = "java/lang/Object";
  62     private static final String CLASS_PREFIX   = "java/lang/invoke/LambdaForm$Value$";
  63     private static final String DEFAULT_CLASS  = "MH";
  64     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  65 



  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;


 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_();


 243         // invocation
 244         if (member.isMethod()) {
 245             mtype = member.getMethodType().toMethodDescriptorString();
 246             builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype,
 247                                member.getDeclaringClass().isInterface());
 248         } else {
 249             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 250             builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype);
 251         }
 252         // Issue a type assertion for the result, so we can avoid casts later.
 253         if (name.type == L_TYPE) {
 254             Class<?> rtype = member.getInvocationType().returnType();
 255             assert(!rtype.isPrimitive());
 256         }
 257     }
 258 
 259     /**
 260      * Emit an invoke for the given name.
 261      */
 262     void emitInvoke(Name name) {
 263         //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 264         if (true) {
 265             // push receiver
 266             MethodHandle target = name.function.resolvedHandle();
 267             assert(target != null) : name.exprString();
 268             builder.ldc(target);
 269             emitReferenceCast(MethodHandle.class, target);
 270         }
 271 
 272         // push arguments
 273         emitPushArguments(name);
 274 
 275         // invocation
 276         MethodType type = name.function.methodType();
 277         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 278     }
 279 
 280     private void emitPushArguments(Name args) {
 281         emitPushArguments(args, 0);
 282     }
 283 


 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;
 321             case V_TYPE:  return TypeTag.V;
 322             case Q_TYPE:  return TypeTag.Q;
 323             default:
 324                 throw new InternalError("unknown type: " + type);
 325         }
 326     }
 327 




 328     InvocationKind invKindFromRefKind(int refKind) {
 329         switch (refKind) {
 330             case REF_invokeVirtual:      return InvocationKind.INVOKEVIRTUAL;
 331             case REF_invokeStatic:       return InvocationKind.INVOKESTATIC;
 332             case REF_invokeSpecial:      return InvocationKind.INVOKESPECIAL;
 333             case REF_invokeInterface:    return InvocationKind.INVOKEINTERFACE;
 334         }
 335         throw new InternalError("refKind="+refKind);
 336     }
 337 
 338     FieldAccessKind fieldKindFromRefKind(int refKind) {
 339         switch (refKind) {
 340             case REF_getField:
 341             case REF_putField:            return FieldAccessKind.INSTANCE;
 342             case REF_getStatic:
 343             case REF_putStatic:          return FieldAccessKind.STATIC;
 344         }
 345         throw new InternalError("refKind="+refKind);
 346     }
 347 
 348     static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder {



 349         public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) {
 350             super(methodBuilder);
 351             if (form.forceInline) {
 352                 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;");
 353             }
 354             methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;")
 355                     .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;");
 356         }
 357 
 358         Class<?> typeOfLocal(int index) {
 359             return typeHelper.symbol(state.locals.get(index));
 360         }





















































































































































































 361     }
 362 }


   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.experimental.bytecode.*;
  29 import jdk.experimental.bytecode.MacroCodeBuilder.FieldAccessKind;
  30 import jdk.experimental.bytecode.MacroCodeBuilder.InvocationKind;


  31 import jdk.experimental.value.MethodHandleBuilder;
  32 import sun.invoke.util.VerifyType;
  33 import sun.invoke.util.Wrapper;
  34 import valhalla.shady.MinimalValueTypes_1_0;
  35 
  36 import java.lang.invoke.LambdaForm.BasicType;
  37 import java.lang.invoke.LambdaForm.Name;
  38 import java.lang.invoke.MethodHandles.Lookup;
  39 import java.util.Arrays;
  40 import java.util.stream.Stream;
  41 
  42 import static java.lang.invoke.LambdaForm.BasicType.L_TYPE;
  43 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE;
  44 import static java.lang.invoke.LambdaForm.BasicType.basicType;
  45 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getField;
  46 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
  47 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeInterface;
  48 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeSpecial;
  49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
  51 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putField;
  52 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
  53 import static java.lang.invoke.MethodHandleStatics.PROFILE_GWT;
  54 import static java.lang.invoke.MethodHandleStatics.PROFILE_LEVEL;
  55 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  56 import static jdk.experimental.bytecode.MacroCodeBuilder.CondKind.NE;
  57 
  58 /**
  59  * Utility class for spinning classfiles associated with lambda forms.
  60  */
  61 class LambdaFormBuilder extends MethodHandleBuilder {
  62 
  63     private static final String OBJ     = "java/lang/Object";
  64     private static final String CLASS_PREFIX   = "java/lang/invoke/LambdaForm$Value$";
  65     private static final String DEFAULT_CLASS  = "MH";
  66     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  67 
  68     private static final String MH           = "java/lang/invoke/MethodHandle";
  69     private static final String MHARY2       = "[[L" + MH + ";";
  70 
  71     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
  72         String invokerName = form.lambdaName();
  73         int p = invokerName.indexOf('.');
  74         boolean overrideNames = p != -1;
  75         String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName;
  76         String className = overrideNames ?
  77                 CLASS_PREFIX + invokerName.substring(0, p) :
  78                 CLASS_PREFIX + DEFAULT_CLASS;
  79         if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
  80             // When DUMP_CLASS_FILES is true methodName will have a unique id
  81             className = className + "_" + methodName;
  82         }
  83         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
  84                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
  85                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
  86     }
  87 
  88     LambdaFormCodeBuilder builder;
  89     LambdaForm lambdaForm;
  90     MethodType invokerType;


 108                 BasicType type = lform.names[i].type();
 109                 index += type.basicTypeSlots();
 110             }
 111         }
 112         return localsMap;
 113     }
 114 
 115     void generateLambdaFormBody() {
 116         // iterate over the form's names, generating bytecode instructions for each
 117         // start iterating at the first name following the arguments
 118         Name onStack = null;
 119         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 120             Name name = lambdaForm.names[i];
 121 
 122             if (onStack != null && onStack.type != V_TYPE) {
 123                 // non-void: actually assign
 124                 builder.store(fromBasicType(onStack.type), localsMap[onStack.index()]);
 125             }
 126             onStack = name;  // unless otherwise modified below
 127             MemberName member = name.function.member();
 128             MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
 129             switch (intr) {
 130                  case SELECT_ALTERNATIVE: {
 131                      assert lambdaForm.isSelectAlternative(i);
 132                      if (PROFILE_GWT) {
 133                          assert(name.arguments[0] instanceof Name &&
 134                                  ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
 135                          builder.method().withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, InvokerBytecodeGenerator.INJECTEDPROFILE_SIG);
 136                      }
 137                      onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
 138                      i++;  // skip MH.invokeBasic of the selectAlternative result
 139                      continue;
 140 
 141                  }
 142                 // TODO: case GUARD_WITH_CATCH:
 143                 // TODO: case TRY_FINALLY:
 144 
 145                 case LOOP: {
 146                     assert lambdaForm.isLoop(i);
 147                     onStack = emitLoop(i);
 148                     i += 2; // jump to the end of the LOOP idiom
 149                     continue;
 150                 }
 151                 case IDENTITY: {
 152                     assert (name.arguments.length == 1);
 153                     emitPushArguments(name, 0);
 154                     continue;
 155                 }
 156                 case ZERO: {
 157                     assert (name.arguments.length == 0);
 158                     assert (name.type != BasicType.Q_TYPE);
 159                     builder.ldc(name.type.basicTypeWrapper().zero());
 160                     continue;
 161                 }
 162                 case NONE: {
 163                     // no intrinsic associated
 164                     break;
 165                 }
 166                 // TODO: case NEW_ARRAY:
 167                 // TODO: case ARRAY_LOAD:
 168                 // TODO: case ARRAY_STORE:
 169                 // TODO: case ARRAY_LENGTH:
 170                 default: {
 171                     throw newInternalError("Unknown intrinsic: "+intr);
 172                 }
 173             }
 174             if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) {
 175                 emitStaticInvoke(member, name);
 176             } else {
 177                 emitInvoke(name);
 178             }
 179         }
 180         emitReturn(onStack);
 181     }
 182 
 183     /**
 184      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 185      */
 186     private void emitReturn(Name onStack) {
 187         // return statement
 188         Class<?> rclass = invokerType.returnType();
 189         BasicType rtype = lambdaForm.returnType();
 190         assert(rtype == basicType(rclass));  // must agree
 191         if (rtype == V_TYPE) {
 192             // void
 193             builder.return_();


 294         // invocation
 295         if (member.isMethod()) {
 296             mtype = member.getMethodType().toMethodDescriptorString();
 297             builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype,
 298                                member.getDeclaringClass().isInterface());
 299         } else {
 300             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 301             builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype);
 302         }
 303         // Issue a type assertion for the result, so we can avoid casts later.
 304         if (name.type == L_TYPE) {
 305             Class<?> rtype = member.getInvocationType().returnType();
 306             assert(!rtype.isPrimitive());
 307         }
 308     }
 309 
 310     /**
 311      * Emit an invoke for the given name.
 312      */
 313     void emitInvoke(Name name) {

 314         if (true) {
 315             // push receiver
 316             MethodHandle target = name.function.resolvedHandle();
 317             assert(target != null) : name.exprString();
 318             builder.ldc(target);
 319             emitReferenceCast(MethodHandle.class, target);
 320         }
 321 
 322         // push arguments
 323         emitPushArguments(name);
 324 
 325         // invocation
 326         MethodType type = name.function.methodType();
 327         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 328     }
 329 
 330     private void emitPushArguments(Name args) {
 331         emitPushArguments(args, 0);
 332     }
 333 


 358                 builder.ldc(arg);
 359                 emitImplicitConversion(L_TYPE, ptype, arg);
 360             }
 361         }
 362     }
 363 
 364     TypeTag fromBasicType(BasicType type) {
 365         switch (type) {
 366             case I_TYPE:  return TypeTag.I;
 367             case J_TYPE:  return TypeTag.J;
 368             case F_TYPE:  return TypeTag.F;
 369             case D_TYPE:  return TypeTag.D;
 370             case L_TYPE:  return TypeTag.A;
 371             case V_TYPE:  return TypeTag.V;
 372             case Q_TYPE:  return TypeTag.Q;
 373             default:
 374                 throw new InternalError("unknown type: " + type);
 375         }
 376     }
 377 
 378     TypeTag fromClass(Class<?> cls) {
 379         return fromBasicType(BasicType.basicType(cls));
 380     }
 381 
 382     InvocationKind invKindFromRefKind(int refKind) {
 383         switch (refKind) {
 384             case REF_invokeVirtual:      return InvocationKind.INVOKEVIRTUAL;
 385             case REF_invokeStatic:       return InvocationKind.INVOKESTATIC;
 386             case REF_invokeSpecial:      return InvocationKind.INVOKESPECIAL;
 387             case REF_invokeInterface:    return InvocationKind.INVOKEINTERFACE;
 388         }
 389         throw new InternalError("refKind="+refKind);
 390     }
 391 
 392     FieldAccessKind fieldKindFromRefKind(int refKind) {
 393         switch (refKind) {
 394             case REF_getField:
 395             case REF_putField:            return FieldAccessKind.INSTANCE;
 396             case REF_getStatic:
 397             case REF_putStatic:          return FieldAccessKind.STATIC;
 398         }
 399         throw new InternalError("refKind="+refKind);
 400     }
 401 
 402     static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder {
 403 
 404         private MethodBuilder<Class<?>, String, byte[]> methodBuilder;
 405 
 406         public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) {
 407             super(methodBuilder);
 408             if (form.forceInline) {
 409                 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;");
 410             }
 411             methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;")
 412                     .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;");
 413         }
 414 
 415         Class<?> typeOfLocal(int index) {
 416             return typeHelper.symbol(state.locals.get(index));
 417         }
 418 
 419         MethodBuilder<Class<?>, String, byte[]> method() {
 420             return methodBuilder;
 421         }
 422     }
 423 
 424     private Name emitLoop(int pos) {
 425         Name args    = lambdaForm.names[pos];
 426         Name invoker = lambdaForm.names[pos+1];
 427         Name result  = lambdaForm.names[pos+2];
 428 
 429         // extract clause and loop-local state types
 430         // find the type info in the loop invocation
 431         BasicType[] loopClauseTypes = (BasicType[]) invoker.arguments[0];
 432         Class<?>[] loopLocalStateTypes = Stream.of(loopClauseTypes).
 433                 filter(bt -> bt != BasicType.V_TYPE).map(BasicType::basicTypeClass).toArray(Class<?>[]::new);
 434 
 435         Class<?>[] localTypes = new Class<?>[loopLocalStateTypes.length + 1];
 436         localTypes[0] = MethodHandleImpl.LoopClauses.class;
 437         System.arraycopy(loopLocalStateTypes, 0, localTypes, 1, loopLocalStateTypes.length);
 438 
 439         final int clauseDataIndex     = extendLocalsMap(localTypes);
 440         final int firstLoopStateIndex = clauseDataIndex + 1;
 441         maxLocals += loopLocalStateTypes.length + 1;
 442 
 443         Class<?> returnType = result.function.resolvedHandle().type().returnType();
 444         MethodType loopType = args.function.resolvedHandle().type()
 445                 .dropParameterTypes(0,1)
 446                 .changeReturnType(returnType);
 447         MethodType loopHandleType = loopType.insertParameterTypes(0, loopLocalStateTypes);
 448         MethodType predType = loopHandleType.changeReturnType(boolean.class);
 449         MethodType finiType = loopHandleType;
 450 
 451         final int nClauses = loopClauseTypes.length;
 452 
 453         // indices to invoker arguments to load method handle arrays
 454         final int inits = 1;
 455         final int steps = 2;
 456         final int preds = 3;
 457         final int finis = 4;
 458 
 459         // PREINIT:
 460         emitPushArgument(MethodHandleImpl.LoopClauses.class, invoker.arguments[1]);
 461         builder.getfield(MethodHandleImpl.LoopClauses.class, "clauses", MHARY2);
 462         emitAstoreInsn(clauseDataIndex);
 463 
 464         // INIT:
 465         for (int c = 0, state = 0; c < nClauses; ++c) {
 466             MethodType cInitType = loopType.changeReturnType(loopClauseTypes[c].basicTypeClass());
 467             emitLoopHandleInvoke(inits, c, args, false, cInitType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 468             if (cInitType.returnType() != void.class) {
 469                 builder.store(fromClass(cInitType.returnType()), localsMap[firstLoopStateIndex + state]);
 470                 ++state;
 471             }
 472         }
 473 
 474         // LOOP:
 475         builder.label("LOOP");
 476 
 477         String val = null;
 478         for (int c = 0, s = 0; c < nClauses; ++c) {
 479             MethodType stepType = loopHandleType.changeReturnType(loopClauseTypes[c].basicTypeClass());
 480             boolean isVoid = (stepType.returnType() == void.class);
 481 
 482             // invoke loop step
 483             emitLoopHandleInvoke(steps, c, args, true, stepType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 484             if (!isVoid) {
 485                 builder.store(fromClass(stepType.returnType()), localsMap[firstLoopStateIndex + s]);
 486                 ++s;
 487             }
 488 
 489             // invoke loop predicate
 490             emitLoopHandleInvoke(preds, c, args, true, predType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 491             builder.emitCondJump(Opcode.IFEQ, NE, "NEXT_" + c);
 492 
 493             // invoke fini
 494             emitLoopHandleInvoke(finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 495             builder.goto_("DONE");
 496 
 497             // this is the beginning of the next loop clause
 498             builder.label("NEXT_" + c);
 499         }
 500         builder.goto_("LOOP");
 501 
 502 
 503         builder.label("DONE");
 504 
 505         return result;
 506     }
 507 
 508     private void emitLoopHandleInvoke(int handles, int clause, Name args, boolean pushLocalState,
 509                                       MethodType type, Class<?>[] loopLocalStateTypes, int clauseDataSlot,
 510                                       int firstLoopStateSlot) {
 511         // load handle for clause
 512         builder.load(TypeTag.A, localsMap[clauseDataSlot])
 513                .ldc(handles - 1)
 514                .aaload()
 515                .ldc(clause)
 516                .aaload();
 517 
 518         // load loop state (preceding the other arguments)
 519         if (pushLocalState) {
 520             for (int s = 0; s < loopLocalStateTypes.length; ++s) {
 521                 builder.load(fromClass(loopLocalStateTypes[s]), localsMap[firstLoopStateSlot + s]);
 522             }
 523         }
 524         // load loop args (skip 0: method handle)
 525         emitPushArguments(args, 1);
 526         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.toMethodDescriptorString(), false);
 527     }
 528 
 529     /**
 530      * Emit bytecode for the selectAlternative idiom.
 531      *
 532      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
 533      * <blockquote><pre>{@code
 534      *   Lambda(a0:L,a1:I)=>{
 535      *     t2:I=foo.test(a1:I);
 536      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
 537      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
 538      * }</pre></blockquote>
 539      */
 540     private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
 541         assert InvokerBytecodeGenerator.isStaticallyInvocable(invokeBasicName);
 542 
 543         Name receiver = (Name) invokeBasicName.arguments[0];
 544 
 545         int pos = invokeBasicName.index();
 546         String L_fallback = "L_fallback_" + pos;
 547         String L_done     = "L_done_"+ pos;
 548 
 549         // load test result
 550         emitPushArgument(selectAlternativeName, 0);
 551 
 552         // if_icmpne L_fallback
 553         builder.emitCondJump(Opcode.IFEQ, NE, L_fallback);
 554 
 555         // invoke selectAlternativeName.arguments[1]
 556         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
 557         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
 558         emitStaticInvoke(invokeBasicName);
 559 
 560         // goto L_done
 561         builder.goto_(L_done);
 562 
 563 
 564 
 565         // L_fallback:
 566         builder.label(L_fallback);
 567 
 568         // invoke selectAlternativeName.arguments[2]
 569         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
 570         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
 571         emitStaticInvoke(invokeBasicName);
 572 
 573         // L_done:
 574         builder.label(L_done);
 575 
 576         return invokeBasicName;  // return what's on stack
 577     }
 578 
 579     private void emitAstoreInsn(int index) {
 580         builder.store(TypeTag.A, localsMap[index]);
 581     }
 582 
 583     void emitStaticInvoke(Name name) {
 584         emitStaticInvoke(name.function.member(), name);
 585     }
 586 
 587     private int extendLocalsMap(Class<?>[] types) {
 588         int firstSlot = localsMap.length - 1;
 589         localsMap = Arrays.copyOf(localsMap, localsMap.length + types.length);
 590         int index = localsMap[firstSlot - 1] + 1;
 591         int lastSlots = 0;
 592         for (int i = 0; i < types.length; ++i) {
 593             localsMap[firstSlot + i] = index;
 594             lastSlots = BasicType.basicType(types[i]).basicTypeSlots();
 595             index += lastSlots;
 596         }
 597         localsMap[localsMap.length - 1] = index - lastSlots;
 598         return firstSlot;
 599     }
 600 }