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