1 /*
   2  * Copyright (c) 2012, 2016, 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.internal.org.objectweb.asm.ClassWriter;
  29 import jdk.internal.org.objectweb.asm.Label;
  30 import jdk.internal.org.objectweb.asm.MethodVisitor;
  31 import jdk.internal.org.objectweb.asm.Opcodes;
  32 import jdk.internal.org.objectweb.asm.Type;
  33 import sun.invoke.util.VerifyAccess;
  34 import sun.invoke.util.VerifyType;
  35 import sun.invoke.util.Wrapper;
  36 import sun.reflect.misc.ReflectUtil;
  37 
  38 import java.io.File;
  39 import java.io.FileOutputStream;
  40 import java.io.IOException;
  41 import java.lang.reflect.Modifier;
  42 import java.util.ArrayList;
  43 import java.util.Arrays;
  44 import java.util.HashMap;
  45 import java.util.stream.Stream;
  46 
  47 import static java.lang.invoke.LambdaForm.BasicType;
  48 import static java.lang.invoke.LambdaForm.BasicType.*;
  49 import static java.lang.invoke.LambdaForm.*;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  51 import static java.lang.invoke.MethodHandleStatics.*;
  52 
  53 /**
  54  * Code generation backend for LambdaForm.
  55  * <p>
  56  * @author John Rose, JSR 292 EG
  57  */
  58 class InvokerBytecodeGenerator {
  59     /** Define class names for convenience. */
  60     private static final String MH      = "java/lang/invoke/MethodHandle";
  61     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  62     private static final String LF      = "java/lang/invoke/LambdaForm";
  63     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  64     private static final String BMH     = "java/lang/invoke/BoundMethodHandle";
  65     private static final String CLS     = "java/lang/Class";
  66     private static final String OBJ     = "java/lang/Object";
  67     private static final String OBJARY  = "[Ljava/lang/Object;";
  68 
  69     private static final String LF_SIG  = "L" + LF + ";";
  70     private static final String LFN_SIG = "L" + LFN + ";";
  71     private static final String OBJ_SIG = "L" + OBJ + ";";
  72     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  73     private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V";
  74     private static final String IL_SIG  = "(I)L" + OBJ + ";";
  75     private static final String CLASS_PREFIX = LF + "$";
  76 
  77     /** Name of its super class*/
  78     static final String INVOKER_SUPER_NAME = OBJ;
  79 
  80     /** Name of new class */
  81     private final String className;
  82 
  83     /** Name of the source file (for stack trace printing). */
  84     private final String sourceFile;
  85 
  86     private final LambdaForm lambdaForm;
  87     private final String     invokerName;
  88     private final MethodType invokerType;
  89 
  90     /** Info about local variables in compiled lambda form */
  91     private int[]       localsMap;    // index
  92     private Class<?>[]  localClasses; // type
  93 
  94     /** ASM bytecode generation. */
  95     private ClassWriter cw;
  96     private MethodVisitor mv;
  97 
  98     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
  99     private static final Class<?> HOST_CLASS = LambdaForm.class;
 100 
 101     /** Main constructor; other constructors delegate to this one. */
 102     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
 103                                      String className, String invokerName, MethodType invokerType) {
 104         int p = invokerName.indexOf('.');
 105         if (p > -1) {
 106             className = invokerName.substring(0, p);
 107             invokerName = invokerName.substring(p + 1);
 108         }
 109         if (DUMP_CLASS_FILES) {
 110             className = makeDumpableClassName(className);
 111         }
 112         this.className  = CLASS_PREFIX + className;
 113         this.sourceFile = "LambdaForm$" + className;
 114         this.lambdaForm = lambdaForm;
 115         this.invokerName = invokerName;
 116         this.invokerType = invokerType;
 117         this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 118         this.localClasses = new Class<?>[localsMapSize+1];
 119     }
 120 
 121     /** For generating LambdaForm interpreter entry points. */
 122     private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
 123         this(null, invokerType.parameterCount(),
 124              className, invokerName, invokerType);
 125         // Create an array to map name indexes to locals indexes.
 126         for (int i = 0; i < localsMap.length; i++) {
 127             localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
 128         }
 129     }
 130 
 131     /** For generating customized code for a single LambdaForm. */
 132     private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
 133         this(className, form.debugName, form, invokerType);
 134     }
 135 
 136     /** For generating customized code for a single LambdaForm. */
 137     InvokerBytecodeGenerator(String className, String invokerName,
 138             LambdaForm form, MethodType invokerType) {
 139         this(form, form.names.length,
 140              className, invokerName, invokerType);
 141         // Create an array to map name indexes to locals indexes.
 142         Name[] names = form.names;
 143         for (int i = 0, index = 0; i < localsMap.length; i++) {
 144             localsMap[i] = index;
 145             if (i < names.length) {
 146                 BasicType type = names[i].type();
 147                 index += type.basicTypeSlots();
 148             }
 149         }
 150     }
 151 
 152     /** instance counters for dumped classes */
 153     private static final HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
 154     /** debugging flag for saving generated class files */
 155     private static final File DUMP_CLASS_FILES_DIR;
 156 
 157     static {
 158         if (DUMP_CLASS_FILES) {
 159             DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
 160             try {
 161                 File dumpDir = new File("DUMP_CLASS_FILES");
 162                 if (!dumpDir.exists()) {
 163                     dumpDir.mkdirs();
 164                 }
 165                 DUMP_CLASS_FILES_DIR = dumpDir;
 166                 System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
 167             } catch (Exception e) {
 168                 throw newInternalError(e);
 169             }
 170         } else {
 171             DUMP_CLASS_FILES_COUNTERS = null;
 172             DUMP_CLASS_FILES_DIR = null;
 173         }
 174     }
 175 
 176     static void maybeDump(final String className, final byte[] classFile) {
 177         if (DUMP_CLASS_FILES) {
 178             java.security.AccessController.doPrivileged(
 179             new java.security.PrivilegedAction<>() {
 180                 public Void run() {
 181                     try {
 182                         String dumpName = className;
 183                         //dumpName = dumpName.replace('/', '-');
 184                         File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
 185                         System.out.println("dump: " + dumpFile);
 186                         dumpFile.getParentFile().mkdirs();
 187                         FileOutputStream file = new FileOutputStream(dumpFile);
 188                         file.write(classFile);
 189                         file.close();
 190                         return null;
 191                     } catch (IOException ex) {
 192                         throw newInternalError(ex);
 193                     }
 194                 }
 195             });
 196         }
 197     }
 198 
 199     private static String makeDumpableClassName(String className) {
 200         Integer ctr;
 201         synchronized (DUMP_CLASS_FILES_COUNTERS) {
 202             ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
 203             if (ctr == null)  ctr = 0;
 204             DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
 205         }
 206         String sfx = ctr.toString();
 207         while (sfx.length() < 3)
 208             sfx = "0"+sfx;
 209         className += sfx;
 210         return className;
 211     }
 212 
 213     class CpPatch {
 214         final int index;
 215         final Object value;
 216         CpPatch(int index, Object value) {
 217             this.index = index;
 218             this.value = value;
 219         }
 220         public String toString() {
 221             return "CpPatch/index="+index+",value="+value;
 222         }
 223     }
 224 
 225     private final ArrayList<CpPatch> cpPatches = new ArrayList<>();
 226 
 227     private int cph = 0;  // for counting constant placeholders
 228 
 229     String constantPlaceholder(Object arg) {
 230         String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
 231         if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>";
 232         // TODO check if arg is already in the constant pool
 233         // insert placeholder in CP and remember the patch
 234         int index = cw.newConst((Object) cpPlaceholder);
 235         cpPatches.add(new CpPatch(index, arg));
 236         return cpPlaceholder;
 237     }
 238 
 239     Object[] cpPatches(byte[] classFile) {
 240         int size = getConstantPoolSize(classFile);
 241         Object[] res = new Object[size];
 242         for (CpPatch p : cpPatches) {
 243             if (p.index >= size)
 244                 throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
 245             res[p.index] = p.value;
 246         }
 247         return res;
 248     }
 249 
 250     private static String debugString(Object arg) {
 251         if (arg instanceof MethodHandle) {
 252             MethodHandle mh = (MethodHandle) arg;
 253             MemberName member = mh.internalMemberName();
 254             if (member != null)
 255                 return member.toString();
 256             return mh.debugString();
 257         }
 258         return arg.toString();
 259     }
 260 
 261     /**
 262      * Extract the number of constant pool entries from a given class file.
 263      *
 264      * @param classFile the bytes of the class file in question.
 265      * @return the number of entries in the constant pool.
 266      */
 267     private static int getConstantPoolSize(byte[] classFile) {
 268         // The first few bytes:
 269         // u4 magic;
 270         // u2 minor_version;
 271         // u2 major_version;
 272         // u2 constant_pool_count;
 273         return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
 274     }
 275 
 276     /**
 277      * Extract the MemberName of a newly-defined method.
 278      */
 279     private MemberName loadMethod(byte[] classFile) {
 280         Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
 281         return resolveInvokerMember(invokerClass, invokerName, invokerType);
 282     }
 283 
 284     /**
 285      * Define a given class as anonymous class in the runtime system.
 286      */
 287     private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
 288         Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
 289         UNSAFE.ensureClassInitialized(invokerClass);  // Make sure the class is initialized; VM might complain.
 290         return invokerClass;
 291     }
 292 
 293     private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
 294         MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
 295         try {
 296             member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
 297         } catch (ReflectiveOperationException e) {
 298             throw newInternalError(e);
 299         }
 300         return member;
 301     }
 302 
 303     /**
 304      * Set up class file generation.
 305      */
 306     private ClassWriter classFilePrologue() {
 307         final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
 308         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 309         cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, INVOKER_SUPER_NAME, null);
 310         cw.visitSource(sourceFile, null);
 311         return cw;
 312     }
 313 
 314     private void methodPrologue() {
 315         String invokerDesc = invokerType.toMethodDescriptorString();
 316         mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
 317     }
 318 
 319     /**
 320      * Tear down class file generation.
 321      */
 322     private void methodEpilogue() {
 323         mv.visitMaxs(0, 0);
 324         mv.visitEnd();
 325     }
 326 
 327     /*
 328      * Low-level emit helpers.
 329      */
 330     private void emitConst(Object con) {
 331         if (con == null) {
 332             mv.visitInsn(Opcodes.ACONST_NULL);
 333             return;
 334         }
 335         if (con instanceof Integer) {
 336             emitIconstInsn((int) con);
 337             return;
 338         }
 339         if (con instanceof Byte) {
 340             emitIconstInsn((byte)con);
 341             return;
 342         }
 343         if (con instanceof Short) {
 344             emitIconstInsn((short)con);
 345             return;
 346         }
 347         if (con instanceof Character) {
 348             emitIconstInsn((char)con);
 349             return;
 350         }
 351         if (con instanceof Long) {
 352             long x = (long) con;
 353             short sx = (short)x;
 354             if (x == sx) {
 355                 if (sx >= 0 && sx <= 1) {
 356                     mv.visitInsn(Opcodes.LCONST_0 + (int) sx);
 357                 } else {
 358                     emitIconstInsn((int) x);
 359                     mv.visitInsn(Opcodes.I2L);
 360                 }
 361                 return;
 362             }
 363         }
 364         if (con instanceof Float) {
 365             float x = (float) con;
 366             short sx = (short)x;
 367             if (x == sx) {
 368                 if (sx >= 0 && sx <= 2) {
 369                     mv.visitInsn(Opcodes.FCONST_0 + (int) sx);
 370                 } else {
 371                     emitIconstInsn((int) x);
 372                     mv.visitInsn(Opcodes.I2F);
 373                 }
 374                 return;
 375             }
 376         }
 377         if (con instanceof Double) {
 378             double x = (double) con;
 379             short sx = (short)x;
 380             if (x == sx) {
 381                 if (sx >= 0 && sx <= 1) {
 382                     mv.visitInsn(Opcodes.DCONST_0 + (int) sx);
 383                 } else {
 384                     emitIconstInsn((int) x);
 385                     mv.visitInsn(Opcodes.I2D);
 386                 }
 387                 return;
 388             }
 389         }
 390         if (con instanceof Boolean) {
 391             emitIconstInsn((boolean) con ? 1 : 0);
 392             return;
 393         }
 394         // fall through:
 395         mv.visitLdcInsn(con);
 396     }
 397 
 398     private void emitIconstInsn(final int cst) {
 399         if (cst >= -1 && cst <= 5) {
 400             mv.visitInsn(Opcodes.ICONST_0 + cst);
 401         } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
 402             mv.visitIntInsn(Opcodes.BIPUSH, cst);
 403         } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
 404             mv.visitIntInsn(Opcodes.SIPUSH, cst);
 405         } else {
 406             mv.visitLdcInsn(cst);
 407         }
 408     }
 409 
 410     /*
 411      * NOTE: These load/store methods use the localsMap to find the correct index!
 412      */
 413     private void emitLoadInsn(BasicType type, int index) {
 414         int opcode = loadInsnOpcode(type);
 415         mv.visitVarInsn(opcode, localsMap[index]);
 416     }
 417 
 418     private int loadInsnOpcode(BasicType type) throws InternalError {
 419         switch (type) {
 420             case I_TYPE: return Opcodes.ILOAD;
 421             case J_TYPE: return Opcodes.LLOAD;
 422             case F_TYPE: return Opcodes.FLOAD;
 423             case D_TYPE: return Opcodes.DLOAD;
 424             case L_TYPE: return Opcodes.ALOAD;
 425             default:
 426                 throw new InternalError("unknown type: " + type);
 427         }
 428     }
 429     private void emitAloadInsn(int index) {
 430         emitLoadInsn(L_TYPE, index);
 431     }
 432 
 433     private void emitStoreInsn(BasicType type, int index) {
 434         int opcode = storeInsnOpcode(type);
 435         mv.visitVarInsn(opcode, localsMap[index]);
 436     }
 437 
 438     private int storeInsnOpcode(BasicType type) throws InternalError {
 439         switch (type) {
 440             case I_TYPE: return Opcodes.ISTORE;
 441             case J_TYPE: return Opcodes.LSTORE;
 442             case F_TYPE: return Opcodes.FSTORE;
 443             case D_TYPE: return Opcodes.DSTORE;
 444             case L_TYPE: return Opcodes.ASTORE;
 445             default:
 446                 throw new InternalError("unknown type: " + type);
 447         }
 448     }
 449     private void emitAstoreInsn(int index) {
 450         emitStoreInsn(L_TYPE, index);
 451     }
 452 
 453     private byte arrayTypeCode(Wrapper elementType) {
 454         switch (elementType) {
 455             case BOOLEAN: return Opcodes.T_BOOLEAN;
 456             case BYTE:    return Opcodes.T_BYTE;
 457             case CHAR:    return Opcodes.T_CHAR;
 458             case SHORT:   return Opcodes.T_SHORT;
 459             case INT:     return Opcodes.T_INT;
 460             case LONG:    return Opcodes.T_LONG;
 461             case FLOAT:   return Opcodes.T_FLOAT;
 462             case DOUBLE:  return Opcodes.T_DOUBLE;
 463             case OBJECT:  return 0; // in place of Opcodes.T_OBJECT
 464             default:      throw new InternalError();
 465         }
 466     }
 467 
 468     private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
 469         assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
 470         int xas;
 471         switch (tcode) {
 472             case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
 473             case Opcodes.T_BYTE:    xas = Opcodes.BASTORE; break;
 474             case Opcodes.T_CHAR:    xas = Opcodes.CASTORE; break;
 475             case Opcodes.T_SHORT:   xas = Opcodes.SASTORE; break;
 476             case Opcodes.T_INT:     xas = Opcodes.IASTORE; break;
 477             case Opcodes.T_LONG:    xas = Opcodes.LASTORE; break;
 478             case Opcodes.T_FLOAT:   xas = Opcodes.FASTORE; break;
 479             case Opcodes.T_DOUBLE:  xas = Opcodes.DASTORE; break;
 480             case 0:                 xas = Opcodes.AASTORE; break;
 481             default:      throw new InternalError();
 482         }
 483         return xas - Opcodes.AASTORE + aaop;
 484     }
 485 
 486     /**
 487      * Emit a boxing call.
 488      *
 489      * @param wrapper primitive type class to box.
 490      */
 491     private void emitBoxing(Wrapper wrapper) {
 492         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 493         String name  = "valueOf";
 494         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
 495         mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
 496     }
 497 
 498     /**
 499      * Emit an unboxing call (plus preceding checkcast).
 500      *
 501      * @param wrapper wrapper type class to unbox.
 502      */
 503     private void emitUnboxing(Wrapper wrapper) {
 504         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 505         String name  = wrapper.primitiveSimpleName() + "Value";
 506         String desc  = "()" + wrapper.basicTypeChar();
 507         emitReferenceCast(wrapper.wrapperType(), null);
 508         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
 509     }
 510 
 511     /**
 512      * Emit an implicit conversion for an argument which must be of the given pclass.
 513      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 514      *
 515      * @param ptype type of value present on stack
 516      * @param pclass type of value required on stack
 517      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 518      */
 519     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 520         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 521         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 522             return;   // nothing to do
 523         switch (ptype) {
 524             case L_TYPE:
 525                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 526                     if (PROFILE_LEVEL > 0)
 527                         emitReferenceCast(Object.class, arg);
 528                     return;
 529                 }
 530                 emitReferenceCast(pclass, arg);
 531                 return;
 532             case I_TYPE:
 533                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 534                     emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
 535                 return;
 536         }
 537         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 538     }
 539 
 540     /** Update localClasses type map.  Return true if the information is already present. */
 541     private boolean assertStaticType(Class<?> cls, Name n) {
 542         int local = n.index();
 543         Class<?> aclass = localClasses[local];
 544         if (aclass != null && (aclass == cls || cls.isAssignableFrom(aclass))) {
 545             return true;  // type info is already present
 546         } else if (aclass == null || aclass.isAssignableFrom(cls)) {
 547             localClasses[local] = cls;  // type info can be improved
 548         }
 549         return false;
 550     }
 551 
 552     private void emitReferenceCast(Class<?> cls, Object arg) {
 553         Name writeBack = null;  // local to write back result
 554         if (arg instanceof Name) {
 555             Name n = (Name) arg;
 556             if (lambdaForm.useCount(n) > 1) {
 557                 // This guy gets used more than once.
 558                 writeBack = n;
 559                 if (assertStaticType(cls, n)) {
 560                     return; // this cast was already performed
 561                 }
 562             }
 563         }
 564         if (isStaticallyNameable(cls)) {
 565             String sig = getInternalName(cls);
 566             mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
 567         } else {
 568             mv.visitLdcInsn(constantPlaceholder(cls));
 569             mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
 570             mv.visitInsn(Opcodes.SWAP);
 571             mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
 572             if (Object[].class.isAssignableFrom(cls))
 573                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
 574             else if (PROFILE_LEVEL > 0)
 575                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
 576         }
 577         if (writeBack != null) {
 578             mv.visitInsn(Opcodes.DUP);
 579             emitAstoreInsn(writeBack.index());
 580         }
 581     }
 582 
 583     /**
 584      * Emits an actual return instruction conforming to the given return type.
 585      */
 586     private void emitReturnInsn(BasicType type) {
 587         int opcode;
 588         switch (type) {
 589         case I_TYPE:  opcode = Opcodes.IRETURN;  break;
 590         case J_TYPE:  opcode = Opcodes.LRETURN;  break;
 591         case F_TYPE:  opcode = Opcodes.FRETURN;  break;
 592         case D_TYPE:  opcode = Opcodes.DRETURN;  break;
 593         case L_TYPE:  opcode = Opcodes.ARETURN;  break;
 594         case V_TYPE:  opcode = Opcodes.RETURN;   break;
 595         default:
 596             throw new InternalError("unknown return type: " + type);
 597         }
 598         mv.visitInsn(opcode);
 599     }
 600 
 601     private static String getInternalName(Class<?> c) {
 602         if (c == Object.class)             return OBJ;
 603         else if (c == Object[].class)      return OBJARY;
 604         else if (c == Class.class)         return CLS;
 605         else if (c == MethodHandle.class)  return MH;
 606         assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
 607         return c.getName().replace('.', '/');
 608     }
 609 
 610     private static MemberName resolveFrom(String name, MethodType type, Class<?> holder) {
 611         MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
 612         MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder);
 613         if (TRACE_RESOLVE) {
 614             System.out.println("[LF_RESOLVE] " + holder.getName() + " " + name + " " +
 615                     shortenSignature(basicTypeSignature(type)) + (resolvedMember != null ? " (success)" : " (fail)") );
 616         }
 617         return resolvedMember;
 618     }
 619 
 620     private static MemberName lookupPregenerated(LambdaForm form) {
 621         if (form.customized != null) {
 622             // No pre-generated version for customized LF
 623             return null;
 624         }
 625         MethodType invokerType = form.methodType();
 626         String name = form.kind.methodName;
 627         switch (form.kind) {
 628             case BOUND_REINVOKER: {
 629                 name = name + "_" + BoundMethodHandle.speciesData(form).fieldSignature();
 630                 return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
 631             }
 632             case DELEGATE:                  return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
 633             case ZERO:                      // fall-through
 634             case IDENTITY: {
 635                 name = name + "_" + form.returnType().basicTypeChar();
 636                 return resolveFrom(name, invokerType, LambdaForm.Holder.class);
 637             }
 638             case EXACT_INVOKER:             // fall-through
 639             case EXACT_LINKER:              // fall-through
 640             case GENERIC_INVOKER:           // fall-through
 641             case GENERIC_LINKER:            return resolveFrom(name, invokerType.basicType(), Invokers.Holder.class);
 642             case GET_OBJECT:                // fall-through
 643             case GET_BOOLEAN:               // fall-through
 644             case GET_BYTE:                  // fall-through
 645             case GET_CHAR:                  // fall-through
 646             case GET_SHORT:                 // fall-through
 647             case GET_INT:                   // fall-through
 648             case GET_LONG:                  // fall-through
 649             case GET_FLOAT:                 // fall-through
 650             case GET_DOUBLE:                // fall-through
 651             case PUT_OBJECT:                // fall-through
 652             case PUT_BOOLEAN:               // fall-through
 653             case PUT_BYTE:                  // fall-through
 654             case PUT_CHAR:                  // fall-through
 655             case PUT_SHORT:                 // fall-through
 656             case PUT_INT:                   // fall-through
 657             case PUT_LONG:                  // fall-through
 658             case PUT_FLOAT:                 // fall-through
 659             case PUT_DOUBLE:                // fall-through
 660             case DIRECT_INVOKE_INTERFACE:   // fall-through
 661             case DIRECT_INVOKE_SPECIAL:     // fall-through
 662             case DIRECT_INVOKE_STATIC:      // fall-through
 663             case DIRECT_INVOKE_STATIC_INIT: // fall-through
 664             case DIRECT_INVOKE_VIRTUAL:     return resolveFrom(name, invokerType, DirectMethodHandle.Holder.class);
 665         }
 666         return null;
 667     }
 668 
 669     /**
 670      * Generate customized bytecode for a given LambdaForm.
 671      */
 672     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
 673         MemberName pregenerated = lookupPregenerated(form);
 674         if (pregenerated != null)  return pregenerated; // pre-generated bytecode
 675 
 676         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
 677         return g.loadMethod(g.generateCustomizedCodeBytes());
 678     }
 679 
 680     /** Generates code to check that actual receiver and LambdaForm matches */
 681     private boolean checkActualReceiver() {
 682         // Expects MethodHandle on the stack and actual receiver MethodHandle in slot #0
 683         mv.visitInsn(Opcodes.DUP);
 684         mv.visitVarInsn(Opcodes.ALOAD, localsMap[0]);
 685         mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "assertSame", LLV_SIG, false);
 686         return true;
 687     }
 688 
 689     static String className(String cn) {
 690         assert checkClassName(cn): "Class not found: " + cn;
 691         return cn;
 692     }
 693 
 694     static boolean checkClassName(String cn) {
 695         Type tp = Type.getType(cn);
 696         // additional sanity so only valid "L;" descriptors work
 697         if (tp.getSort() != Type.OBJECT) {
 698             return false;
 699         }
 700         try {
 701             Class<?> c = Class.forName(tp.getClassName(), false, null);
 702             return true;
 703         } catch (ClassNotFoundException e) {
 704             return false;
 705         }
 706     }
 707 
 708     static final String  LF_HIDDEN_SIG = className("Ljava/lang/invoke/LambdaForm$Hidden;");
 709     static final String  LF_COMPILED_SIG = className("Ljava/lang/invoke/LambdaForm$Compiled;");
 710     static final String  FORCEINLINE_SIG = className("Ljdk/internal/vm/annotation/ForceInline;");
 711     static final String  DONTINLINE_SIG = className("Ljdk/internal/vm/annotation/DontInline;");
 712     static final String  INJECTEDPROFILE_SIG = className("Ljava/lang/invoke/InjectedProfile;");
 713 
 714     /**
 715      * Generate an invoker method for the passed {@link LambdaForm}.
 716      */
 717     private byte[] generateCustomizedCodeBytes() {
 718         classFilePrologue();
 719         addMethod();
 720         bogusMethod(lambdaForm);
 721 
 722         final byte[] classFile = toByteArray();
 723         maybeDump(className, classFile);
 724         return classFile;
 725     }
 726 
 727     void setClassWriter(ClassWriter cw) {
 728         this.cw = cw;
 729     }
 730 
 731     void addMethod() {
 732         methodPrologue();
 733 
 734         // Suppress this method in backtraces displayed to the user.
 735         mv.visitAnnotation(LF_HIDDEN_SIG, true);
 736 
 737         // Mark this method as a compiled LambdaForm
 738         mv.visitAnnotation(LF_COMPILED_SIG, true);
 739 
 740         if (lambdaForm.forceInline) {
 741             // Force inlining of this invoker method.
 742             mv.visitAnnotation(FORCEINLINE_SIG, true);
 743         } else {
 744             mv.visitAnnotation(DONTINLINE_SIG, true);
 745         }
 746 
 747         constantPlaceholder(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
 748 
 749         if (lambdaForm.customized != null) {
 750             // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute
 751             // receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
 752             // It enables more efficient code generation in some situations, since embedded constants
 753             // are compile-time constants for JIT compiler.
 754             mv.visitLdcInsn(constantPlaceholder(lambdaForm.customized));
 755             mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
 756             assert(checkActualReceiver()); // expects MethodHandle on top of the stack
 757             mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
 758         }
 759 
 760         // iterate over the form's names, generating bytecode instructions for each
 761         // start iterating at the first name following the arguments
 762         Name onStack = null;
 763         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 764             Name name = lambdaForm.names[i];
 765 
 766             emitStoreResult(onStack);
 767             onStack = name;  // unless otherwise modified below
 768             MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
 769             switch (intr) {
 770                 case SELECT_ALTERNATIVE:
 771                     assert lambdaForm.isSelectAlternative(i);
 772                     if (PROFILE_GWT) {
 773                         assert(name.arguments[0] instanceof Name &&
 774                                 ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
 775                         mv.visitAnnotation(INJECTEDPROFILE_SIG, true);
 776                     }
 777                     onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
 778                     i++;  // skip MH.invokeBasic of the selectAlternative result
 779                     continue;
 780                 case GUARD_WITH_CATCH:
 781                     assert lambdaForm.isGuardWithCatch(i);
 782                     onStack = emitGuardWithCatch(i);
 783                     i += 2; // jump to the end of GWC idiom
 784                     continue;
 785                 case TRY_FINALLY:
 786                     assert lambdaForm.isTryFinally(i);
 787                     onStack = emitTryFinally(i);
 788                     i += 2; // jump to the end of the TF idiom
 789                     continue;
 790                 case LOOP:
 791                     assert lambdaForm.isLoop(i);
 792                     onStack = emitLoop(i);
 793                     i += 2; // jump to the end of the LOOP idiom
 794                     continue;
 795                 case NEW_ARRAY:
 796                     Class<?> rtype = name.function.methodType().returnType();
 797                     if (isStaticallyNameable(rtype)) {
 798                         emitNewArray(name);
 799                         continue;
 800                     }
 801                     break;
 802                 case ARRAY_LOAD:
 803                     emitArrayLoad(name);
 804                     continue;
 805                 case ARRAY_STORE:
 806                     emitArrayStore(name);
 807                     continue;
 808                 case ARRAY_LENGTH:
 809                     emitArrayLength(name);
 810                     continue;
 811                 case IDENTITY:
 812                     assert(name.arguments.length == 1);
 813                     emitPushArguments(name, 0);
 814                     continue;
 815                 case ZERO:
 816                     assert(name.arguments.length == 0);
 817                     emitConst(name.type.basicTypeWrapper().zero());
 818                     continue;
 819                 case NONE:
 820                     // no intrinsic associated
 821                     break;
 822                 default:
 823                     throw newInternalError("Unknown intrinsic: "+intr);
 824             }
 825 
 826             MemberName member = name.function.member();
 827             if (isStaticallyInvocable(member)) {
 828                 emitStaticInvoke(member, name);
 829             } else {
 830                 emitInvoke(name);
 831             }
 832         }
 833 
 834         // return statement
 835         emitReturn(onStack);
 836 
 837         methodEpilogue();
 838     }
 839 
 840     /*
 841      * @throws BytecodeGenerationException if something goes wrong when
 842      *         generating the byte code
 843      */
 844     private byte[] toByteArray() {
 845         try {
 846             return cw.toByteArray();
 847         } catch (RuntimeException e) {
 848             throw new BytecodeGenerationException(e);
 849         }
 850     }
 851 
 852     @SuppressWarnings("serial")
 853     static final class BytecodeGenerationException extends RuntimeException {
 854         BytecodeGenerationException(Exception cause) {
 855             super(cause);
 856         }
 857     }
 858 
 859     void emitArrayLoad(Name name)   { emitArrayOp(name, Opcodes.AALOAD);      }
 860     void emitArrayStore(Name name)  { emitArrayOp(name, Opcodes.AASTORE);     }
 861     void emitArrayLength(Name name) { emitArrayOp(name, Opcodes.ARRAYLENGTH); }
 862 
 863     void emitArrayOp(Name name, int arrayOpcode) {
 864         assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE || arrayOpcode == Opcodes.ARRAYLENGTH;
 865         Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
 866         assert elementType != null;
 867         emitPushArguments(name, 0);
 868         if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) {
 869             Wrapper w = Wrapper.forPrimitiveType(elementType);
 870             arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
 871         }
 872         mv.visitInsn(arrayOpcode);
 873     }
 874 
 875     /**
 876      * Emit an invoke for the given name.
 877      */
 878     void emitInvoke(Name name) {
 879         assert(!name.isLinkerMethodInvoke());  // should use the static path for these
 880         if (true) {
 881             // push receiver
 882             MethodHandle target = name.function.resolvedHandle();
 883             assert(target != null) : name.exprString();
 884             mv.visitLdcInsn(constantPlaceholder(target));
 885             emitReferenceCast(MethodHandle.class, target);
 886         } else {
 887             // load receiver
 888             emitAloadInsn(0);
 889             emitReferenceCast(MethodHandle.class, null);
 890             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
 891             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
 892             // TODO more to come
 893         }
 894 
 895         // push arguments
 896         emitPushArguments(name, 0);
 897 
 898         // invocation
 899         MethodType type = name.function.methodType();
 900         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 901     }
 902 
 903     private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
 904         // Sample classes from each package we are willing to bind to statically:
 905         java.lang.Object.class,
 906         java.util.Arrays.class,
 907         jdk.internal.misc.Unsafe.class
 908         //MethodHandle.class already covered
 909     };
 910 
 911     static boolean isStaticallyInvocable(NamedFunction[] functions) {
 912         for (NamedFunction nf : functions) {
 913             if (!isStaticallyInvocable(nf.member())) {
 914                 return false;
 915             }
 916         }
 917         return true;
 918     }
 919 
 920     static boolean isStaticallyInvocable(Name name) {
 921         return isStaticallyInvocable(name.function.member());
 922     }
 923 
 924     static boolean isStaticallyInvocable(MemberName member) {
 925         if (member == null)  return false;
 926         if (member.isConstructor())  return false;
 927         Class<?> cls = member.getDeclaringClass();
 928         if (cls.isArray() || cls.isPrimitive())
 929             return false;  // FIXME
 930         if (cls.isAnonymousClass() || cls.isLocalClass())
 931             return false;  // inner class of some sort
 932         if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
 933             return false;  // not on BCP
 934         if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
 935             return false;
 936         MethodType mtype = member.getMethodOrFieldType();
 937         if (!isStaticallyNameable(mtype.returnType()))
 938             return false;
 939         for (Class<?> ptype : mtype.parameterArray())
 940             if (!isStaticallyNameable(ptype))
 941                 return false;
 942         if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
 943             return true;   // in java.lang.invoke package
 944         if (member.isPublic() && isStaticallyNameable(cls))
 945             return true;
 946         return false;
 947     }
 948 
 949     static boolean isStaticallyNameable(Class<?> cls) {
 950         if (cls == Object.class)
 951             return true;
 952         while (cls.isArray())
 953             cls = cls.getComponentType();
 954         if (cls.isPrimitive())
 955             return true;  // int[].class, for example
 956         if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
 957             return false;
 958         // could use VerifyAccess.isClassAccessible but the following is a safe approximation
 959         if (cls.getClassLoader() != Object.class.getClassLoader())
 960             return false;
 961         if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
 962             return true;
 963         if (!Modifier.isPublic(cls.getModifiers()))
 964             return false;
 965         for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
 966             if (VerifyAccess.isSamePackage(pkgcls, cls))
 967                 return true;
 968         }
 969         return false;
 970     }
 971 
 972     void emitStaticInvoke(Name name) {
 973         emitStaticInvoke(name.function.member(), name);
 974     }
 975 
 976     /**
 977      * Emit an invoke for the given name, using the MemberName directly.
 978      */
 979     void emitStaticInvoke(MemberName member, Name name) {
 980         assert(member.equals(name.function.member()));
 981         Class<?> defc = member.getDeclaringClass();
 982         String cname = getInternalName(defc);
 983         String mname = member.getName();
 984         String mtype;
 985         byte refKind = member.getReferenceKind();
 986         if (refKind == REF_invokeSpecial) {
 987             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 988             assert(member.canBeStaticallyBound()) : member;
 989             refKind = REF_invokeVirtual;
 990         }
 991 
 992         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 993 
 994         // push arguments
 995         emitPushArguments(name, 0);
 996 
 997         // invocation
 998         if (member.isMethod()) {
 999             mtype = member.getMethodType().toMethodDescriptorString();
1000             mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype,
1001                                member.getDeclaringClass().isInterface());
1002         } else {
1003             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
1004             mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
1005         }
1006         // Issue a type assertion for the result, so we can avoid casts later.
1007         if (name.type == L_TYPE) {
1008             Class<?> rtype = member.getInvocationType().returnType();
1009             assert(!rtype.isPrimitive());
1010             if (rtype != Object.class && !rtype.isInterface()) {
1011                 assertStaticType(rtype, name);
1012             }
1013         }
1014     }
1015 
1016     void emitNewArray(Name name) throws InternalError {
1017         Class<?> rtype = name.function.methodType().returnType();
1018         if (name.arguments.length == 0) {
1019             // The array will be a constant.
1020             Object emptyArray;
1021             try {
1022                 emptyArray = name.function.resolvedHandle().invoke();
1023             } catch (Throwable ex) {
1024                 throw newInternalError(ex);
1025             }
1026             assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
1027             assert(emptyArray.getClass() == rtype);  // exact typing
1028             mv.visitLdcInsn(constantPlaceholder(emptyArray));
1029             emitReferenceCast(rtype, emptyArray);
1030             return;
1031         }
1032         Class<?> arrayElementType = rtype.getComponentType();
1033         assert(arrayElementType != null);
1034         emitIconstInsn(name.arguments.length);
1035         int xas = Opcodes.AASTORE;
1036         if (!arrayElementType.isPrimitive()) {
1037             mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
1038         } else {
1039             byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
1040             xas = arrayInsnOpcode(tc, xas);
1041             mv.visitIntInsn(Opcodes.NEWARRAY, tc);
1042         }
1043         // store arguments
1044         for (int i = 0; i < name.arguments.length; i++) {
1045             mv.visitInsn(Opcodes.DUP);
1046             emitIconstInsn(i);
1047             emitPushArgument(name, i);
1048             mv.visitInsn(xas);
1049         }
1050         // the array is left on the stack
1051         assertStaticType(rtype, name);
1052     }
1053     int refKindOpcode(byte refKind) {
1054         switch (refKind) {
1055         case REF_invokeVirtual:      return Opcodes.INVOKEVIRTUAL;
1056         case REF_invokeStatic:       return Opcodes.INVOKESTATIC;
1057         case REF_invokeSpecial:      return Opcodes.INVOKESPECIAL;
1058         case REF_invokeInterface:    return Opcodes.INVOKEINTERFACE;
1059         case REF_getField:           return Opcodes.GETFIELD;
1060         case REF_putField:           return Opcodes.PUTFIELD;
1061         case REF_getStatic:          return Opcodes.GETSTATIC;
1062         case REF_putStatic:          return Opcodes.PUTSTATIC;
1063         }
1064         throw new InternalError("refKind="+refKind);
1065     }
1066 
1067     /**
1068      * Emit bytecode for the selectAlternative idiom.
1069      *
1070      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
1071      * <blockquote><pre>{@code
1072      *   Lambda(a0:L,a1:I)=>{
1073      *     t2:I=foo.test(a1:I);
1074      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
1075      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
1076      * }</pre></blockquote>
1077      */
1078     private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
1079         assert isStaticallyInvocable(invokeBasicName);
1080 
1081         Name receiver = (Name) invokeBasicName.arguments[0];
1082 
1083         Label L_fallback = new Label();
1084         Label L_done     = new Label();
1085 
1086         // load test result
1087         emitPushArgument(selectAlternativeName, 0);
1088 
1089         // if_icmpne L_fallback
1090         mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
1091 
1092         // invoke selectAlternativeName.arguments[1]
1093         Class<?>[] preForkClasses = localClasses.clone();
1094         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
1095         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
1096         emitStaticInvoke(invokeBasicName);
1097 
1098         // goto L_done
1099         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1100 
1101         // L_fallback:
1102         mv.visitLabel(L_fallback);
1103 
1104         // invoke selectAlternativeName.arguments[2]
1105         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1106         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
1107         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
1108         emitStaticInvoke(invokeBasicName);
1109 
1110         // L_done:
1111         mv.visitLabel(L_done);
1112         // for now do not bother to merge typestate; just reset to the dominator state
1113         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1114 
1115         return invokeBasicName;  // return what's on stack
1116     }
1117 
1118     /**
1119       * Emit bytecode for the guardWithCatch idiom.
1120       *
1121       * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch):
1122       * <blockquote><pre>{@code
1123       *  guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
1124       *    t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L);
1125       *    t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L);
1126       *   t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I}
1127       * }</pre></blockquote>
1128       *
1129       * It is compiled into bytecode equivalent of the following code:
1130       * <blockquote><pre>{@code
1131       *  try {
1132       *      return a1.invokeBasic(a6, a7);
1133       *  } catch (Throwable e) {
1134       *      if (!a2.isInstance(e)) throw e;
1135       *      return a3.invokeBasic(ex, a6, a7);
1136       *  }}
1137       */
1138     private Name emitGuardWithCatch(int pos) {
1139         Name args    = lambdaForm.names[pos];
1140         Name invoker = lambdaForm.names[pos+1];
1141         Name result  = lambdaForm.names[pos+2];
1142 
1143         Label L_startBlock = new Label();
1144         Label L_endBlock = new Label();
1145         Label L_handler = new Label();
1146         Label L_done = new Label();
1147 
1148         Class<?> returnType = result.function.resolvedHandle().type().returnType();
1149         MethodType type = args.function.resolvedHandle().type()
1150                               .dropParameterTypes(0,1)
1151                               .changeReturnType(returnType);
1152 
1153         mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable");
1154 
1155         // Normal case
1156         mv.visitLabel(L_startBlock);
1157         // load target
1158         emitPushArgument(invoker, 0);
1159         emitPushArguments(args, 1); // skip 1st argument: method handle
1160         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1161         mv.visitLabel(L_endBlock);
1162         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1163 
1164         // Exceptional case
1165         mv.visitLabel(L_handler);
1166 
1167         // Check exception's type
1168         mv.visitInsn(Opcodes.DUP);
1169         // load exception class
1170         emitPushArgument(invoker, 1);
1171         mv.visitInsn(Opcodes.SWAP);
1172         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "isInstance", "(Ljava/lang/Object;)Z", false);
1173         Label L_rethrow = new Label();
1174         mv.visitJumpInsn(Opcodes.IFEQ, L_rethrow);
1175 
1176         // Invoke catcher
1177         // load catcher
1178         emitPushArgument(invoker, 2);
1179         mv.visitInsn(Opcodes.SWAP);
1180         emitPushArguments(args, 1); // skip 1st argument: method handle
1181         MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
1182         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString(), false);
1183         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1184 
1185         mv.visitLabel(L_rethrow);
1186         mv.visitInsn(Opcodes.ATHROW);
1187 
1188         mv.visitLabel(L_done);
1189 
1190         return result;
1191     }
1192 
1193     /**
1194      * Emit bytecode for the tryFinally idiom.
1195      * <p>
1196      * The pattern looks like (Cf. MethodHandleImpl.makeTryFinally):
1197      * <blockquote><pre>{@code
1198      * // a0: BMH
1199      * // a1: target, a2: cleanup
1200      * // a3: box, a4: unbox
1201      * // a5 (and following): arguments
1202      * tryFinally=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L)=>{
1203      *   t6:L=MethodHandle.invokeBasic(a3:L,a5:L);         // box the arguments into an Object[]
1204      *   t7:L=MethodHandleImpl.tryFinally(a1:L,a2:L,t6:L); // call the tryFinally executor
1205      *   t8:L=MethodHandle.invokeBasic(a4:L,t7:L);t8:L}    // unbox the result; return the result
1206      * }</pre></blockquote>
1207      * <p>
1208      * It is compiled into bytecode equivalent to the following code:
1209      * <blockquote><pre>{@code
1210      * Throwable t;
1211      * Object r;
1212      * try {
1213      *     r = a1.invokeBasic(a5);
1214      * } catch (Throwable thrown) {
1215      *     t = thrown;
1216      *     throw t;
1217      * } finally {
1218      *     r = a2.invokeBasic(t, r, a5);
1219      * }
1220      * return r;
1221      * }</pre></blockquote>
1222      * <p>
1223      * Specifically, the bytecode will have the following form (the stack effects are given for the beginnings of
1224      * blocks, and for the situations after executing the given instruction - the code will have a slightly different
1225      * shape if the return type is {@code void}):
1226      * <blockquote><pre>{@code
1227      * TRY:                 (--)
1228      *                      load target                             (-- target)
1229      *                      load args                               (-- args... target)
1230      *                      INVOKEVIRTUAL MethodHandle.invokeBasic  (depends)
1231      * FINALLY_NORMAL:      (-- r)
1232      *                      load cleanup                            (-- cleanup r)
1233      *                      SWAP                                    (-- r cleanup)
1234      *                      ACONST_NULL                             (-- t r cleanup)
1235      *                      SWAP                                    (-- r t cleanup)
1236      *                      load args                               (-- args... r t cleanup)
1237      *                      INVOKEVIRTUAL MethodHandle.invokeBasic  (-- r)
1238      *                      GOTO DONE
1239      * CATCH:               (-- t)
1240      *                      DUP                                     (-- t t)
1241      * FINALLY_EXCEPTIONAL: (-- t t)
1242      *                      load cleanup                            (-- cleanup t t)
1243      *                      SWAP                                    (-- t cleanup t)
1244      *                      load default for r                      (-- r t cleanup t)
1245      *                      load args                               (-- args... r t cleanup t)
1246      *                      INVOKEVIRTUAL MethodHandle.invokeBasic  (-- r t)
1247      *                      POP                                     (-- t)
1248      *                      ATHROW
1249      * DONE:                (-- r)
1250      * }</pre></blockquote>
1251      */
1252     private Name emitTryFinally(int pos) {
1253         Name args    = lambdaForm.names[pos];
1254         Name invoker = lambdaForm.names[pos+1];
1255         Name result  = lambdaForm.names[pos+2];
1256 
1257         Label lFrom = new Label();
1258         Label lTo = new Label();
1259         Label lCatch = new Label();
1260         Label lDone = new Label();
1261 
1262         Class<?> returnType = result.function.resolvedHandle().type().returnType();
1263         boolean isNonVoid = returnType != void.class;
1264         MethodType type = args.function.resolvedHandle().type()
1265                 .dropParameterTypes(0,1)
1266                 .changeReturnType(returnType);
1267         MethodType cleanupType = type.insertParameterTypes(0, Throwable.class);
1268         if (isNonVoid) {
1269             cleanupType = cleanupType.insertParameterTypes(1, returnType);
1270         }
1271         String cleanupDesc = cleanupType.basicType().toMethodDescriptorString();
1272 
1273         // exception handler table
1274         mv.visitTryCatchBlock(lFrom, lTo, lCatch, "java/lang/Throwable");
1275 
1276         // TRY:
1277         mv.visitLabel(lFrom);
1278         emitPushArgument(invoker, 0); // load target
1279         emitPushArguments(args, 1); // load args (skip 0: method handle)
1280         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1281         mv.visitLabel(lTo);
1282 
1283         // FINALLY_NORMAL:
1284         emitPushArgument(invoker, 1); // load cleanup
1285         if (isNonVoid) {
1286             mv.visitInsn(Opcodes.SWAP);
1287         }
1288         mv.visitInsn(Opcodes.ACONST_NULL);
1289         if (isNonVoid) {
1290             mv.visitInsn(Opcodes.SWAP);
1291         }
1292         emitPushArguments(args, 1); // load args (skip 0: method handle)
1293         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false);
1294         mv.visitJumpInsn(Opcodes.GOTO, lDone);
1295 
1296         // CATCH:
1297         mv.visitLabel(lCatch);
1298         mv.visitInsn(Opcodes.DUP);
1299 
1300         // FINALLY_EXCEPTIONAL:
1301         emitPushArgument(invoker, 1); // load cleanup
1302         mv.visitInsn(Opcodes.SWAP);
1303         if (isNonVoid) {
1304             emitZero(BasicType.basicType(returnType)); // load default for result
1305         }
1306         emitPushArguments(args, 1); // load args (skip 0: method handle)
1307         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", cleanupDesc, false);
1308         if (isNonVoid) {
1309             mv.visitInsn(Opcodes.POP);
1310         }
1311         mv.visitInsn(Opcodes.ATHROW);
1312 
1313         // DONE:
1314         mv.visitLabel(lDone);
1315 
1316         return result;
1317     }
1318 
1319     /**
1320      * Emit bytecode for the loop idiom.
1321      * <p>
1322      * The pattern looks like (Cf. MethodHandleImpl.loop):
1323      * <blockquote><pre>{@code
1324      * // a0: BMH
1325      * // a1: inits, a2: steps, a3: preds, a4: finis
1326      * // a5: box, a6: unbox
1327      * // a7 (and following): arguments
1328      * loop=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
1329      *   t8:L=MethodHandle.invokeBasic(a5:L,a7:L);                  // box the arguments into an Object[]
1330      *   t9:L=MethodHandleImpl.loop(bt:L,a1:L,a2:L,a3:L,a4:L,t8:L); // call the loop executor (with supplied types in bt)
1331      *   t10:L=MethodHandle.invokeBasic(a6:L,t9:L);t10:L}           // unbox the result; return the result
1332      * }</pre></blockquote>
1333      * <p>
1334      * It is compiled into bytecode equivalent to the code seen in {@link MethodHandleImpl#loop(BasicType[],
1335      * BoundMethodHandle, BoundMethodHandle, BoundMethodHandle, BoundMethodHandle, Object...)}, with the difference that
1336      * no arrays will be used for local state storage. Instead, the local state will be mapped to actual stack slots.
1337      * <p>
1338      * Bytecode generation applies an unrolling scheme to enable better bytecode generation regarding local state type
1339      * handling. The generated bytecode will have the following form ({@code void} types are ignored for convenience).
1340      * Assume there are {@code C} clauses in the loop.
1341      * <blockquote><pre>{@code
1342      * INIT: (INIT_SEQ for clause 1)
1343      *       ...
1344      *       (INIT_SEQ for clause C)
1345      * LOOP: (LOOP_SEQ for clause 1)
1346      *       ...
1347      *       (LOOP_SEQ for clause C)
1348      *       GOTO LOOP
1349      * DONE: ...
1350      * }</pre></blockquote>
1351      * <p>
1352      * The {@code INIT_SEQ_x} sequence for clause {@code x} (with {@code x} ranging from {@code 0} to {@code C-1}) has
1353      * the following shape. Assume slot {@code vx} is used to hold the state for clause {@code x}.
1354      * <blockquote><pre>{@code
1355      * INIT_SEQ_x:  ALOAD inits
1356      *              CHECKCAST BoundMethodHandle$Species_LC
1357      *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the init handle for clause x
1358      *              CHECKCAST MethodHandle
1359      *              load args
1360      *              INVOKEVIRTUAL MethodHandle.invokeBasic
1361      *              store vx
1362      * }</pre></blockquote>
1363      * <p>
1364      * The {@code LOOP_SEQ_x} sequence for clause {@code x} (with {@code x} ranging from {@code 0} to {@code C-1}) has
1365      * the following shape. Again, assume slot {@code vx} is used to hold the state for clause {@code x}.
1366      * <blockquote><pre>{@code
1367      * LOOP_SEQ_x:  ALOAD steps
1368      *              CHECKCAST BoundMethodHandle$Species_LC
1369      *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the step handle for clause x
1370      *              CHECKCAST MethodHandle
1371      *              load locals
1372      *              load args
1373      *              INVOKEVIRTUAL MethodHandle.invokeBasic
1374      *              store vx
1375      *              ALOAD preds
1376      *              CHECKCAST BoundMethodHandle$Species_LC
1377      *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the pred handle for clause x
1378      *              CHECKCAST MethodHandle
1379      *              load locals
1380      *              load args
1381      *              INVOKEVIRTUAL MethodHandle.invokeBasic
1382      *              IFNE LOOP_SEQ_x+1                          // predicate returned false -> jump to next clause
1383      *              ALOAD finis
1384      *              CHECKCAST BoundMethodHandle$Species_LC
1385      *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the fini handle for clause x
1386      *              CHECKCAST MethodHandle
1387      *              load locals
1388      *              load args
1389      *              INVOKEVIRTUAL MethodHandle.invokeBasic
1390      *              GOTO DONE                                  // jump beyond end of clauses to return from loop
1391      * }</pre></blockquote>
1392      */
1393     private Name emitLoop(int pos) {
1394         Name args    = lambdaForm.names[pos];
1395         Name invoker = lambdaForm.names[pos+1];
1396         Name result  = lambdaForm.names[pos+2];
1397 
1398         // extract clause and loop-local state types
1399         // find the type info in the loop invocation
1400         BasicType[] loopClauseTypes = (BasicType[]) invoker.arguments[0];
1401         Class<?>[] loopLocalStateTypes = Stream.of(loopClauseTypes).
1402                 filter(bt -> bt != BasicType.V_TYPE).map(BasicType::basicTypeClass).toArray(Class<?>[]::new);
1403 
1404         final int firstLoopStateIndex = extendLocalsMap(loopLocalStateTypes);
1405 
1406         Class<?> returnType = result.function.resolvedHandle().type().returnType();
1407         MethodType loopType = args.function.resolvedHandle().type()
1408                 .dropParameterTypes(0,1)
1409                 .changeReturnType(returnType);
1410         MethodType loopHandleType = loopType.insertParameterTypes(0, loopLocalStateTypes);
1411         MethodType predType = loopHandleType.changeReturnType(boolean.class);
1412         MethodType finiType = loopHandleType;
1413 
1414         final int nClauses = loopClauseTypes.length;
1415 
1416         // indices to invoker arguments to load method handle arrays
1417         final int inits = 1;
1418         final int steps = 2;
1419         final int preds = 3;
1420         final int finis = 4;
1421 
1422         Label lLoop = new Label();
1423         Label lDone = new Label();
1424         Label lNext;
1425 
1426         final String speciesType = new StringBuilder("java/lang/invoke/BoundMethodHandle$Species_").
1427                 append(nClauses == 1 ? "L" : nClauses == 2 ? "LL" : "L" + nClauses).toString();
1428 
1429         // INIT:
1430         for (int c = 0, state = 0; c < nClauses; ++c) {
1431             MethodType cInitType = loopType.changeReturnType(loopClauseTypes[c].basicTypeClass());
1432             emitLoopHandleInvoke(invoker, speciesType, inits, c, args, false, cInitType, loopLocalStateTypes,
1433                     firstLoopStateIndex);
1434             if (cInitType.returnType() != void.class) {
1435                 emitStoreInsn(BasicType.basicType(cInitType.returnType()), firstLoopStateIndex + state);
1436                 ++state;
1437             }
1438         }
1439 
1440         // LOOP:
1441         mv.visitLabel(lLoop);
1442 
1443         for (int c = 0, state = 0; c < nClauses; ++c) {
1444             lNext = new Label();
1445 
1446             MethodType stepType = loopHandleType.changeReturnType(loopClauseTypes[c].basicTypeClass());
1447             boolean isVoid = stepType.returnType() == void.class;
1448 
1449             // invoke loop step
1450             emitLoopHandleInvoke(invoker, speciesType, steps, c, args, true, stepType, loopLocalStateTypes,
1451                     firstLoopStateIndex);
1452             if (!isVoid) {
1453                 emitStoreInsn(BasicType.basicType(stepType.returnType()), firstLoopStateIndex + state);
1454                 ++state;
1455             }
1456 
1457             // invoke loop predicate
1458             emitLoopHandleInvoke(invoker, speciesType, preds, c, args, true, predType, loopLocalStateTypes,
1459                     firstLoopStateIndex);
1460             mv.visitJumpInsn(Opcodes.IFNE, lNext);
1461 
1462             // invoke fini
1463             emitLoopHandleInvoke(invoker, speciesType, finis, c, args, true, finiType, loopLocalStateTypes,
1464                     firstLoopStateIndex);
1465             mv.visitJumpInsn(Opcodes.GOTO, lDone);
1466 
1467             // this is the beginning of the next loop clause
1468             mv.visitLabel(lNext);
1469         }
1470 
1471         mv.visitJumpInsn(Opcodes.GOTO, lLoop);
1472 
1473         // DONE:
1474         mv.visitLabel(lDone);
1475 
1476         return result;
1477     }
1478 
1479     private int extendLocalsMap(Class<?>[] types) {
1480         int firstSlot = localsMap.length - 1;
1481         localsMap = Arrays.copyOf(localsMap, localsMap.length + types.length);
1482         localClasses = Arrays.copyOf(localClasses, localClasses.length + types.length);
1483         System.arraycopy(types, 0, localClasses, firstSlot, types.length);
1484         int index = localsMap[firstSlot - 1] + 1;
1485         int lastSlots = 0;
1486         for (int i = 0; i < types.length; ++i) {
1487             localsMap[firstSlot + i] = index;
1488             lastSlots = BasicType.basicType(localClasses[firstSlot + i]).basicTypeSlots();
1489             index += lastSlots;
1490         }
1491         localsMap[localsMap.length - 1] = index - lastSlots;
1492         return firstSlot;
1493     }
1494 
1495     private void emitLoopHandleInvoke(Name holder, String speciesType, int handles, int clause, Name args,
1496                                       boolean pushLocalState, MethodType type, Class<?>[] loopLocalStateTypes,
1497                                       int firstLoopStateSlot) {
1498         // load handle for clause
1499         Name hname = (Name) holder.arguments[handles];
1500         emitLoadInsn(hname.type, hname.index());
1501         mv.visitTypeInsn(Opcodes.CHECKCAST, speciesType);
1502         mv.visitFieldInsn(Opcodes.GETFIELD, speciesType, "argL" + clause, OBJ_SIG);
1503         mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
1504         // load loop state (preceding the other arguments)
1505         if (pushLocalState) {
1506             for (int s = 0; s < loopLocalStateTypes.length; ++s) {
1507                 emitLoadInsn(BasicType.basicType(loopLocalStateTypes[s]), firstLoopStateSlot + s);
1508             }
1509         }
1510         // load loop args (skip 0: method handle)
1511         emitPushArguments(args, 1);
1512         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.toMethodDescriptorString(), false);
1513     }
1514 
1515     private void emitZero(BasicType type) {
1516         switch (type) {
1517             case I_TYPE: mv.visitInsn(Opcodes.ICONST_0); break;
1518             case J_TYPE: mv.visitInsn(Opcodes.LCONST_0); break;
1519             case F_TYPE: mv.visitInsn(Opcodes.FCONST_0); break;
1520             case D_TYPE: mv.visitInsn(Opcodes.DCONST_0); break;
1521             case L_TYPE: mv.visitInsn(Opcodes.ACONST_NULL); break;
1522             default: throw new InternalError("unknown type: " + type);
1523         }
1524     }
1525 
1526     private void emitPushArguments(Name args, int start) {
1527         MethodType type = args.function.methodType();
1528         for (int i = start; i < args.arguments.length; i++) {
1529             emitPushArgument(type.parameterType(i), args.arguments[i]);
1530         }
1531     }
1532 
1533     private void emitPushArgument(Name name, int paramIndex) {
1534         Object arg = name.arguments[paramIndex];
1535         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1536         emitPushArgument(ptype, arg);
1537     }
1538 
1539     private void emitPushArgument(Class<?> ptype, Object arg) {
1540         BasicType bptype = basicType(ptype);
1541         if (arg instanceof Name) {
1542             Name n = (Name) arg;
1543             emitLoadInsn(n.type, n.index());
1544             emitImplicitConversion(n.type, ptype, n);
1545         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1546             emitConst(arg);
1547         } else {
1548             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1549                 emitConst(arg);
1550             } else {
1551                 mv.visitLdcInsn(constantPlaceholder(arg));
1552                 emitImplicitConversion(L_TYPE, ptype, arg);
1553             }
1554         }
1555     }
1556 
1557     /**
1558      * Store the name to its local, if necessary.
1559      */
1560     private void emitStoreResult(Name name) {
1561         if (name != null && name.type != V_TYPE) {
1562             // non-void: actually assign
1563             emitStoreInsn(name.type, name.index());
1564         }
1565     }
1566 
1567     /**
1568      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1569      */
1570     private void emitReturn(Name onStack) {
1571         // return statement
1572         Class<?> rclass = invokerType.returnType();
1573         BasicType rtype = lambdaForm.returnType();
1574         assert(rtype == basicType(rclass));  // must agree
1575         if (rtype == V_TYPE) {
1576             // void
1577             mv.visitInsn(Opcodes.RETURN);
1578             // it doesn't matter what rclass is; the JVM will discard any value
1579         } else {
1580             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
1581 
1582             // put return value on the stack if it is not already there
1583             if (rn != onStack) {
1584                 emitLoadInsn(rtype, lambdaForm.result);
1585             }
1586 
1587             emitImplicitConversion(rtype, rclass, rn);
1588 
1589             // generate actual return statement
1590             emitReturnInsn(rtype);
1591         }
1592     }
1593 
1594     /**
1595      * Emit a type conversion bytecode casting from "from" to "to".
1596      */
1597     private void emitPrimCast(Wrapper from, Wrapper to) {
1598         // Here's how.
1599         // -   indicates forbidden
1600         // <-> indicates implicit
1601         //      to ----> boolean  byte     short    char     int      long     float    double
1602         // from boolean    <->        -        -        -        -        -        -        -
1603         //      byte        -       <->       i2s      i2c      <->      i2l      i2f      i2d
1604         //      short       -       i2b       <->      i2c      <->      i2l      i2f      i2d
1605         //      char        -       i2b       i2s      <->      <->      i2l      i2f      i2d
1606         //      int         -       i2b       i2s      i2c      <->      i2l      i2f      i2d
1607         //      long        -     l2i,i2b   l2i,i2s  l2i,i2c    l2i      <->      l2f      l2d
1608         //      float       -     f2i,i2b   f2i,i2s  f2i,i2c    f2i      f2l      <->      f2d
1609         //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i      d2l      d2f      <->
1610         if (from == to) {
1611             // no cast required, should be dead code anyway
1612             return;
1613         }
1614         if (from.isSubwordOrInt()) {
1615             // cast from {byte,short,char,int} to anything
1616             emitI2X(to);
1617         } else {
1618             // cast from {long,float,double} to anything
1619             if (to.isSubwordOrInt()) {
1620                 // cast to {byte,short,char,int}
1621                 emitX2I(from);
1622                 if (to.bitWidth() < 32) {
1623                     // targets other than int require another conversion
1624                     emitI2X(to);
1625                 }
1626             } else {
1627                 // cast to {long,float,double} - this is verbose
1628                 boolean error = false;
1629                 switch (from) {
1630                 case LONG:
1631                     switch (to) {
1632                     case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
1633                     case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
1634                     default:      error = true;               break;
1635                     }
1636                     break;
1637                 case FLOAT:
1638                     switch (to) {
1639                     case LONG :   mv.visitInsn(Opcodes.F2L);  break;
1640                     case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
1641                     default:      error = true;               break;
1642                     }
1643                     break;
1644                 case DOUBLE:
1645                     switch (to) {
1646                     case LONG :   mv.visitInsn(Opcodes.D2L);  break;
1647                     case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
1648                     default:      error = true;               break;
1649                     }
1650                     break;
1651                 default:
1652                     error = true;
1653                     break;
1654                 }
1655                 if (error) {
1656                     throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
1657                 }
1658             }
1659         }
1660     }
1661 
1662     private void emitI2X(Wrapper type) {
1663         switch (type) {
1664         case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
1665         case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
1666         case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
1667         case INT:     /* naught */                break;
1668         case LONG:    mv.visitInsn(Opcodes.I2L);  break;
1669         case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
1670         case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
1671         case BOOLEAN:
1672             // For compatibility with ValueConversions and explicitCastArguments:
1673             mv.visitInsn(Opcodes.ICONST_1);
1674             mv.visitInsn(Opcodes.IAND);
1675             break;
1676         default:   throw new InternalError("unknown type: " + type);
1677         }
1678     }
1679 
1680     private void emitX2I(Wrapper type) {
1681         switch (type) {
1682         case LONG:    mv.visitInsn(Opcodes.L2I);  break;
1683         case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
1684         case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
1685         default:      throw new InternalError("unknown type: " + type);
1686         }
1687     }
1688 
1689     /**
1690      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
1691      */
1692     static MemberName generateLambdaFormInterpreterEntryPoint(MethodType mt) {
1693         assert(isValidSignature(basicTypeSignature(mt)));
1694         String name = "interpret_"+basicTypeChar(mt.returnType());
1695         MethodType type = mt;  // includes leading argument
1696         type = type.changeParameterType(0, MethodHandle.class);
1697         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
1698         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
1699     }
1700 
1701     private byte[] generateLambdaFormInterpreterEntryPointBytes() {
1702         classFilePrologue();
1703         methodPrologue();
1704 
1705         // Suppress this method in backtraces displayed to the user.
1706         mv.visitAnnotation(LF_HIDDEN_SIG, true);
1707 
1708         // Don't inline the interpreter entry.
1709         mv.visitAnnotation(DONTINLINE_SIG, true);
1710 
1711         // create parameter array
1712         emitIconstInsn(invokerType.parameterCount());
1713         mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1714 
1715         // fill parameter array
1716         for (int i = 0; i < invokerType.parameterCount(); i++) {
1717             Class<?> ptype = invokerType.parameterType(i);
1718             mv.visitInsn(Opcodes.DUP);
1719             emitIconstInsn(i);
1720             emitLoadInsn(basicType(ptype), i);
1721             // box if primitive type
1722             if (ptype.isPrimitive()) {
1723                 emitBoxing(Wrapper.forPrimitiveType(ptype));
1724             }
1725             mv.visitInsn(Opcodes.AASTORE);
1726         }
1727         // invoke
1728         emitAloadInsn(0);
1729         mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1730         mv.visitInsn(Opcodes.SWAP);  // swap form and array; avoid local variable
1731         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1732 
1733         // maybe unbox
1734         Class<?> rtype = invokerType.returnType();
1735         if (rtype.isPrimitive() && rtype != void.class) {
1736             emitUnboxing(Wrapper.forPrimitiveType(rtype));
1737         }
1738 
1739         // return statement
1740         emitReturnInsn(basicType(rtype));
1741 
1742         methodEpilogue();
1743         bogusMethod(invokerType);
1744 
1745         final byte[] classFile = cw.toByteArray();
1746         maybeDump(className, classFile);
1747         return classFile;
1748     }
1749 
1750     /**
1751      * Generate bytecode for a NamedFunction invoker.
1752      */
1753     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1754         MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1755         String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1756         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1757         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1758     }
1759 
1760     private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1761         MethodType dstType = typeForm.erasedType();
1762         classFilePrologue();
1763         methodPrologue();
1764 
1765         // Suppress this method in backtraces displayed to the user.
1766         mv.visitAnnotation(LF_HIDDEN_SIG, true);
1767 
1768         // Force inlining of this invoker method.
1769         mv.visitAnnotation(FORCEINLINE_SIG, true);
1770 
1771         // Load receiver
1772         emitAloadInsn(0);
1773 
1774         // Load arguments from array
1775         for (int i = 0; i < dstType.parameterCount(); i++) {
1776             emitAloadInsn(1);
1777             emitIconstInsn(i);
1778             mv.visitInsn(Opcodes.AALOAD);
1779 
1780             // Maybe unbox
1781             Class<?> dptype = dstType.parameterType(i);
1782             if (dptype.isPrimitive()) {
1783                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
1784                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
1785                 emitUnboxing(srcWrapper);
1786                 emitPrimCast(srcWrapper, dstWrapper);
1787             }
1788         }
1789 
1790         // Invoke
1791         String targetDesc = dstType.basicType().toMethodDescriptorString();
1792         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1793 
1794         // Box primitive types
1795         Class<?> rtype = dstType.returnType();
1796         if (rtype != void.class && rtype.isPrimitive()) {
1797             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1798             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
1799             // boolean casts not allowed
1800             emitPrimCast(srcWrapper, dstWrapper);
1801             emitBoxing(dstWrapper);
1802         }
1803 
1804         // If the return type is void we return a null reference.
1805         if (rtype == void.class) {
1806             mv.visitInsn(Opcodes.ACONST_NULL);
1807         }
1808         emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
1809 
1810         methodEpilogue();
1811         bogusMethod(dstType);
1812 
1813         final byte[] classFile = cw.toByteArray();
1814         maybeDump(className, classFile);
1815         return classFile;
1816     }
1817 
1818     /**
1819      * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1820      * for debugging purposes.
1821      */
1822     private void bogusMethod(Object... os) {
1823         if (DUMP_CLASS_FILES) {
1824             mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1825             for (Object o : os) {
1826                 mv.visitLdcInsn(o.toString());
1827                 mv.visitInsn(Opcodes.POP);
1828             }
1829             mv.visitInsn(Opcodes.RETURN);
1830             mv.visitMaxs(0, 0);
1831             mv.visitEnd();
1832         }
1833     }
1834 }