1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   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 jdk.internal.org.objectweb.asm.Label;
  33 import jdk.internal.org.objectweb.asm.Opcodes;
  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 import java.util.Arrays;
  42 import java.util.stream.Stream;
  43 
  44 import static java.lang.invoke.InvokerBytecodeGenerator.isStaticallyInvocable;
  45 import static java.lang.invoke.InvokerBytecodeGenerator.isStaticallyNameable;
  46 import static java.lang.invoke.LambdaForm.BasicType.L_TYPE;
  47 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE;
  48 import static java.lang.invoke.LambdaForm.BasicType.basicType;
  49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getField;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
  51 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeInterface;
  52 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeSpecial;
  53 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  54 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
  55 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putField;
  56 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
  57 import static java.lang.invoke.MethodHandleStatics.PROFILE_GWT;
  58 import static java.lang.invoke.MethodHandleStatics.PROFILE_LEVEL;
  59 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  60 import static jdk.experimental.bytecode.MacroCodeBuilder.CondKind.NE;
  61 
  62 /**
  63  * Utility class for spinning classfiles associated with lambda forms.
  64  */
  65 class LambdaFormBuilder extends MethodHandleBuilder {
  66 
  67     private static final String OBJ     = "java/lang/Object";
  68     private static final String CLASS_PREFIX   = "java/lang/invoke/LambdaForm$Value$";
  69     private static final String DEFAULT_CLASS  = "MH";
  70     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  71 
  72     private static final String MH           = "java/lang/invoke/MethodHandle";
  73     private static final String MHARY2       = "[[L" + MH + ";";
  74 
  75     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
  76         String invokerName = form.lambdaName();
  77         int p = invokerName.indexOf('.');
  78         boolean overrideNames = p != -1;
  79         String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName;
  80         String className = overrideNames ?
  81                 CLASS_PREFIX + invokerName.substring(0, p) :
  82                 CLASS_PREFIX + DEFAULT_CLASS;
  83         if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
  84             // When DUMP_CLASS_FILES is true methodName will have a unique id
  85             className = className + "_" + methodName;
  86         }
  87         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
  88                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
  89                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
  90     }
  91 
  92     LambdaFormCodeBuilder builder;
  93     LambdaForm lambdaForm;
  94     MethodType invokerType;
  95     int maxLocals;
  96     int[] localsMap;
  97 
  98     LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) {
  99         this.builder = builder;
 100         this.lambdaForm = lambdaForm;
 101         this.invokerType = invokerType;
 102         this.maxLocals = lambdaForm.names.length;
 103         this.localsMap = computeLocalsMap(lambdaForm);
 104     }
 105 
 106     static int[] computeLocalsMap(LambdaForm lform) {
 107         int localsMapSize = lform.names.length;
 108         int[] localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 109         for (int i = 0, index = 0; i < localsMap.length; i++) {
 110             localsMap[i] = index;
 111             if (i < lform.names.length) {
 112                 BasicType type = lform.names[i].type();
 113                 index += type.basicTypeSlots();
 114             }
 115         }
 116         return localsMap;
 117     }
 118     void generateLambdaFormBody() {
 119         // iterate over the form's names, generating bytecode instructions for each
 120         // start iterating at the first name following the arguments
 121         Name onStack = null;
 122         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 123             Name name = lambdaForm.names[i];
 124 
 125             if (onStack != null && onStack.type != V_TYPE) {
 126                 // non-void: actually assign
 127                 builder.store(fromBasicType(onStack.type), localsMap[onStack.index()]);
 128             }
 129             onStack = name;  // unless otherwise modified below
 130             MemberName member = name.function.member();
 131             MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
 132             switch (intr) {
 133                  case SELECT_ALTERNATIVE: {
 134                      assert lambdaForm.isSelectAlternative(i);
 135                      if (PROFILE_GWT) {
 136                          assert(name.arguments[0] instanceof Name &&
 137                                  ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
 138 //                          mv.visitAnnotation(INJECTEDPROFILE_SIG, true);
 139                      }
 140                      onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
 141                      i++;  // skip MH.invokeBasic of the selectAlternative result
 142                      continue;
 143 
 144                  }
 145                 // case GUARD_WITH_CATCH:
 146                 // case TRY_FINALLY:
 147 
 148                 case LOOP: {
 149                     assert lambdaForm.isLoop(i);
 150                     onStack = emitLoop(i);
 151                     i += 2; // jump to the end of the LOOP idiom
 152                     continue;
 153                 }
 154                 case IDENTITY: {
 155                     assert (name.arguments.length == 1);
 156                     emitPushArguments(name, 0);
 157                     continue;
 158                 }
 159                 case ZERO: {
 160                     assert (name.arguments.length == 0);
 161                     assert (name.type != BasicType.Q_TYPE);
 162                     builder.ldc(name.type.basicTypeWrapper().zero());
 163                     continue;
 164                 }
 165                 case NONE: {
 166                     // no intrinsic associated
 167                     break;
 168                 }
 169                 // case NEW_ARRAY: ?
 170                 // case ARRAY_LOAD: -
 171                 // case ARRAY_STORE: -
 172                 // case ARRAY_LENGTH: -
 173                 default: {
 174                     throw newInternalError("Unknown intrinsic: "+intr);
 175                 }
 176             }
 177             if (isStaticallyInvocable(member)) {
 178                 emitStaticInvoke(member, name);
 179             } else {
 180                 emitInvoke(name);
 181             }
 182         }
 183         emitReturn(onStack);
 184     }
 185 
 186     /**
 187      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 188      */
 189     private void emitReturn(Name onStack) {
 190         // return statement
 191         Class<?> rclass = invokerType.returnType();
 192         BasicType rtype = lambdaForm.returnType();
 193         assert(rtype == basicType(rclass));  // must agree
 194         if (rtype == V_TYPE) {
 195             // void
 196             builder.return_();
 197             // it doesn't matter what rclass is; the JVM will discard any value
 198         } else {
 199             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 200 
 201             // put return value on the stack if it is not already there
 202             if (rn != onStack) {
 203                 builder.load(localsMap[lambdaForm.result]);
 204             }
 205 
 206             emitImplicitConversion(rtype, rclass, rn);
 207 
 208             // generate actual return statement
 209             builder.return_(fromBasicType(rtype));
 210         }
 211     }
 212 
 213     /**
 214      * Emit an implicit conversion for an argument which must be of the given pclass.
 215      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 216      *
 217      * @param ptype type of value present on stack
 218      * @param pclass type of value required on stack
 219      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 220      */
 221     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 222         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 223         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 224             return;   // nothing to do
 225         switch (ptype) {
 226             case L_TYPE:
 227                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 228                     if (PROFILE_LEVEL > 0)
 229                         emitReferenceCast(Object.class, arg);
 230                     return;
 231                 }
 232                 emitReferenceCast(pclass, arg);
 233                 return;
 234             case I_TYPE:
 235                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 236                     builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass)));
 237                 return;
 238             case Q_TYPE:
 239                 if (!MinimalValueTypes_1_0.isValueType(pclass)) {
 240                     builder.vbox(Object.class);
 241                     return;
 242                 }
 243                 assert pclass == arg.getClass();
 244                 return; //assume they are equal
 245         }
 246         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 247     }
 248 
 249     private void emitReferenceCast(Class<?> cls, Object arg) {
 250         Name writeBack = null;  // local to write back result
 251         if (arg instanceof Name) {
 252             Name n = (Name) arg;
 253             if (cls.isAssignableFrom(builder.typeOfLocal(localsMap[n.index()])))
 254                 return;  // this cast was already performed
 255             if (lambdaForm.useCount(n) > 1) {
 256                 // This guy gets used more than once.
 257                 writeBack = n;
 258             }
 259         }
 260         if (isStaticallyNameable(cls)) {
 261             builder.checkcast(cls);
 262         } else {
 263             builder.ldc(cls)
 264                     .checkcast(Class.class)
 265                     .swap()
 266                     .invokevirtual(Class.class, "cast", LL_SIG, false);
 267             if (Object[].class.isAssignableFrom(cls))
 268                 builder.checkcast(Object[].class);
 269             else if (PROFILE_LEVEL > 0)
 270                 builder.checkcast(Object.class);
 271         }
 272         if (writeBack != null) {
 273             builder.dup().astore(localsMap[writeBack.index()]);
 274         }
 275     }
 276 
 277     void emitStaticInvoke(Name name) {
 278         emitStaticInvoke(name.function.member(), name);
 279     }
 280 
 281     /**
 282      * Emit an invoke for the given name, using the MemberName directly.
 283      */
 284     void emitStaticInvoke(MemberName member, Name name) {
 285         assert(member.equals(name.function.member()));
 286         Class<?> defc = member.getDeclaringClass();
 287         String mname = member.getName();
 288         String mtype;
 289         byte refKind = member.getReferenceKind();
 290         if (refKind == REF_invokeSpecial) {
 291             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 292             assert(member.canBeStaticallyBound()) : member;
 293             refKind = REF_invokeVirtual;
 294         }
 295 
 296         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 297 
 298         // push arguments
 299         emitPushArguments(name);
 300 
 301         // invocation
 302         if (member.isMethod()) {
 303             mtype = member.getMethodType().toMethodDescriptorString();
 304             builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype,
 305                                member.getDeclaringClass().isInterface());
 306         } else {
 307             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 308             builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype);
 309         }
 310         // Issue a type assertion for the result, so we can avoid casts later.
 311         if (name.type == L_TYPE) {
 312             Class<?> rtype = member.getInvocationType().returnType();
 313             assert(!rtype.isPrimitive());
 314         }
 315     }
 316 
 317     /**
 318      * Emit an invoke for the given name.
 319      */
 320     void emitInvoke(Name name) {
 321         //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 322         if (true) {
 323             // push receiver
 324             MethodHandle target = name.function.resolvedHandle();
 325             assert(target != null) : name.exprString();
 326             builder.ldc(target);
 327             emitReferenceCast(MethodHandle.class, target);
 328         }
 329 
 330         // push arguments
 331         emitPushArguments(name);
 332 
 333         // invocation
 334         MethodType type = name.function.methodType();
 335         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 336     }
 337 
 338     private void emitPushArguments(Name args) {
 339         emitPushArguments(args, 0);
 340     }
 341 
 342     private void emitPushArguments(Name args, int start) {
 343         for (int i = start; i < args.arguments.length; i++) {
 344             emitPushArgument(args, i);
 345         }
 346     }
 347 
 348     private void emitPushArgument(Name name, int paramIndex) {
 349         Object arg = name.arguments[paramIndex];
 350         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
 351         emitPushArgument(ptype, arg);
 352     }
 353 
 354     private void emitPushArgument(Class<?> ptype, Object arg) {
 355         BasicType bptype = basicType(ptype);
 356         if (arg instanceof Name) {
 357             Name n = (Name) arg;
 358             builder.load(fromBasicType(n.type), localsMap[n.index()]);
 359             emitImplicitConversion(n.type, ptype, n);
 360         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
 361             builder.ldc(arg);
 362         } else {
 363             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
 364                 builder.ldc(arg);
 365             } else {
 366                 builder.ldc(arg);
 367                 emitImplicitConversion(L_TYPE, ptype, arg);
 368             }
 369         }
 370     }
 371 
 372     TypeTag fromBasicType(BasicType type) {
 373         switch (type) {
 374             case I_TYPE:  return TypeTag.I;
 375             case J_TYPE:  return TypeTag.J;
 376             case F_TYPE:  return TypeTag.F;
 377             case D_TYPE:  return TypeTag.D;
 378             case L_TYPE:  return TypeTag.A;
 379             case V_TYPE:  return TypeTag.V;
 380             case Q_TYPE:  return TypeTag.Q;
 381             default:
 382                 throw new InternalError("unknown type: " + type);
 383         }
 384     }
 385 
 386     TypeTag fromClass(Class<?> cls) {
 387         return fromBasicType(BasicType.basicType(cls));
 388     }
 389 
 390     InvocationKind invKindFromRefKind(int refKind) {
 391         switch (refKind) {
 392             case REF_invokeVirtual:      return InvocationKind.INVOKEVIRTUAL;
 393             case REF_invokeStatic:       return InvocationKind.INVOKESTATIC;
 394             case REF_invokeSpecial:      return InvocationKind.INVOKESPECIAL;
 395             case REF_invokeInterface:    return InvocationKind.INVOKEINTERFACE;
 396         }
 397         throw new InternalError("refKind="+refKind);
 398     }
 399 
 400     FieldAccessKind fieldKindFromRefKind(int refKind) {
 401         switch (refKind) {
 402             case REF_getField:
 403             case REF_putField:            return FieldAccessKind.INSTANCE;
 404             case REF_getStatic:
 405             case REF_putStatic:          return FieldAccessKind.STATIC;
 406         }
 407         throw new InternalError("refKind="+refKind);
 408     }
 409 
 410     static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder {
 411         public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) {
 412             super(methodBuilder);
 413             if (form.forceInline) {
 414                 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;");
 415             }
 416             methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;")
 417                     .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;");
 418         }
 419 
 420         Class<?> typeOfLocal(int index) {
 421             return typeHelper.symbol(state.locals.get(index));
 422         }
 423     }
 424 
 425     private Name emitLoop(int pos) {
 426         Name args    = lambdaForm.names[pos];
 427         Name invoker = lambdaForm.names[pos+1];
 428         Name result  = lambdaForm.names[pos+2];
 429 
 430         // extract clause and loop-local state types
 431         // find the type info in the loop invocation
 432         BasicType[] loopClauseTypes = (BasicType[]) invoker.arguments[0];
 433         Class<?>[] loopLocalStateTypes = Stream.of(loopClauseTypes).
 434                 filter(bt -> bt != BasicType.V_TYPE).map(BasicType::basicTypeClass).toArray(Class<?>[]::new);
 435 
 436         Class<?>[] localTypes = new Class<?>[loopLocalStateTypes.length + 1];
 437         localTypes[0] = MethodHandleImpl.LoopClauses.class;
 438         System.arraycopy(loopLocalStateTypes, 0, localTypes, 1, loopLocalStateTypes.length);
 439 
 440         final int clauseDataIndex     = extendLocalsMap(localTypes);
 441         final int firstLoopStateIndex = clauseDataIndex + 1;
 442         maxLocals += loopLocalStateTypes.length + 1;
 443 
 444         Class<?> returnType = result.function.resolvedHandle().type().returnType();
 445         MethodType loopType = args.function.resolvedHandle().type()
 446                 .dropParameterTypes(0,1)
 447                 .changeReturnType(returnType);
 448         MethodType loopHandleType = loopType.insertParameterTypes(0, loopLocalStateTypes);
 449         MethodType predType = loopHandleType.changeReturnType(boolean.class);
 450         MethodType finiType = loopHandleType;
 451 
 452         final int nClauses = loopClauseTypes.length;
 453 
 454         // indices to invoker arguments to load method handle arrays
 455         final int inits = 1;
 456         final int steps = 2;
 457         final int preds = 3;
 458         final int finis = 4;
 459 
 460         // PREINIT:
 461         emitPushArgument(MethodHandleImpl.LoopClauses.class, invoker.arguments[1]);
 462         builder.getfield(MethodHandleImpl.LoopClauses.class, "clauses", MHARY2);
 463         emitAstoreInsn(clauseDataIndex);
 464 
 465         // INIT:
 466         for (int c = 0, state = 0; c < nClauses; ++c) {
 467             MethodType cInitType = loopType.changeReturnType(loopClauseTypes[c].basicTypeClass());
 468             emitLoopHandleInvoke(inits, c, args, false, cInitType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 469             if (cInitType.returnType() != void.class) {
 470                 builder.store(fromClass(cInitType.returnType()), localsMap[firstLoopStateIndex + state]);
 471                 ++state;
 472             }
 473         }
 474 
 475         // LOOP:
 476         builder.label("LOOP");
 477 
 478         String val = null;
 479         for (int c = 0, s = 0; c < nClauses; ++c) {
 480             MethodType stepType = loopHandleType.changeReturnType(loopClauseTypes[c].basicTypeClass());
 481             boolean isVoid = (stepType.returnType() == void.class);
 482 
 483             // invoke loop step
 484             emitLoopHandleInvoke(steps, c, args, true, stepType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 485             if (!isVoid) {
 486                 builder.store(fromClass(stepType.returnType()), localsMap[firstLoopStateIndex + s]);
 487                 ++s;
 488             }
 489 
 490             // invoke loop predicate
 491             emitLoopHandleInvoke(preds, c, args, true, predType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 492             builder.emitCondJump(Opcode.IFEQ, NE, "NEXT_" + c);
 493 
 494             // invoke fini
 495             emitLoopHandleInvoke(finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex, firstLoopStateIndex);
 496             builder.goto_("DONE");
 497 
 498             if (finiType.returnType() != void.class) {
 499                 val = builder.state().pop(); // FIXME !!! HACK !!!
 500             }
 501 
 502             // this is the beginning of the next loop clause
 503             builder.label("NEXT_" + c);
 504         }
 505         builder.goto_("LOOP");
 506 
 507         if (finiType.returnType() != void.class) {
 508             builder.state().push(val); // FIXME !!! HACK !!!
 509         }
 510 
 511         builder.label("DONE");
 512 
 513         return result;
 514     }
 515 
 516     private void emitLoopHandleInvoke(int handles, int clause, Name args, boolean pushLocalState,
 517                                       MethodType type, Class<?>[] loopLocalStateTypes, int clauseDataSlot,
 518                                       int firstLoopStateSlot) {
 519         // load handle for clause
 520 //        emitPushClauseArray(clauseDataSlot, handles);
 521         builder.load(TypeTag.A, localsMap[clauseDataSlot])
 522                .ldc(handles - 1)
 523                .aaload()
 524 //        emitIconstInsn(clause);
 525                .ldc(clause)
 526                .aaload();
 527 
 528         // load loop state (preceding the other arguments)
 529         if (pushLocalState) {
 530             for (int s = 0; s < loopLocalStateTypes.length; ++s) {
 531 //                emitLoadInsn(BasicType.basicType(loopLocalStateTypes[s]), firstLoopStateSlot + s);
 532                 builder.load(fromClass(loopLocalStateTypes[s]), localsMap[firstLoopStateSlot + s]);
 533             }
 534         }
 535         // load loop args (skip 0: method handle)
 536         emitPushArguments(args, 1);
 537         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.toMethodDescriptorString(), false);
 538     }
 539 
 540     /**
 541      * Emit bytecode for the selectAlternative idiom.
 542      *
 543      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
 544      * <blockquote><pre>{@code
 545      *   Lambda(a0:L,a1:I)=>{
 546      *     t2:I=foo.test(a1:I);
 547      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
 548      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
 549      * }</pre></blockquote>
 550      */
 551     private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
 552         assert isStaticallyInvocable(invokeBasicName);
 553 
 554         Name receiver = (Name) invokeBasicName.arguments[0];
 555 
 556         int pos = invokeBasicName.index();
 557         String L_fallback = "L_fallback_" + pos;
 558         String L_done     = "L_done_"+ pos;
 559 
 560         // load test result
 561         emitPushArgument(selectAlternativeName, 0);
 562 
 563         // if_icmpne L_fallback
 564         builder.emitCondJump(Opcode.IFEQ, NE, L_fallback);
 565 
 566         // invoke selectAlternativeName.arguments[1]
 567         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
 568         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
 569         emitStaticInvoke(invokeBasicName);
 570 
 571         // goto L_done
 572         builder.goto_(L_done);
 573 
 574         if (invokeBasicName.type() != BasicType.V_TYPE) {
 575             builder.state().pop(); // FIXME !!! HACK !!!
 576         }
 577 
 578         // L_fallback:
 579         builder.label(L_fallback);
 580 
 581         // invoke selectAlternativeName.arguments[2]
 582         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
 583         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
 584         emitStaticInvoke(invokeBasicName);
 585 
 586         // L_done:
 587         builder.label(L_done);
 588 
 589         return invokeBasicName;  // return what's on stack
 590     }
 591 
 592     private void emitAstoreInsn(int index) {
 593         builder.store(TypeTag.A, localsMap[index]);
 594     }
 595 
 596     private int extendLocalsMap(Class<?>[] types) {
 597         int firstSlot = localsMap.length - 1;
 598         localsMap = Arrays.copyOf(localsMap, localsMap.length + types.length);
 599         int index = localsMap[firstSlot - 1] + 1;
 600         int lastSlots = 0;
 601         for (int i = 0; i < types.length; ++i) {
 602             localsMap[firstSlot + i] = index;
 603             lastSlots = BasicType.basicType(types[i]).basicTypeSlots();
 604             index += lastSlots;
 605         }
 606         localsMap[localsMap.length - 1] = index - lastSlots;
 607         return firstSlot;
 608     }
 609 }