1 /*
   2  * Copyright (c) 2012, 2013, 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 java.io.*;
  29 import java.util.*;
  30 import java.lang.reflect.Modifier;
  31 
  32 import jdk.internal.org.objectweb.asm.*;
  33 
  34 import static java.lang.invoke.LambdaForm.*;
  35 import static java.lang.invoke.LambdaForm.BasicType.*;
  36 import static java.lang.invoke.MethodHandleStatics.*;
  37 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  38 import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
  39 import sun.invoke.util.ValueConversions;
  40 import sun.invoke.util.VerifyType;
  41 import sun.invoke.util.VerifyAccess;
  42 import sun.invoke.util.Wrapper;
  43 
  44 /**
  45  * Code generation backend for LambdaForm.
  46  * <p>
  47  * @author John Rose, JSR 292 EG
  48  */
  49 class InvokerBytecodeGenerator {
  50     /** Define class names for convenience. */
  51     private static final String MH      = "java/lang/invoke/MethodHandle";
  52     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  53     private static final String LF      = "java/lang/invoke/LambdaForm";
  54     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  55     private static final String CLS     = "java/lang/Class";
  56     private static final String OBJ     = "java/lang/Object";
  57     private static final String OBJARY  = "[Ljava/lang/Object;";
  58 
  59     private static final String LF_SIG  = "L" + LF + ";";
  60     private static final String LFN_SIG = "L" + LFN + ";";
  61     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  62     private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";";
  63 
  64     /** Name of its super class*/
  65     private static final String superName = LF;
  66 
  67     /** Name of new class */
  68     private final String className;
  69 
  70     /** Name of the source file (for stack trace printing). */
  71     private final String sourceFile;
  72 
  73     private final LambdaForm lambdaForm;
  74     private final String     invokerName;
  75     private final MethodType invokerType;
  76 
  77     /** Info about local variables in compiled lambda form */
  78     private final int[] localsMap;         // index
  79     private final BasicType[] localTypes;  // basic type
  80     private final Class<?>[] localClasses; // type
  81 
  82     /** ASM bytecode generation. */
  83     private ClassWriter cw;
  84     private MethodVisitor mv;
  85 
  86     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
  87     private static final Class<?> HOST_CLASS = LambdaForm.class;
  88 
  89     /** Main constructor; other constructors delegate to this one. */
  90     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
  91                                      String className, String invokerName, MethodType invokerType) {
  92         if (invokerName.contains(".")) {
  93             int p = invokerName.indexOf(".");
  94             className = invokerName.substring(0, p);
  95             invokerName = invokerName.substring(p+1);
  96         }
  97         if (DUMP_CLASS_FILES) {
  98             className = makeDumpableClassName(className);
  99         }
 100         this.className  = superName + "$" + className;
 101         this.sourceFile = "LambdaForm$" + className;
 102         this.lambdaForm = lambdaForm;
 103         this.invokerName = invokerName;
 104         this.invokerType = invokerType;
 105         this.localsMap = new int[localsMapSize+1];
 106         // last entry of localsMap is count of allocated local slots
 107         this.localTypes = new BasicType[localsMapSize+1];
 108         this.localClasses = new Class<?>[localsMapSize+1];
 109     }
 110 
 111     /** For generating LambdaForm interpreter entry points. */
 112     private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
 113         this(null, invokerType.parameterCount(),
 114              className, invokerName, invokerType);
 115         // Create an array to map name indexes to locals indexes.
 116         localTypes[localTypes.length - 1] = V_TYPE;
 117         for (int i = 0; i < localsMap.length; i++) {
 118             localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
 119             if (i < invokerType.parameterCount())
 120                 localTypes[i] = basicType(invokerType.parameterType(i));
 121         }
 122     }
 123 
 124     /** For generating customized code for a single LambdaForm. */
 125     private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
 126         this(form, form.names.length,
 127              className, form.debugName, invokerType);
 128         // Create an array to map name indexes to locals indexes.
 129         Name[] names = form.names;
 130         for (int i = 0, index = 0; i < localsMap.length; i++) {
 131             localsMap[i] = index;
 132             if (i < names.length) {
 133                 BasicType type = names[i].type();
 134                 index += type.basicTypeSlots();
 135                 localTypes[i] = type;
 136             }
 137         }
 138     }
 139 
 140 
 141     /** instance counters for dumped classes */
 142     private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
 143     /** debugging flag for saving generated class files */
 144     private final static File DUMP_CLASS_FILES_DIR;
 145 
 146     static {
 147         if (DUMP_CLASS_FILES) {
 148             DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
 149             try {
 150                 File dumpDir = new File("DUMP_CLASS_FILES");
 151                 if (!dumpDir.exists()) {
 152                     dumpDir.mkdirs();
 153                 }
 154                 DUMP_CLASS_FILES_DIR = dumpDir;
 155                 System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
 156             } catch (Exception e) {
 157                 throw newInternalError(e);
 158             }
 159         } else {
 160             DUMP_CLASS_FILES_COUNTERS = null;
 161             DUMP_CLASS_FILES_DIR = null;
 162         }
 163     }
 164 
 165     static void maybeDump(final String className, final byte[] classFile) {
 166         if (DUMP_CLASS_FILES) {
 167             java.security.AccessController.doPrivileged(
 168             new java.security.PrivilegedAction<Void>() {
 169                 public Void run() {
 170                     try {
 171                         String dumpName = className;
 172                         //dumpName = dumpName.replace('/', '-');
 173                         File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
 174                         System.out.println("dump: " + dumpFile);
 175                         dumpFile.getParentFile().mkdirs();
 176                         FileOutputStream file = new FileOutputStream(dumpFile);
 177                         file.write(classFile);
 178                         file.close();
 179                         return null;
 180                     } catch (IOException ex) {
 181                         throw newInternalError(ex);
 182                     }
 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 String placeholder;
 206         final Object value;
 207         CpPatch(int index, String placeholder, Object value) {
 208             this.index = index;
 209             this.placeholder = placeholder;
 210             this.value = value;
 211         }
 212         public String toString() {
 213             return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
 214         }
 215     }
 216 
 217     Map<Object, CpPatch> cpPatches = new HashMap<>();
 218 
 219     int cph = 0;  // for counting constant placeholders
 220 
 221     String constantPlaceholder(Object arg) {
 222         String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
 223         if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>";  // debugging aid
 224         if (cpPatches.containsKey(cpPlaceholder)) {
 225             throw new InternalError("observed CP placeholder twice: " + cpPlaceholder);
 226         }
 227         // insert placeholder in CP and remember the patch
 228         int index = cw.newConst((Object) cpPlaceholder);  // TODO check if aready in the constant pool
 229         cpPatches.put(cpPlaceholder, new CpPatch(index, cpPlaceholder, arg));
 230         return cpPlaceholder;
 231     }
 232 
 233     Object[] cpPatches(byte[] classFile) {
 234         int size = getConstantPoolSize(classFile);
 235         Object[] res = new Object[size];
 236         for (CpPatch p : cpPatches.values()) {
 237             if (p.index >= size)
 238                 throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
 239             res[p.index] = p.value;
 240         }
 241         return res;
 242     }
 243 
 244     private static String debugString(Object arg) {
 245         if (arg instanceof MethodHandle) {
 246             MethodHandle mh = (MethodHandle) arg;
 247             MemberName member = mh.internalMemberName();
 248             if (member != null)
 249                 return member.toString();
 250             return mh.debugString();
 251         }
 252         return arg.toString();
 253     }
 254 
 255     /**
 256      * Extract the number of constant pool entries from a given class file.
 257      *
 258      * @param classFile the bytes of the class file in question.
 259      * @return the number of entries in the constant pool.
 260      */
 261     private static int getConstantPoolSize(byte[] classFile) {
 262         // The first few bytes:
 263         // u4 magic;
 264         // u2 minor_version;
 265         // u2 major_version;
 266         // u2 constant_pool_count;
 267         return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
 268     }
 269 
 270     /**
 271      * Extract the MemberName of a newly-defined method.
 272      */
 273     private MemberName loadMethod(byte[] classFile) {
 274         Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
 275         return resolveInvokerMember(invokerClass, invokerName, invokerType);
 276     }
 277 
 278     /**
 279      * Define a given class as anonymous class in the runtime system.
 280      */
 281     private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
 282         Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
 283         UNSAFE.ensureClassInitialized(invokerClass);  // Make sure the class is initialized; VM might complain.
 284         return invokerClass;
 285     }
 286 
 287     private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
 288         MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
 289         //System.out.println("resolveInvokerMember => "+member);
 290         //for (Method m : invokerClass.getDeclaredMethods())  System.out.println("  "+m);
 291         try {
 292             member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
 293         } catch (ReflectiveOperationException e) {
 294             throw newInternalError(e);
 295         }
 296         //System.out.println("resolveInvokerMember => "+member);
 297         return member;
 298     }
 299 
 300     /**
 301      * Set up class file generation.
 302      */
 303     private void classFilePrologue() {
 304         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 305         cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
 306         cw.visitSource(sourceFile, null);
 307 
 308         String invokerDesc = invokerType.toMethodDescriptorString();
 309         mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
 310     }
 311 
 312     /**
 313      * Tear down class file generation.
 314      */
 315     private void classFileEpilogue() {
 316         mv.visitMaxs(0, 0);
 317         mv.visitEnd();
 318     }
 319 
 320     /*
 321      * Low-level emit helpers.
 322      */
 323     private void emitConst(Object con) {
 324         if (con == null) {
 325             mv.visitInsn(Opcodes.ACONST_NULL);
 326             return;
 327         }
 328         if (con instanceof Integer) {
 329             emitIconstInsn((int) con);
 330             return;
 331         }
 332         if (con instanceof Long) {
 333             long x = (long) con;
 334             if (x == (short) x) {
 335                 emitIconstInsn((int) x);
 336                 mv.visitInsn(Opcodes.I2L);
 337                 return;
 338             }
 339         }
 340         if (con instanceof Float) {
 341             float x = (float) con;
 342             if (x == (short) x) {
 343                 emitIconstInsn((int) x);
 344                 mv.visitInsn(Opcodes.I2F);
 345                 return;
 346             }
 347         }
 348         if (con instanceof Double) {
 349             double x = (double) con;
 350             if (x == (short) x) {
 351                 emitIconstInsn((int) x);
 352                 mv.visitInsn(Opcodes.I2D);
 353                 return;
 354             }
 355         }
 356         if (con instanceof Boolean) {
 357             emitIconstInsn((boolean) con ? 1 : 0);
 358             return;
 359         }
 360         // fall through:
 361         mv.visitLdcInsn(con);
 362     }
 363 
 364     private void emitIconstInsn(int i) {
 365         int opcode;
 366         switch (i) {
 367         case 0:  opcode = Opcodes.ICONST_0;  break;
 368         case 1:  opcode = Opcodes.ICONST_1;  break;
 369         case 2:  opcode = Opcodes.ICONST_2;  break;
 370         case 3:  opcode = Opcodes.ICONST_3;  break;
 371         case 4:  opcode = Opcodes.ICONST_4;  break;
 372         case 5:  opcode = Opcodes.ICONST_5;  break;
 373         default:
 374             if (i == (byte) i) {
 375                 mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
 376             } else if (i == (short) i) {
 377                 mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
 378             } else {
 379                 mv.visitLdcInsn(i);
 380             }
 381             return;
 382         }
 383         mv.visitInsn(opcode);
 384     }
 385 
 386     /*
 387      * NOTE: These load/store methods use the localsMap to find the correct index!
 388      */
 389     private void emitLoadInsn(BasicType type, int index) {
 390         int opcode = loadInsnOpcode(type);
 391         mv.visitVarInsn(opcode, localsMap[index]);
 392     }
 393 
 394     private int loadInsnOpcode(BasicType type) throws InternalError {
 395         int opcode;
 396         switch (type) {
 397         case I_TYPE:  opcode = Opcodes.ILOAD;  break;
 398         case J_TYPE:  opcode = Opcodes.LLOAD;  break;
 399         case F_TYPE:  opcode = Opcodes.FLOAD;  break;
 400         case D_TYPE:  opcode = Opcodes.DLOAD;  break;
 401         case L_TYPE:  opcode = Opcodes.ALOAD;  break;
 402         default:
 403             throw new InternalError("unknown type: " + type);
 404         }
 405         return opcode;
 406     }
 407     private void emitAloadInsn(int index) {
 408         emitLoadInsn(L_TYPE, index);
 409     }
 410 
 411     private void emitStoreInsn(BasicType type, int index) {
 412         int opcode = storeInsnOpcode(type);
 413         mv.visitVarInsn(opcode, localsMap[index]);
 414     }
 415 
 416     private int storeInsnOpcode(BasicType type) throws InternalError {
 417         int opcode;
 418         switch (type) {
 419         case I_TYPE:  opcode = Opcodes.ISTORE;  break;
 420         case J_TYPE:  opcode = Opcodes.LSTORE;  break;
 421         case F_TYPE:  opcode = Opcodes.FSTORE;  break;
 422         case D_TYPE:  opcode = Opcodes.DSTORE;  break;
 423         case L_TYPE:  opcode = Opcodes.ASTORE;  break;
 424         default:
 425             throw new InternalError("unknown type: " + type);
 426         }
 427         return opcode;
 428     }
 429     private void emitAstoreInsn(int index) {
 430         emitStoreInsn(L_TYPE, index);
 431     }
 432 
 433     private void freeFrameLocal(int oldFrameLocal) {
 434         int i = indexForFrameLocal(oldFrameLocal);
 435         if (i < 0)  return;
 436         BasicType type = localTypes[i];
 437         int newFrameLocal = makeLocalTemp(type);
 438         mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
 439         mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
 440         assert(localsMap[i] == oldFrameLocal);
 441         localsMap[i] = newFrameLocal;
 442         assert(indexForFrameLocal(oldFrameLocal) < 0);
 443     }
 444     private int indexForFrameLocal(int frameLocal) {
 445         for (int i = 0; i < localsMap.length; i++) {
 446             if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
 447                 return i;
 448         }
 449         return -1;
 450     }
 451     private int makeLocalTemp(BasicType type) {
 452         int frameLocal = localsMap[localsMap.length - 1];
 453         localsMap[localsMap.length - 1] = frameLocal + type.basicTypeSlots();
 454         return frameLocal;
 455     }
 456 
 457     /**
 458      * Emit a boxing call.
 459      *
 460      * @param wrapper primitive type class to box.
 461      */
 462     private void emitBoxing(Wrapper wrapper) {
 463         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 464         String name  = "valueOf";
 465         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
 466         mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
 467     }
 468 
 469     /**
 470      * Emit an unboxing call (plus preceding checkcast).
 471      *
 472      * @param wrapper wrapper type class to unbox.
 473      */
 474     private void emitUnboxing(Wrapper wrapper) {
 475         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 476         String name  = wrapper.primitiveSimpleName() + "Value";
 477         String desc  = "()" + wrapper.basicTypeChar();
 478         emitReferenceCast(wrapper.wrapperType(), null);
 479         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
 480     }
 481 
 482     /**
 483      * Emit an implicit conversion for an argument which must be of the given pclass.
 484      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 485      *
 486      * @param ptype type of value present on stack
 487      * @param pclass type of value required on stack
 488      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 489      */
 490     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 491         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 492         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 493             return;   // nothing to do
 494         switch (ptype) {
 495             case L_TYPE:
 496                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 497                     if (PROFILE_LEVEL > 0)
 498                         emitReferenceCast(Object.class, arg);
 499                     return;
 500                 }
 501                 emitReferenceCast(pclass, arg);
 502                 return;
 503             case I_TYPE:
 504                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 505                     emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
 506                 return;
 507         }
 508         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 509     }
 510 
 511     /** Update localClasses type map.  Return true if the information is already present. */
 512     private boolean assertStaticType(Class<?> cls, Name n) {
 513         int local = n.index();
 514         Class<?> aclass = localClasses[local];
 515         if (aclass != null && (aclass == cls || cls.isAssignableFrom(aclass))) {
 516             return true;  // type info is already present
 517         } else if (aclass == null || aclass.isAssignableFrom(cls)) {
 518             localClasses[local] = cls;  // type info can be improved
 519         }
 520         return false;
 521     }
 522 
 523     private void emitReferenceCast(Class<?> cls, Object arg) {
 524         Name writeBack = null;  // local to write back result
 525         if (arg instanceof Name) {
 526             Name n = (Name) arg;
 527             if (assertStaticType(cls, n))
 528                 return;  // this cast was already performed
 529             if (lambdaForm.useCount(n) > 1) {
 530                 // This guy gets used more than once.
 531                 writeBack = n;
 532             }
 533         }
 534         if (isStaticallyNameable(cls)) {
 535             String sig = getInternalName(cls);
 536             mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
 537         } else {
 538             mv.visitLdcInsn(constantPlaceholder(cls));
 539             mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
 540             mv.visitInsn(Opcodes.SWAP);
 541             mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
 542             if (Object[].class.isAssignableFrom(cls))
 543                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
 544             else if (PROFILE_LEVEL > 0)
 545                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
 546         }
 547         if (writeBack != null) {
 548             mv.visitInsn(Opcodes.DUP);
 549             emitAstoreInsn(writeBack.index());
 550         }
 551     }
 552 
 553     /**
 554      * Emits an actual return instruction conforming to the given return type.
 555      */
 556     private void emitReturnInsn(BasicType type) {
 557         int opcode;
 558         switch (type) {
 559         case I_TYPE:  opcode = Opcodes.IRETURN;  break;
 560         case J_TYPE:  opcode = Opcodes.LRETURN;  break;
 561         case F_TYPE:  opcode = Opcodes.FRETURN;  break;
 562         case D_TYPE:  opcode = Opcodes.DRETURN;  break;
 563         case L_TYPE:  opcode = Opcodes.ARETURN;  break;
 564         case V_TYPE:  opcode = Opcodes.RETURN;   break;
 565         default:
 566             throw new InternalError("unknown return type: " + type);
 567         }
 568         mv.visitInsn(opcode);
 569     }
 570 
 571     private static String getInternalName(Class<?> c) {
 572         if (c == Object.class)             return OBJ;
 573         else if (c == Object[].class)      return OBJARY;
 574         else if (c == Class.class)         return CLS;
 575         else if (c == MethodHandle.class)  return MH;
 576         assert(VerifyAccess.isTypeVisible(c, Object.class));
 577         return c.getName().replace('.', '/');
 578     }
 579 
 580     /**
 581      * Generate customized bytecode for a given LambdaForm.
 582      */
 583     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
 584         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
 585         return g.loadMethod(g.generateCustomizedCodeBytes());
 586     }
 587 
 588     /**
 589      * Generate an invoker method for the passed {@link LambdaForm}.
 590      */
 591     private byte[] generateCustomizedCodeBytes() {
 592         classFilePrologue();
 593 
 594         // Suppress this method in backtraces displayed to the user.
 595         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 596 
 597         // Mark this method as a compiled LambdaForm
 598         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
 599 
 600         // Force inlining of this invoker method.
 601         mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
 602 
 603         // iterate over the form's names, generating bytecode instructions for each
 604         // start iterating at the first name following the arguments
 605         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 606             Name name = lambdaForm.names[i];
 607             MemberName member = name.function.member();
 608             Class<?> rtype = name.function.methodType().returnType();
 609 
 610             if (isSelectAlternative(i)) {
 611                 emitSelectAlternative(name, lambdaForm.names[i + 1]);
 612                 i++;  // skip MH.invokeBasic of the selectAlternative result
 613             } else if (isGuardWithCatch(i)) {
 614                 emitGuardWithCatch(i);
 615                 i = i+2; // Jump to the end of GWC idiom
 616             } else if (isNewArray(rtype, name)) {
 617                 emitNewArray(rtype, name);
 618             } else if (isStaticallyInvocable(member)) {
 619                 if (isLinkerMethodInvoke(name))
 620                     preserveLinkerMethodTarget(name);
 621                 emitStaticInvoke(member, name);
 622             } else {
 623                 emitInvoke(name);
 624             }
 625 
 626             // Update cached form name's info in case an intrinsic spanning multiple names was encountered.
 627             name = lambdaForm.names[i];
 628             member = name.function.member();
 629             rtype = name.function.methodType().returnType();
 630 
 631             // store the result from evaluating to the target name in a local if required
 632             // (if this is the last value, i.e., the one that is going to be returned,
 633             // avoid store/load/return and just return)
 634             if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
 635                 // return value - do nothing
 636             } else if (name.type != V_TYPE) {
 637                 // non-void: actually assign
 638                 emitStoreInsn(name.type, name.index());
 639             }
 640         }
 641 
 642         // return statement
 643         emitReturn();
 644 
 645         classFileEpilogue();
 646         bogusMethod(lambdaForm);
 647 
 648         final byte[] classFile = cw.toByteArray();
 649         maybeDump(className, classFile);
 650         return classFile;
 651     }
 652 
 653     /** Certain parts of the JVM expect that, when a call to linkToStatic is made,
 654      *  the DMH that produced its MN argument is in local #0.
 655      *  This is often true, since the lambda form of a DMH will start with
 656      *  the DMH 'l'in arg 0 (local #0) and will end with a call to its linker method.
 657      *  But if the DMH is transformed, a new lambda form may be created with
 658      *  the DMH placed elsewhere.
 659      */
 660     private void preserveLinkerMethodTarget(Name name) {
 661         Object lastArg = name.arguments[name.arguments.length - 1];
 662         Name targetMember = (Name) lastArg;
 663         assert(targetMember.type() == L_TYPE &&
 664                 !targetMember.isParam() &&
 665                 isStaticallyInvocable(targetMember.function.member()) &&
 666                 targetMember.arguments.length == 1);
 667         Object targetDMH = DirectMethodHandle.findDirectMethodHandle(targetMember);
 668         assert(targetDMH != null);
 669         if (!(targetDMH instanceof Name && ((Name)targetDMH).index() == 0)) {
 670             // Oops, the DMH is not in a local #0, or is a constant.
 671             int DMH_FRAME_INDEX = 0;  // hardwired to local #0
 672             BasicType DMH_TYPE = L_TYPE;
 673             freeFrameLocal(DMH_FRAME_INDEX);
 674             // Save it to local #0:
 675             emitPushArgument(Object.class, targetDMH);
 676             mv.visitVarInsn(storeInsnOpcode(DMH_TYPE), DMH_FRAME_INDEX);
 677         }
 678     }
 679 
 680     /**
 681      * Emit an invoke for the given name.
 682      */
 683     void emitInvoke(Name name) {
 684         assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 685         if (true) {
 686             // push receiver
 687             MethodHandle target = name.function.resolvedHandle;
 688             assert(target != null) : name.exprString();
 689             mv.visitLdcInsn(constantPlaceholder(target));
 690             emitReferenceCast(MethodHandle.class, target);
 691         } else {
 692             // load receiver
 693             emitAloadInsn(0);
 694             emitReferenceCast(MethodHandle.class, null);
 695             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
 696             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
 697             // TODO more to come
 698         }
 699 
 700         // push arguments
 701         for (int i = 0; i < name.arguments.length; i++) {
 702             emitPushArgument(name, i);
 703         }
 704 
 705         // invocation
 706         MethodType type = name.function.methodType();
 707         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 708     }
 709 
 710     static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
 711         // Sample classes from each package we are willing to bind to statically:
 712         java.lang.Object.class,
 713         java.util.Arrays.class,
 714         sun.misc.Unsafe.class
 715         //MethodHandle.class already covered
 716     };
 717 
 718     static boolean isStaticallyInvocable(MemberName member) {
 719         if (member == null)  return false;
 720         if (member.isConstructor())  return false;
 721         Class<?> cls = member.getDeclaringClass();
 722         if (cls.isArray() || cls.isPrimitive())
 723             return false;  // FIXME
 724         if (cls.isAnonymousClass() || cls.isLocalClass())
 725             return false;  // inner class of some sort
 726         if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
 727             return false;  // not on BCP
 728         MethodType mtype = member.getMethodOrFieldType();
 729         if (!isStaticallyNameable(mtype.returnType()))
 730             return false;
 731         for (Class<?> ptype : mtype.parameterArray())
 732             if (!isStaticallyNameable(ptype))
 733                 return false;
 734         if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
 735             return true;   // in java.lang.invoke package
 736         if (member.isPublic() && isStaticallyNameable(cls))
 737             return true;
 738         return false;
 739     }
 740 
 741     static boolean isStaticallyNameable(Class<?> cls) {
 742         if (cls == Object.class)
 743             return true;
 744         while (cls.isArray())
 745             cls = cls.getComponentType();
 746         if (cls.isPrimitive())
 747             return true;  // int[].class, for example
 748         // could use VerifyAccess.isClassAccessible but the following is a safe approximation
 749         if (cls.getClassLoader() != Object.class.getClassLoader())
 750             return false;
 751         if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
 752             return true;
 753         if (!Modifier.isPublic(cls.getModifiers()))
 754             return false;
 755         for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
 756             if (VerifyAccess.isSamePackage(pkgcls, cls))
 757                 return true;
 758         }
 759         return false;
 760     }
 761 
 762     /**
 763      * Emit an invoke for the given name, using the MemberName directly.
 764      */
 765     void emitStaticInvoke(MemberName member, Name name) {
 766         assert(member.equals(name.function.member()));
 767         Class<?> defc = member.getDeclaringClass();
 768         String cname = getInternalName(defc);
 769         String mname = member.getName();
 770         String mtype;
 771         byte refKind = member.getReferenceKind();
 772         if (refKind == REF_invokeSpecial) {
 773             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 774             assert(member.canBeStaticallyBound()) : member;
 775             refKind = REF_invokeVirtual;
 776         }
 777 
 778         if (member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual) {
 779             // Methods from Object declared in an interface can be resolved by JVM to invokevirtual kind.
 780             // Need to convert it back to invokeinterface to pass verification and make the invocation works as expected.
 781             refKind = REF_invokeInterface;
 782         }
 783 
 784         // push arguments
 785         for (int i = 0; i < name.arguments.length; i++) {
 786             emitPushArgument(name, i);
 787         }
 788 
 789         // invocation
 790         if (defc == ArrayAccessor.class &&
 791                 match(member, ArrayAccessor.OBJECT_ARRAY_GETTER)) {
 792             mv.visitInsn(Opcodes.AALOAD);
 793         } else if (defc == ArrayAccessor.class &&
 794                 match(member, ArrayAccessor.OBJECT_ARRAY_SETTER)) {
 795             mv.visitInsn(Opcodes.AASTORE);
 796         } else if (member.isMethod()) {
 797             mtype = member.getMethodType().toMethodDescriptorString();
 798             mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype,
 799                                member.getDeclaringClass().isInterface());
 800         } else {
 801             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 802             mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
 803         }
 804         // Issue a type assertion for the result, so we can avoid casts later.
 805         if (name.type == L_TYPE) {
 806             Class<?> rtype = member.getInvocationType().returnType();
 807             assert(!rtype.isPrimitive());
 808             if (rtype != Object.class && !rtype.isInterface()) {
 809                 assertStaticType(rtype, name);
 810             }
 811         }
 812     }
 813 
 814     boolean isNewArray(Class<?> rtype, Name name) {
 815         return rtype.isArray() &&
 816                 isStaticallyNameable(rtype) &&
 817                 isArrayBuilder(name.function.resolvedHandle) &&
 818                 name.arguments.length > 0;
 819     }
 820 
 821     void emitNewArray(Class<?> rtype, Name name) throws InternalError {
 822         Class<?> arrayElementType = rtype.getComponentType();
 823         emitIconstInsn(name.arguments.length);
 824         int xas;
 825         if (!arrayElementType.isPrimitive()) {
 826             mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
 827             xas = Opcodes.AASTORE;
 828         } else {
 829             int tc;
 830             switch (Wrapper.forPrimitiveType(arrayElementType)) {
 831             case BOOLEAN: tc = Opcodes.T_BOOLEAN; xas = Opcodes.BASTORE; break;
 832             case BYTE:    tc = Opcodes.T_BYTE;    xas = Opcodes.BASTORE; break;
 833             case CHAR:    tc = Opcodes.T_CHAR;    xas = Opcodes.CASTORE; break;
 834             case SHORT:   tc = Opcodes.T_SHORT;   xas = Opcodes.SASTORE; break;
 835             case INT:     tc = Opcodes.T_INT;     xas = Opcodes.IASTORE; break;
 836             case LONG:    tc = Opcodes.T_LONG;    xas = Opcodes.LASTORE; break;
 837             case FLOAT:   tc = Opcodes.T_FLOAT;   xas = Opcodes.FASTORE; break;
 838             case DOUBLE:  tc = Opcodes.T_DOUBLE;  xas = Opcodes.DASTORE; break;
 839             default:      throw new InternalError(rtype.getName());
 840             }
 841             mv.visitIntInsn(Opcodes.NEWARRAY, tc);
 842         }
 843         // store arguments
 844         for (int i = 0; i < name.arguments.length; i++) {
 845             mv.visitInsn(Opcodes.DUP);
 846             emitIconstInsn(i);
 847             emitPushArgument(name, i);
 848             mv.visitInsn(xas);
 849         }
 850         // the array is left on the stack
 851         assertStaticType(rtype, name);
 852     }
 853     int refKindOpcode(byte refKind) {
 854         switch (refKind) {
 855         case REF_invokeVirtual:      return Opcodes.INVOKEVIRTUAL;
 856         case REF_invokeStatic:       return Opcodes.INVOKESTATIC;
 857         case REF_invokeSpecial:      return Opcodes.INVOKESPECIAL;
 858         case REF_invokeInterface:    return Opcodes.INVOKEINTERFACE;
 859         case REF_getField:           return Opcodes.GETFIELD;
 860         case REF_putField:           return Opcodes.PUTFIELD;
 861         case REF_getStatic:          return Opcodes.GETSTATIC;
 862         case REF_putStatic:          return Opcodes.PUTSTATIC;
 863         }
 864         throw new InternalError("refKind="+refKind);
 865     }
 866 
 867     static boolean isArrayBuilder(MethodHandle fn) {
 868         if (fn == null)
 869             return false;
 870         MethodType mtype = fn.type();
 871         Class<?> rtype = mtype.returnType();
 872         Class<?> arrayElementType = rtype.getComponentType();
 873         if (arrayElementType == null)
 874             return false;
 875         List<Class<?>> ptypes = mtype.parameterList();
 876         int size = ptypes.size();
 877         if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
 878             return false;
 879         // Assume varargsArray caches pointers.
 880         if (fn != ValueConversions.varargsArray(rtype, size))
 881             return false;
 882         return true;
 883     }
 884 
 885     static boolean match(MemberName member, MethodHandle fn) {
 886         if (member == null || fn == null)  return false;
 887         return member.equals(fn.internalMemberName());
 888     }
 889 
 890     /**
 891      * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
 892      */
 893     private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
 894         return member != null &&
 895                member.getDeclaringClass() == declaringClass &&
 896                member.getName().equals(name);
 897     }
 898     private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
 899         return name.function != null &&
 900                memberRefersTo(name.function.member(), declaringClass, methodName);
 901     }
 902 
 903     /**
 904      * Check if MemberName is a call to MethodHandle.invokeBasic.
 905      */
 906     private boolean isInvokeBasic(Name name) {
 907         if (name.function == null)
 908             return false;
 909         if (name.arguments.length < 1)
 910             return false;  // must have MH argument
 911         MemberName member = name.function.member();
 912         return memberRefersTo(member, MethodHandle.class, "invokeBasic") &&
 913                !member.isPublic() && !member.isStatic();
 914     }
 915 
 916     /**
 917      * Check if MemberName is a call to MethodHandle.linkToStatic, etc.
 918      */
 919     private boolean isLinkerMethodInvoke(Name name) {
 920         if (name.function == null)
 921             return false;
 922         if (name.arguments.length < 1)
 923             return false;  // must have MH argument
 924         MemberName member = name.function.member();
 925         return member != null &&
 926                member.getDeclaringClass() == MethodHandle.class &&
 927                !member.isPublic() && member.isStatic() &&
 928                member.getName().startsWith("linkTo");
 929     }
 930 
 931     /**
 932      * Check if i-th name is a call to MethodHandleImpl.selectAlternative.
 933      */
 934     private boolean isSelectAlternative(int pos) {
 935         // selectAlternative idiom:
 936         //   t_{n}:L=MethodHandleImpl.selectAlternative(...)
 937         //   t_{n+1}:?=MethodHandle.invokeBasic(t_{n}, ...)
 938         if (pos+1 >= lambdaForm.names.length)  return false;
 939         Name name0 = lambdaForm.names[pos];
 940         Name name1 = lambdaForm.names[pos+1];
 941         return nameRefersTo(name0, MethodHandleImpl.class, "selectAlternative") &&
 942                isInvokeBasic(name1) &&
 943                name1.lastUseIndex(name0) == 0 &&        // t_{n+1}:?=MethodHandle.invokeBasic(t_{n}, ...)
 944                lambdaForm.lastUseIndex(name0) == pos+1; // t_{n} is local: used only in t_{n+1}
 945     }
 946 
 947     /**
 948      * Check if i-th name is a start of GuardWithCatch idiom.
 949      */
 950     private boolean isGuardWithCatch(int pos) {
 951         // GuardWithCatch idiom:
 952         //   t_{n}:L=MethodHandle.invokeBasic(...)
 953         //   t_{n+1}:L=MethodHandleImpl.guardWithCatch(*, *, *, t_{n});
 954         //   t_{n+2}:?=MethodHandle.invokeBasic(t_{n+1})
 955         if (pos+2 >= lambdaForm.names.length)  return false;
 956         Name name0 = lambdaForm.names[pos];
 957         Name name1 = lambdaForm.names[pos+1];
 958         Name name2 = lambdaForm.names[pos+2];
 959         return nameRefersTo(name1, MethodHandleImpl.class, "guardWithCatch") &&
 960                isInvokeBasic(name0) &&
 961                isInvokeBasic(name2) &&
 962                name1.lastUseIndex(name0) == 3 &&          // t_{n+1}:L=MethodHandleImpl.guardWithCatch(*, *, *, t_{n});
 963                lambdaForm.lastUseIndex(name0) == pos+1 && // t_{n} is local: used only in t_{n+1}
 964                name2.lastUseIndex(name1) == 1 &&          // t_{n+2}:?=MethodHandle.invokeBasic(t_{n+1})
 965                lambdaForm.lastUseIndex(name1) == pos+2;   // t_{n+1} is local: used only in t_{n+2}
 966     }
 967 
 968     /**
 969      * Emit bytecode for the selectAlternative idiom.
 970      *
 971      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
 972      * <blockquote><pre>{@code
 973      *   Lambda(a0:L,a1:I)=>{
 974      *     t2:I=foo.test(a1:I);
 975      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
 976      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
 977      * }</pre></blockquote>
 978      */
 979     private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
 980         Name receiver = (Name) invokeBasicName.arguments[0];
 981 
 982         Label L_fallback = new Label();
 983         Label L_done     = new Label();
 984 
 985         // load test result
 986         emitPushArgument(selectAlternativeName, 0);
 987 
 988         // if_icmpne L_fallback
 989         mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
 990 
 991         // invoke selectAlternativeName.arguments[1]
 992         Class<?>[] preForkClasses = localClasses.clone();
 993         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
 994         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
 995         emitInvoke(invokeBasicName);
 996 
 997         // goto L_done
 998         mv.visitJumpInsn(Opcodes.GOTO, L_done);
 999 
1000         // L_fallback:
1001         mv.visitLabel(L_fallback);
1002 
1003         // invoke selectAlternativeName.arguments[2]
1004         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1005         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
1006         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
1007         emitInvoke(invokeBasicName);
1008 
1009         // L_done:
1010         mv.visitLabel(L_done);
1011         // for now do not bother to merge typestate; just reset to the dominator state
1012         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1013     }
1014 
1015     /**
1016       * Emit bytecode for the guardWithCatch idiom.
1017       *
1018       * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch):
1019       * <blockquote><pre>{@code
1020       *  guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
1021       *    t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L);
1022       *    t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L);
1023       *   t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I}
1024       * }</pre></blockquote>
1025       *
1026       * It is compiled into bytecode equivalent of the following code:
1027       * <blockquote><pre>{@code
1028       *  try {
1029       *      return a1.invokeBasic(a6, a7);
1030       *  } catch (Throwable e) {
1031       *      if (!a2.isInstance(e)) throw e;
1032       *      return a3.invokeBasic(ex, a6, a7);
1033       *  }}
1034       */
1035     private void emitGuardWithCatch(int pos) {
1036         Name args    = lambdaForm.names[pos];
1037         Name invoker = lambdaForm.names[pos+1];
1038         Name result  = lambdaForm.names[pos+2];
1039 
1040         Label L_startBlock = new Label();
1041         Label L_endBlock = new Label();
1042         Label L_handler = new Label();
1043         Label L_done = new Label();
1044 
1045         Class<?> returnType = result.function.resolvedHandle.type().returnType();
1046         MethodType type = args.function.resolvedHandle.type()
1047                               .dropParameterTypes(0,1)
1048                               .changeReturnType(returnType);
1049 
1050         mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable");
1051 
1052         // Normal case
1053         mv.visitLabel(L_startBlock);
1054         // load target
1055         emitPushArgument(invoker, 0);
1056         emitPushArguments(args, 1); // skip 1st argument: method handle
1057         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1058         mv.visitLabel(L_endBlock);
1059         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1060 
1061         // Exceptional case
1062         mv.visitLabel(L_handler);
1063 
1064         // Check exception's type
1065         mv.visitInsn(Opcodes.DUP);
1066         // load exception class
1067         emitPushArgument(invoker, 1);
1068         mv.visitInsn(Opcodes.SWAP);
1069         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "isInstance", "(Ljava/lang/Object;)Z", false);
1070         Label L_rethrow = new Label();
1071         mv.visitJumpInsn(Opcodes.IFEQ, L_rethrow);
1072 
1073         // Invoke catcher
1074         // load catcher
1075         emitPushArgument(invoker, 2);
1076         mv.visitInsn(Opcodes.SWAP);
1077         emitPushArguments(args, 1); // skip 1st argument: method handle
1078         MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
1079         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString(), false);
1080         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1081 
1082         mv.visitLabel(L_rethrow);
1083         mv.visitInsn(Opcodes.ATHROW);
1084 
1085         mv.visitLabel(L_done);
1086     }
1087 
1088     private void emitPushArguments(Name args, int start) {
1089         for (int i = start; i < args.arguments.length; i++) {
1090             emitPushArgument(args, i);
1091         }
1092     }
1093 
1094     private void emitPushArgument(Name name, int paramIndex) {
1095         Object arg = name.arguments[paramIndex];
1096         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1097         emitPushArgument(ptype, arg);
1098     }
1099 
1100     private void emitPushArgument(Class<?> ptype, Object arg) {
1101         BasicType bptype = basicType(ptype);
1102         if (arg instanceof Name) {
1103             Name n = (Name) arg;
1104             emitLoadInsn(n.type, n.index());
1105             emitImplicitConversion(n.type, ptype, n);
1106         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1107             emitConst(arg);
1108         } else {
1109             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1110                 emitConst(arg);
1111             } else {
1112                 mv.visitLdcInsn(constantPlaceholder(arg));
1113                 emitImplicitConversion(L_TYPE, ptype, arg);
1114             }
1115         }
1116     }
1117 
1118     /**
1119      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1120      */
1121     private void emitReturn() {
1122         // return statement
1123         Class<?> rclass = invokerType.returnType();
1124         BasicType rtype = lambdaForm.returnType();
1125         assert(rtype == basicType(rclass));  // must agree
1126         if (rtype == V_TYPE) {
1127             // void
1128             mv.visitInsn(Opcodes.RETURN);
1129             // it doesn't matter what rclass is; the JVM will discard any value
1130         } else {
1131             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
1132 
1133             // put return value on the stack if it is not already there
1134             if (lambdaForm.result != lambdaForm.names.length - 1 ||
1135                     lambdaForm.result < lambdaForm.arity) {
1136                 emitLoadInsn(rtype, lambdaForm.result);
1137             }
1138 
1139             emitImplicitConversion(rtype, rclass, rn);
1140 
1141             // generate actual return statement
1142             emitReturnInsn(rtype);
1143         }
1144     }
1145 
1146     /**
1147      * Emit a type conversion bytecode casting from "from" to "to".
1148      */
1149     private void emitPrimCast(Wrapper from, Wrapper to) {
1150         // Here's how.
1151         // -   indicates forbidden
1152         // <-> indicates implicit
1153         //      to ----> boolean  byte     short    char     int      long     float    double
1154         // from boolean    <->        -        -        -        -        -        -        -
1155         //      byte        -       <->       i2s      i2c      <->      i2l      i2f      i2d
1156         //      short       -       i2b       <->      i2c      <->      i2l      i2f      i2d
1157         //      char        -       i2b       i2s      <->      <->      i2l      i2f      i2d
1158         //      int         -       i2b       i2s      i2c      <->      i2l      i2f      i2d
1159         //      long        -     l2i,i2b   l2i,i2s  l2i,i2c    l2i      <->      l2f      l2d
1160         //      float       -     f2i,i2b   f2i,i2s  f2i,i2c    f2i      f2l      <->      f2d
1161         //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i      d2l      d2f      <->
1162         if (from == to) {
1163             // no cast required, should be dead code anyway
1164             return;
1165         }
1166         if (from.isSubwordOrInt()) {
1167             // cast from {byte,short,char,int} to anything
1168             emitI2X(to);
1169         } else {
1170             // cast from {long,float,double} to anything
1171             if (to.isSubwordOrInt()) {
1172                 // cast to {byte,short,char,int}
1173                 emitX2I(from);
1174                 if (to.bitWidth() < 32) {
1175                     // targets other than int require another conversion
1176                     emitI2X(to);
1177                 }
1178             } else {
1179                 // cast to {long,float,double} - this is verbose
1180                 boolean error = false;
1181                 switch (from) {
1182                 case LONG:
1183                     switch (to) {
1184                     case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
1185                     case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
1186                     default:      error = true;               break;
1187                     }
1188                     break;
1189                 case FLOAT:
1190                     switch (to) {
1191                     case LONG :   mv.visitInsn(Opcodes.F2L);  break;
1192                     case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
1193                     default:      error = true;               break;
1194                     }
1195                     break;
1196                 case DOUBLE:
1197                     switch (to) {
1198                     case LONG :   mv.visitInsn(Opcodes.D2L);  break;
1199                     case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
1200                     default:      error = true;               break;
1201                     }
1202                     break;
1203                 default:
1204                     error = true;
1205                     break;
1206                 }
1207                 if (error) {
1208                     throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
1209                 }
1210             }
1211         }
1212     }
1213 
1214     private void emitI2X(Wrapper type) {
1215         switch (type) {
1216         case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
1217         case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
1218         case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
1219         case INT:     /* naught */                break;
1220         case LONG:    mv.visitInsn(Opcodes.I2L);  break;
1221         case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
1222         case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
1223         case BOOLEAN:
1224             // For compatibility with ValueConversions and explicitCastArguments:
1225             mv.visitInsn(Opcodes.ICONST_1);
1226             mv.visitInsn(Opcodes.IAND);
1227             break;
1228         default:   throw new InternalError("unknown type: " + type);
1229         }
1230     }
1231 
1232     private void emitX2I(Wrapper type) {
1233         switch (type) {
1234         case LONG:    mv.visitInsn(Opcodes.L2I);  break;
1235         case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
1236         case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
1237         default:      throw new InternalError("unknown type: " + type);
1238         }
1239     }
1240 
1241     /**
1242      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
1243      */
1244     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
1245         assert(isValidSignature(sig));
1246         String name = "interpret_"+signatureReturn(sig).basicTypeChar();
1247         MethodType type = signatureType(sig);  // sig includes leading argument
1248         type = type.changeParameterType(0, MethodHandle.class);
1249         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
1250         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
1251     }
1252 
1253     private byte[] generateLambdaFormInterpreterEntryPointBytes() {
1254         classFilePrologue();
1255 
1256         // Suppress this method in backtraces displayed to the user.
1257         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1258 
1259         // Don't inline the interpreter entry.
1260         mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
1261 
1262         // create parameter array
1263         emitIconstInsn(invokerType.parameterCount());
1264         mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1265 
1266         // fill parameter array
1267         for (int i = 0; i < invokerType.parameterCount(); i++) {
1268             Class<?> ptype = invokerType.parameterType(i);
1269             mv.visitInsn(Opcodes.DUP);
1270             emitIconstInsn(i);
1271             emitLoadInsn(basicType(ptype), i);
1272             // box if primitive type
1273             if (ptype.isPrimitive()) {
1274                 emitBoxing(Wrapper.forPrimitiveType(ptype));
1275             }
1276             mv.visitInsn(Opcodes.AASTORE);
1277         }
1278         // invoke
1279         emitAloadInsn(0);
1280         mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1281         mv.visitInsn(Opcodes.SWAP);  // swap form and array; avoid local variable
1282         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1283 
1284         // maybe unbox
1285         Class<?> rtype = invokerType.returnType();
1286         if (rtype.isPrimitive() && rtype != void.class) {
1287             emitUnboxing(Wrapper.forPrimitiveType(rtype));
1288         }
1289 
1290         // return statement
1291         emitReturnInsn(basicType(rtype));
1292 
1293         classFileEpilogue();
1294         bogusMethod(invokerType);
1295 
1296         final byte[] classFile = cw.toByteArray();
1297         maybeDump(className, classFile);
1298         return classFile;
1299     }
1300 
1301     /**
1302      * Generate bytecode for a NamedFunction invoker.
1303      */
1304     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1305         MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1306         String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1307         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1308         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1309     }
1310 
1311     static int nfi = 0;
1312 
1313     private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1314         MethodType dstType = typeForm.erasedType();
1315         classFilePrologue();
1316 
1317         // Suppress this method in backtraces displayed to the user.
1318         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1319 
1320         // Force inlining of this invoker method.
1321         mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
1322 
1323         // Load receiver
1324         emitAloadInsn(0);
1325 
1326         // Load arguments from array
1327         for (int i = 0; i < dstType.parameterCount(); i++) {
1328             emitAloadInsn(1);
1329             emitIconstInsn(i);
1330             mv.visitInsn(Opcodes.AALOAD);
1331 
1332             // Maybe unbox
1333             Class<?> dptype = dstType.parameterType(i);
1334             if (dptype.isPrimitive()) {
1335                 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
1336                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
1337                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
1338                 emitUnboxing(srcWrapper);
1339                 emitPrimCast(srcWrapper, dstWrapper);
1340             }
1341         }
1342 
1343         // Invoke
1344         String targetDesc = dstType.basicType().toMethodDescriptorString();
1345         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1346 
1347         // Box primitive types
1348         Class<?> rtype = dstType.returnType();
1349         if (rtype != void.class && rtype.isPrimitive()) {
1350             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1351             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
1352             // boolean casts not allowed
1353             emitPrimCast(srcWrapper, dstWrapper);
1354             emitBoxing(dstWrapper);
1355         }
1356 
1357         // If the return type is void we return a null reference.
1358         if (rtype == void.class) {
1359             mv.visitInsn(Opcodes.ACONST_NULL);
1360         }
1361         emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
1362 
1363         classFileEpilogue();
1364         bogusMethod(dstType);
1365 
1366         final byte[] classFile = cw.toByteArray();
1367         maybeDump(className, classFile);
1368         return classFile;
1369     }
1370 
1371     /**
1372      * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1373      * for debugging purposes.
1374      */
1375     private void bogusMethod(Object... os) {
1376         if (DUMP_CLASS_FILES) {
1377             mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1378             for (Object o : os) {
1379                 mv.visitLdcInsn(o.toString());
1380                 mv.visitInsn(Opcodes.POP);
1381             }
1382             mv.visitInsn(Opcodes.RETURN);
1383             mv.visitMaxs(0, 0);
1384             mv.visitEnd();
1385         }
1386     }
1387 }