1 /*
   2  * Copyright (c) 2012, 2014, 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 
  39 import sun.invoke.util.VerifyAccess;
  40 import sun.invoke.util.VerifyType;
  41 import sun.invoke.util.Wrapper;
  42 import sun.reflect.misc.ReflectUtil;
  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 = OBJ;
  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  = LF + "$" + 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 already 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         try {
 290             member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
 291         } catch (ReflectiveOperationException e) {
 292             throw newInternalError(e);
 293         }
 294         return member;
 295     }
 296 
 297     /**
 298      * Set up class file generation.
 299      */
 300     private void classFilePrologue() {
 301         final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
 302         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 303         cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
 304         cw.visitSource(sourceFile, null);
 305 
 306         String invokerDesc = invokerType.toMethodDescriptorString();
 307         mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
 308     }
 309 
 310     /**
 311      * Tear down class file generation.
 312      */
 313     private void classFileEpilogue() {
 314         mv.visitMaxs(0, 0);
 315         mv.visitEnd();
 316     }
 317 
 318     /*
 319      * Low-level emit helpers.
 320      */
 321     private void emitConst(Object con) {
 322         if (con == null) {
 323             mv.visitInsn(Opcodes.ACONST_NULL);
 324             return;
 325         }
 326         if (con instanceof Integer) {
 327             emitIconstInsn((int) con);
 328             return;
 329         }
 330         if (con instanceof Long) {
 331             long x = (long) con;
 332             if (x == (short) x) {
 333                 emitIconstInsn((int) x);
 334                 mv.visitInsn(Opcodes.I2L);
 335                 return;
 336             }
 337         }
 338         if (con instanceof Float) {
 339             float x = (float) con;
 340             if (x == (short) x) {
 341                 emitIconstInsn((int) x);
 342                 mv.visitInsn(Opcodes.I2F);
 343                 return;
 344             }
 345         }
 346         if (con instanceof Double) {
 347             double x = (double) con;
 348             if (x == (short) x) {
 349                 emitIconstInsn((int) x);
 350                 mv.visitInsn(Opcodes.I2D);
 351                 return;
 352             }
 353         }
 354         if (con instanceof Boolean) {
 355             emitIconstInsn((boolean) con ? 1 : 0);
 356             return;
 357         }
 358         // fall through:
 359         mv.visitLdcInsn(con);
 360     }
 361 
 362     private void emitIconstInsn(int i) {
 363         int opcode;
 364         switch (i) {
 365         case 0:  opcode = Opcodes.ICONST_0;  break;
 366         case 1:  opcode = Opcodes.ICONST_1;  break;
 367         case 2:  opcode = Opcodes.ICONST_2;  break;
 368         case 3:  opcode = Opcodes.ICONST_3;  break;
 369         case 4:  opcode = Opcodes.ICONST_4;  break;
 370         case 5:  opcode = Opcodes.ICONST_5;  break;
 371         default:
 372             if (i == (byte) i) {
 373                 mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
 374             } else if (i == (short) i) {
 375                 mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
 376             } else {
 377                 mv.visitLdcInsn(i);
 378             }
 379             return;
 380         }
 381         mv.visitInsn(opcode);
 382     }
 383 
 384     /*
 385      * NOTE: These load/store methods use the localsMap to find the correct index!
 386      */
 387     private void emitLoadInsn(BasicType type, int index) {
 388         int opcode = loadInsnOpcode(type);
 389         mv.visitVarInsn(opcode, localsMap[index]);
 390     }
 391 
 392     private int loadInsnOpcode(BasicType type) throws InternalError {
 393         switch (type) {
 394             case I_TYPE: return Opcodes.ILOAD;
 395             case J_TYPE: return Opcodes.LLOAD;
 396             case F_TYPE: return Opcodes.FLOAD;
 397             case D_TYPE: return Opcodes.DLOAD;
 398             case L_TYPE: return Opcodes.ALOAD;
 399             default:
 400                 throw new InternalError("unknown type: " + type);
 401         }
 402     }
 403     private void emitAloadInsn(int index) {
 404         emitLoadInsn(L_TYPE, index);
 405     }
 406 
 407     private void emitStoreInsn(BasicType type, int index) {
 408         int opcode = storeInsnOpcode(type);
 409         mv.visitVarInsn(opcode, localsMap[index]);
 410     }
 411 
 412     private int storeInsnOpcode(BasicType type) throws InternalError {
 413         switch (type) {
 414             case I_TYPE: return Opcodes.ISTORE;
 415             case J_TYPE: return Opcodes.LSTORE;
 416             case F_TYPE: return Opcodes.FSTORE;
 417             case D_TYPE: return Opcodes.DSTORE;
 418             case L_TYPE: return Opcodes.ASTORE;
 419             default:
 420                 throw new InternalError("unknown type: " + type);
 421         }
 422     }
 423     private void emitAstoreInsn(int index) {
 424         emitStoreInsn(L_TYPE, index);
 425     }
 426 
 427     private byte arrayTypeCode(Wrapper elementType) {
 428         switch (elementType) {
 429             case BOOLEAN: return Opcodes.T_BOOLEAN;
 430             case BYTE:    return Opcodes.T_BYTE;
 431             case CHAR:    return Opcodes.T_CHAR;
 432             case SHORT:   return Opcodes.T_SHORT;
 433             case INT:     return Opcodes.T_INT;
 434             case LONG:    return Opcodes.T_LONG;
 435             case FLOAT:   return Opcodes.T_FLOAT;
 436             case DOUBLE:  return Opcodes.T_DOUBLE;
 437             case OBJECT:  return 0; // in place of Opcodes.T_OBJECT
 438             default:      throw new InternalError();
 439         }
 440     }
 441 
 442     private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
 443         assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
 444         int xas;
 445         switch (tcode) {
 446             case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
 447             case Opcodes.T_BYTE:    xas = Opcodes.BASTORE; break;
 448             case Opcodes.T_CHAR:    xas = Opcodes.CASTORE; break;
 449             case Opcodes.T_SHORT:   xas = Opcodes.SASTORE; break;
 450             case Opcodes.T_INT:     xas = Opcodes.IASTORE; break;
 451             case Opcodes.T_LONG:    xas = Opcodes.LASTORE; break;
 452             case Opcodes.T_FLOAT:   xas = Opcodes.FASTORE; break;
 453             case Opcodes.T_DOUBLE:  xas = Opcodes.DASTORE; break;
 454             case 0:                 xas = Opcodes.AASTORE; break;
 455             default:      throw new InternalError();
 456         }
 457         return xas - Opcodes.AASTORE + aaop;
 458     }
 459 
 460 
 461     private void freeFrameLocal(int oldFrameLocal) {
 462         int i = indexForFrameLocal(oldFrameLocal);
 463         if (i < 0)  return;
 464         BasicType type = localTypes[i];
 465         int newFrameLocal = makeLocalTemp(type);
 466         mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
 467         mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
 468         assert(localsMap[i] == oldFrameLocal);
 469         localsMap[i] = newFrameLocal;
 470         assert(indexForFrameLocal(oldFrameLocal) < 0);
 471     }
 472     private int indexForFrameLocal(int frameLocal) {
 473         for (int i = 0; i < localsMap.length; i++) {
 474             if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
 475                 return i;
 476         }
 477         return -1;
 478     }
 479     private int makeLocalTemp(BasicType type) {
 480         int frameLocal = localsMap[localsMap.length - 1];
 481         localsMap[localsMap.length - 1] = frameLocal + type.basicTypeSlots();
 482         return frameLocal;
 483     }
 484 
 485     /**
 486      * Emit a boxing call.
 487      *
 488      * @param wrapper primitive type class to box.
 489      */
 490     private void emitBoxing(Wrapper wrapper) {
 491         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 492         String name  = "valueOf";
 493         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
 494         mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
 495     }
 496 
 497     /**
 498      * Emit an unboxing call (plus preceding checkcast).
 499      *
 500      * @param wrapper wrapper type class to unbox.
 501      */
 502     private void emitUnboxing(Wrapper wrapper) {
 503         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
 504         String name  = wrapper.primitiveSimpleName() + "Value";
 505         String desc  = "()" + wrapper.basicTypeChar();
 506         emitReferenceCast(wrapper.wrapperType(), null);
 507         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
 508     }
 509 
 510     /**
 511      * Emit an implicit conversion for an argument which must be of the given pclass.
 512      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 513      *
 514      * @param ptype type of value present on stack
 515      * @param pclass type of value required on stack
 516      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 517      */
 518     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 519         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 520         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 521             return;   // nothing to do
 522         switch (ptype) {
 523             case L_TYPE:
 524                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 525                     if (PROFILE_LEVEL > 0)
 526                         emitReferenceCast(Object.class, arg);
 527                     return;
 528                 }
 529                 emitReferenceCast(pclass, arg);
 530                 return;
 531             case I_TYPE:
 532                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 533                     emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
 534                 return;
 535         }
 536         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 537     }
 538 
 539     /** Update localClasses type map.  Return true if the information is already present. */
 540     private boolean assertStaticType(Class<?> cls, Name n) {
 541         int local = n.index();
 542         Class<?> aclass = localClasses[local];
 543         if (aclass != null && (aclass == cls || cls.isAssignableFrom(aclass))) {
 544             return true;  // type info is already present
 545         } else if (aclass == null || aclass.isAssignableFrom(cls)) {
 546             localClasses[local] = cls;  // type info can be improved
 547         }
 548         return false;
 549     }
 550 
 551     private void emitReferenceCast(Class<?> cls, Object arg) {
 552         Name writeBack = null;  // local to write back result
 553         if (arg instanceof Name) {
 554             Name n = (Name) arg;
 555             if (assertStaticType(cls, n))
 556                 return;  // this cast was already performed
 557             if (lambdaForm.useCount(n) > 1) {
 558                 // This guy gets used more than once.
 559                 writeBack = n;
 560             }
 561         }
 562         if (isStaticallyNameable(cls)) {
 563             String sig = getInternalName(cls);
 564             mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
 565         } else {
 566             mv.visitLdcInsn(constantPlaceholder(cls));
 567             mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
 568             mv.visitInsn(Opcodes.SWAP);
 569             mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
 570             if (Object[].class.isAssignableFrom(cls))
 571                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
 572             else if (PROFILE_LEVEL > 0)
 573                 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
 574         }
 575         if (writeBack != null) {
 576             mv.visitInsn(Opcodes.DUP);
 577             emitAstoreInsn(writeBack.index());
 578         }
 579     }
 580 
 581     /**
 582      * Emits an actual return instruction conforming to the given return type.
 583      */
 584     private void emitReturnInsn(BasicType type) {
 585         int opcode;
 586         switch (type) {
 587         case I_TYPE:  opcode = Opcodes.IRETURN;  break;
 588         case J_TYPE:  opcode = Opcodes.LRETURN;  break;
 589         case F_TYPE:  opcode = Opcodes.FRETURN;  break;
 590         case D_TYPE:  opcode = Opcodes.DRETURN;  break;
 591         case L_TYPE:  opcode = Opcodes.ARETURN;  break;
 592         case V_TYPE:  opcode = Opcodes.RETURN;   break;
 593         default:
 594             throw new InternalError("unknown return type: " + type);
 595         }
 596         mv.visitInsn(opcode);
 597     }
 598 
 599     private static String getInternalName(Class<?> c) {
 600         if (c == Object.class)             return OBJ;
 601         else if (c == Object[].class)      return OBJARY;
 602         else if (c == Class.class)         return CLS;
 603         else if (c == MethodHandle.class)  return MH;
 604         assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
 605         return c.getName().replace('.', '/');
 606     }
 607 
 608     /**
 609      * Generate customized bytecode for a given LambdaForm.
 610      */
 611     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
 612         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
 613         return g.loadMethod(g.generateCustomizedCodeBytes());
 614     }
 615 
 616     /**
 617      * Generate an invoker method for the passed {@link LambdaForm}.
 618      */
 619     private byte[] generateCustomizedCodeBytes() {
 620         classFilePrologue();
 621 
 622         // Suppress this method in backtraces displayed to the user.
 623         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 624 
 625         // Mark this method as a compiled LambdaForm
 626         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
 627 
 628         if (lambdaForm.forceInline) {
 629             // Force inlining of this invoker method.
 630             mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
 631         } else {
 632             mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
 633         }
 634 
 635 
 636         // iterate over the form's names, generating bytecode instructions for each
 637         // start iterating at the first name following the arguments
 638         Name onStack = null;
 639         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 640             Name name = lambdaForm.names[i];
 641 
 642             emitStoreResult(onStack);
 643             onStack = name;  // unless otherwise modified below
 644             MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
 645             switch (intr) {
 646                 case SELECT_ALTERNATIVE:
 647                     assert isSelectAlternative(i);
 648                     onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
 649                     i++;  // skip MH.invokeBasic of the selectAlternative result
 650                     continue;
 651                 case GUARD_WITH_CATCH:
 652                     assert isGuardWithCatch(i);
 653                     onStack = emitGuardWithCatch(i);
 654                     i = i+2; // Jump to the end of GWC idiom
 655                     continue;
 656                 case NEW_ARRAY:
 657                     Class<?> rtype = name.function.methodType().returnType();
 658                     if (isStaticallyNameable(rtype)) {
 659                         emitNewArray(name);
 660                         continue;
 661                     }
 662                     break;
 663                 case ARRAY_LOAD:
 664                     emitArrayLoad(name);
 665                     continue;
 666                 case ARRAY_STORE:
 667                     emitArrayStore(name);
 668                     continue;
 669                 case IDENTITY:
 670                     assert(name.arguments.length == 1);
 671                     emitPushArguments(name);
 672                     continue;
 673                 case ZERO:
 674                     assert(name.arguments.length == 0);
 675                     emitConst(name.type.basicTypeWrapper().zero());
 676                     continue;
 677                 case NONE:
 678                     // no intrinsic associated
 679                     break;
 680                 default:
 681                     throw newInternalError("Unknown intrinsic: "+intr);
 682             }
 683 
 684             MemberName member = name.function.member();
 685             if (isStaticallyInvocable(member)) {
 686                 emitStaticInvoke(member, name);
 687             } else {
 688                 emitInvoke(name);
 689             }
 690         }
 691 
 692         // return statement
 693         emitReturn(onStack);
 694 
 695         classFileEpilogue();
 696         bogusMethod(lambdaForm);
 697 
 698         final byte[] classFile = cw.toByteArray();
 699         maybeDump(className, classFile);
 700         return classFile;
 701     }
 702 
 703     void emitArrayLoad(Name name)  { emitArrayOp(name, Opcodes.AALOAD);  }
 704     void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
 705 
 706     void emitArrayOp(Name name, int arrayOpcode) {
 707         assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
 708         Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
 709         assert elementType != null;
 710         emitPushArguments(name);
 711         if (elementType.isPrimitive()) {
 712             Wrapper w = Wrapper.forPrimitiveType(elementType);
 713             arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
 714         }
 715         mv.visitInsn(arrayOpcode);
 716     }
 717 
 718     /**
 719      * Emit an invoke for the given name.
 720      */
 721     void emitInvoke(Name name) {
 722         assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 723         if (true) {
 724             // push receiver
 725             MethodHandle target = name.function.resolvedHandle;
 726             assert(target != null) : name.exprString();
 727             mv.visitLdcInsn(constantPlaceholder(target));
 728             emitReferenceCast(MethodHandle.class, target);
 729         } else {
 730             // load receiver
 731             emitAloadInsn(0);
 732             emitReferenceCast(MethodHandle.class, null);
 733             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
 734             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
 735             // TODO more to come
 736         }
 737 
 738         // push arguments
 739         emitPushArguments(name);
 740 
 741         // invocation
 742         MethodType type = name.function.methodType();
 743         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 744     }
 745 
 746     static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
 747         // Sample classes from each package we are willing to bind to statically:
 748         java.lang.Object.class,
 749         java.util.Arrays.class,
 750         sun.misc.Unsafe.class
 751         //MethodHandle.class already covered
 752     };
 753 
 754     static boolean isStaticallyInvocable(Name name) {
 755         return isStaticallyInvocable(name.function.member());
 756     }
 757 
 758     static boolean isStaticallyInvocable(MemberName member) {
 759         if (member == null)  return false;
 760         if (member.isConstructor())  return false;
 761         Class<?> cls = member.getDeclaringClass();
 762         if (cls.isArray() || cls.isPrimitive())
 763             return false;  // FIXME
 764         if (cls.isAnonymousClass() || cls.isLocalClass())
 765             return false;  // inner class of some sort
 766         if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
 767             return false;  // not on BCP
 768         if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
 769             return false;
 770         MethodType mtype = member.getMethodOrFieldType();
 771         if (!isStaticallyNameable(mtype.returnType()))
 772             return false;
 773         for (Class<?> ptype : mtype.parameterArray())
 774             if (!isStaticallyNameable(ptype))
 775                 return false;
 776         if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
 777             return true;   // in java.lang.invoke package
 778         if (member.isPublic() && isStaticallyNameable(cls))
 779             return true;
 780         return false;
 781     }
 782 
 783     static boolean isStaticallyNameable(Class<?> cls) {
 784         if (cls == Object.class)
 785             return true;
 786         while (cls.isArray())
 787             cls = cls.getComponentType();
 788         if (cls.isPrimitive())
 789             return true;  // int[].class, for example
 790         if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
 791             return false;
 792         // could use VerifyAccess.isClassAccessible but the following is a safe approximation
 793         if (cls.getClassLoader() != Object.class.getClassLoader())
 794             return false;
 795         if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
 796             return true;
 797         if (!Modifier.isPublic(cls.getModifiers()))
 798             return false;
 799         for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
 800             if (VerifyAccess.isSamePackage(pkgcls, cls))
 801                 return true;
 802         }
 803         return false;
 804     }
 805 
 806     void emitStaticInvoke(Name name) {
 807         emitStaticInvoke(name.function.member(), name);
 808     }
 809 
 810     /**
 811      * Emit an invoke for the given name, using the MemberName directly.
 812      */
 813     void emitStaticInvoke(MemberName member, Name name) {
 814         assert(member.equals(name.function.member()));
 815         Class<?> defc = member.getDeclaringClass();
 816         String cname = getInternalName(defc);
 817         String mname = member.getName();
 818         String mtype;
 819         byte refKind = member.getReferenceKind();
 820         if (refKind == REF_invokeSpecial) {
 821             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 822             assert(member.canBeStaticallyBound()) : member;
 823             refKind = REF_invokeVirtual;
 824         }
 825 
 826         if (member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual) {
 827             // Methods from Object declared in an interface can be resolved by JVM to invokevirtual kind.
 828             // Need to convert it back to invokeinterface to pass verification and make the invocation works as expected.
 829             refKind = REF_invokeInterface;
 830         }
 831 
 832         // push arguments
 833         emitPushArguments(name);
 834 
 835         // invocation
 836         if (member.isMethod()) {
 837             mtype = member.getMethodType().toMethodDescriptorString();
 838             mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype,
 839                                member.getDeclaringClass().isInterface());
 840         } else {
 841             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 842             mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
 843         }
 844         // Issue a type assertion for the result, so we can avoid casts later.
 845         if (name.type == L_TYPE) {
 846             Class<?> rtype = member.getInvocationType().returnType();
 847             assert(!rtype.isPrimitive());
 848             if (rtype != Object.class && !rtype.isInterface()) {
 849                 assertStaticType(rtype, name);
 850             }
 851         }
 852     }
 853 
 854     void emitNewArray(Name name) throws InternalError {
 855         Class<?> rtype = name.function.methodType().returnType();
 856         if (name.arguments.length == 0) {
 857             // The array will be a constant.
 858             Object emptyArray;
 859             try {
 860                 emptyArray = name.function.resolvedHandle.invoke();
 861             } catch (Throwable ex) {
 862                 throw newInternalError(ex);
 863             }
 864             assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
 865             assert(emptyArray.getClass() == rtype);  // exact typing
 866             mv.visitLdcInsn(constantPlaceholder(emptyArray));
 867             emitReferenceCast(rtype, emptyArray);
 868             return;
 869         }
 870         Class<?> arrayElementType = rtype.getComponentType();
 871         assert(arrayElementType != null);
 872         emitIconstInsn(name.arguments.length);
 873         int xas = Opcodes.AASTORE;
 874         if (!arrayElementType.isPrimitive()) {
 875             mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
 876         } else {
 877             byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
 878             xas = arrayInsnOpcode(tc, xas);
 879             mv.visitIntInsn(Opcodes.NEWARRAY, tc);
 880         }
 881         // store arguments
 882         for (int i = 0; i < name.arguments.length; i++) {
 883             mv.visitInsn(Opcodes.DUP);
 884             emitIconstInsn(i);
 885             emitPushArgument(name, i);
 886             mv.visitInsn(xas);
 887         }
 888         // the array is left on the stack
 889         assertStaticType(rtype, name);
 890     }
 891     int refKindOpcode(byte refKind) {
 892         switch (refKind) {
 893         case REF_invokeVirtual:      return Opcodes.INVOKEVIRTUAL;
 894         case REF_invokeStatic:       return Opcodes.INVOKESTATIC;
 895         case REF_invokeSpecial:      return Opcodes.INVOKESPECIAL;
 896         case REF_invokeInterface:    return Opcodes.INVOKEINTERFACE;
 897         case REF_getField:           return Opcodes.GETFIELD;
 898         case REF_putField:           return Opcodes.PUTFIELD;
 899         case REF_getStatic:          return Opcodes.GETSTATIC;
 900         case REF_putStatic:          return Opcodes.PUTSTATIC;
 901         }
 902         throw new InternalError("refKind="+refKind);
 903     }
 904 
 905     /**
 906      * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
 907      */
 908     private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
 909         return member != null &&
 910                member.getDeclaringClass() == declaringClass &&
 911                member.getName().equals(name);
 912     }
 913     private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
 914         return name.function != null &&
 915                memberRefersTo(name.function.member(), declaringClass, methodName);
 916     }
 917 
 918     /**
 919      * Check if MemberName is a call to MethodHandle.invokeBasic.
 920      */
 921     private boolean isInvokeBasic(Name name) {
 922         if (name.function == null)
 923             return false;
 924         if (name.arguments.length < 1)
 925             return false;  // must have MH argument
 926         MemberName member = name.function.member();
 927         return memberRefersTo(member, MethodHandle.class, "invokeBasic") &&
 928                !member.isPublic() && !member.isStatic();
 929     }
 930 
 931     /**
 932      * Check if MemberName is a call to MethodHandle.linkToStatic, etc.
 933      */
 934     private boolean isLinkerMethodInvoke(Name name) {
 935         if (name.function == null)
 936             return false;
 937         if (name.arguments.length < 1)
 938             return false;  // must have MH argument
 939         MemberName member = name.function.member();
 940         return member != null &&
 941                member.getDeclaringClass() == MethodHandle.class &&
 942                !member.isPublic() && member.isStatic() &&
 943                member.getName().startsWith("linkTo");
 944     }
 945 
 946     /**
 947      * Check if i-th name is a call to MethodHandleImpl.selectAlternative.
 948      */
 949     private boolean isSelectAlternative(int pos) {
 950         // selectAlternative idiom:
 951         //   t_{n}:L=MethodHandleImpl.selectAlternative(...)
 952         //   t_{n+1}:?=MethodHandle.invokeBasic(t_{n}, ...)
 953         if (pos+1 >= lambdaForm.names.length)  return false;
 954         Name name0 = lambdaForm.names[pos];
 955         Name name1 = lambdaForm.names[pos+1];
 956         return nameRefersTo(name0, MethodHandleImpl.class, "selectAlternative") &&
 957                isInvokeBasic(name1) &&
 958                name1.lastUseIndex(name0) == 0 &&        // t_{n+1}:?=MethodHandle.invokeBasic(t_{n}, ...)
 959                lambdaForm.lastUseIndex(name0) == pos+1; // t_{n} is local: used only in t_{n+1}
 960     }
 961 
 962     /**
 963      * Check if i-th name is a start of GuardWithCatch idiom.
 964      */
 965     private boolean isGuardWithCatch(int pos) {
 966         // GuardWithCatch idiom:
 967         //   t_{n}:L=MethodHandle.invokeBasic(...)
 968         //   t_{n+1}:L=MethodHandleImpl.guardWithCatch(*, *, *, t_{n});
 969         //   t_{n+2}:?=MethodHandle.invokeBasic(t_{n+1})
 970         if (pos+2 >= lambdaForm.names.length)  return false;
 971         Name name0 = lambdaForm.names[pos];
 972         Name name1 = lambdaForm.names[pos+1];
 973         Name name2 = lambdaForm.names[pos+2];
 974         return nameRefersTo(name1, MethodHandleImpl.class, "guardWithCatch") &&
 975                isInvokeBasic(name0) &&
 976                isInvokeBasic(name2) &&
 977                name1.lastUseIndex(name0) == 3 &&          // t_{n+1}:L=MethodHandleImpl.guardWithCatch(*, *, *, t_{n});
 978                lambdaForm.lastUseIndex(name0) == pos+1 && // t_{n} is local: used only in t_{n+1}
 979                name2.lastUseIndex(name1) == 1 &&          // t_{n+2}:?=MethodHandle.invokeBasic(t_{n+1})
 980                lambdaForm.lastUseIndex(name1) == pos+2;   // t_{n+1} is local: used only in t_{n+2}
 981     }
 982 
 983     /**
 984      * Emit bytecode for the selectAlternative idiom.
 985      *
 986      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
 987      * <blockquote><pre>{@code
 988      *   Lambda(a0:L,a1:I)=>{
 989      *     t2:I=foo.test(a1:I);
 990      *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
 991      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
 992      * }</pre></blockquote>
 993      */
 994     private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
 995         assert isStaticallyInvocable(invokeBasicName);
 996 
 997         Name receiver = (Name) invokeBasicName.arguments[0];
 998 
 999         Label L_fallback = new Label();
1000         Label L_done     = new Label();
1001 
1002         // load test result
1003         emitPushArgument(selectAlternativeName, 0);
1004 
1005         // if_icmpne L_fallback
1006         mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
1007 
1008         // invoke selectAlternativeName.arguments[1]
1009         Class<?>[] preForkClasses = localClasses.clone();
1010         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
1011         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
1012         emitStaticInvoke(invokeBasicName);
1013 
1014         // goto L_done
1015         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1016 
1017         // L_fallback:
1018         mv.visitLabel(L_fallback);
1019 
1020         // invoke selectAlternativeName.arguments[2]
1021         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1022         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
1023         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
1024         emitStaticInvoke(invokeBasicName);
1025 
1026         // L_done:
1027         mv.visitLabel(L_done);
1028         // for now do not bother to merge typestate; just reset to the dominator state
1029         System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1030 
1031         return invokeBasicName;  // return what's on stack
1032     }
1033 
1034     /**
1035       * Emit bytecode for the guardWithCatch idiom.
1036       *
1037       * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch):
1038       * <blockquote><pre>{@code
1039       *  guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
1040       *    t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L);
1041       *    t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L);
1042       *   t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I}
1043       * }</pre></blockquote>
1044       *
1045       * It is compiled into bytecode equivalent of the following code:
1046       * <blockquote><pre>{@code
1047       *  try {
1048       *      return a1.invokeBasic(a6, a7);
1049       *  } catch (Throwable e) {
1050       *      if (!a2.isInstance(e)) throw e;
1051       *      return a3.invokeBasic(ex, a6, a7);
1052       *  }}
1053       */
1054     private Name emitGuardWithCatch(int pos) {
1055         Name args    = lambdaForm.names[pos];
1056         Name invoker = lambdaForm.names[pos+1];
1057         Name result  = lambdaForm.names[pos+2];
1058 
1059         Label L_startBlock = new Label();
1060         Label L_endBlock = new Label();
1061         Label L_handler = new Label();
1062         Label L_done = new Label();
1063 
1064         Class<?> returnType = result.function.resolvedHandle.type().returnType();
1065         MethodType type = args.function.resolvedHandle.type()
1066                               .dropParameterTypes(0,1)
1067                               .changeReturnType(returnType);
1068 
1069         mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable");
1070 
1071         // Normal case
1072         mv.visitLabel(L_startBlock);
1073         // load target
1074         emitPushArgument(invoker, 0);
1075         emitPushArguments(args, 1); // skip 1st argument: method handle
1076         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
1077         mv.visitLabel(L_endBlock);
1078         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1079 
1080         // Exceptional case
1081         mv.visitLabel(L_handler);
1082 
1083         // Check exception's type
1084         mv.visitInsn(Opcodes.DUP);
1085         // load exception class
1086         emitPushArgument(invoker, 1);
1087         mv.visitInsn(Opcodes.SWAP);
1088         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "isInstance", "(Ljava/lang/Object;)Z", false);
1089         Label L_rethrow = new Label();
1090         mv.visitJumpInsn(Opcodes.IFEQ, L_rethrow);
1091 
1092         // Invoke catcher
1093         // load catcher
1094         emitPushArgument(invoker, 2);
1095         mv.visitInsn(Opcodes.SWAP);
1096         emitPushArguments(args, 1); // skip 1st argument: method handle
1097         MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
1098         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString(), false);
1099         mv.visitJumpInsn(Opcodes.GOTO, L_done);
1100 
1101         mv.visitLabel(L_rethrow);
1102         mv.visitInsn(Opcodes.ATHROW);
1103 
1104         mv.visitLabel(L_done);
1105 
1106         return result;
1107     }
1108 
1109     private void emitPushArguments(Name args) {
1110         emitPushArguments(args, 0);
1111     }
1112 
1113     private void emitPushArguments(Name args, int start) {
1114         for (int i = start; i < args.arguments.length; i++) {
1115             emitPushArgument(args, i);
1116         }
1117     }
1118 
1119     private void emitPushArgument(Name name, int paramIndex) {
1120         Object arg = name.arguments[paramIndex];
1121         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1122         emitPushArgument(ptype, arg);
1123     }
1124 
1125     private void emitPushArgument(Class<?> ptype, Object arg) {
1126         BasicType bptype = basicType(ptype);
1127         if (arg instanceof Name) {
1128             Name n = (Name) arg;
1129             emitLoadInsn(n.type, n.index());
1130             emitImplicitConversion(n.type, ptype, n);
1131         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1132             emitConst(arg);
1133         } else {
1134             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1135                 emitConst(arg);
1136             } else {
1137                 mv.visitLdcInsn(constantPlaceholder(arg));
1138                 emitImplicitConversion(L_TYPE, ptype, arg);
1139             }
1140         }
1141     }
1142 
1143     /**
1144      * Store the name to its local, if necessary.
1145      */
1146     private void emitStoreResult(Name name) {
1147         if (name != null && name.type != V_TYPE) {
1148             // non-void: actually assign
1149             emitStoreInsn(name.type, name.index());
1150         }
1151     }
1152 
1153     /**
1154      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1155      */
1156     private void emitReturn(Name onStack) {
1157         // return statement
1158         Class<?> rclass = invokerType.returnType();
1159         BasicType rtype = lambdaForm.returnType();
1160         assert(rtype == basicType(rclass));  // must agree
1161         if (rtype == V_TYPE) {
1162             // void
1163             mv.visitInsn(Opcodes.RETURN);
1164             // it doesn't matter what rclass is; the JVM will discard any value
1165         } else {
1166             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
1167 
1168             // put return value on the stack if it is not already there
1169             if (rn != onStack) {
1170                 emitLoadInsn(rtype, lambdaForm.result);
1171             }
1172 
1173             emitImplicitConversion(rtype, rclass, rn);
1174 
1175             // generate actual return statement
1176             emitReturnInsn(rtype);
1177         }
1178     }
1179 
1180     /**
1181      * Emit a type conversion bytecode casting from "from" to "to".
1182      */
1183     private void emitPrimCast(Wrapper from, Wrapper to) {
1184         // Here's how.
1185         // -   indicates forbidden
1186         // <-> indicates implicit
1187         //      to ----> boolean  byte     short    char     int      long     float    double
1188         // from boolean    <->        -        -        -        -        -        -        -
1189         //      byte        -       <->       i2s      i2c      <->      i2l      i2f      i2d
1190         //      short       -       i2b       <->      i2c      <->      i2l      i2f      i2d
1191         //      char        -       i2b       i2s      <->      <->      i2l      i2f      i2d
1192         //      int         -       i2b       i2s      i2c      <->      i2l      i2f      i2d
1193         //      long        -     l2i,i2b   l2i,i2s  l2i,i2c    l2i      <->      l2f      l2d
1194         //      float       -     f2i,i2b   f2i,i2s  f2i,i2c    f2i      f2l      <->      f2d
1195         //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i      d2l      d2f      <->
1196         if (from == to) {
1197             // no cast required, should be dead code anyway
1198             return;
1199         }
1200         if (from.isSubwordOrInt()) {
1201             // cast from {byte,short,char,int} to anything
1202             emitI2X(to);
1203         } else {
1204             // cast from {long,float,double} to anything
1205             if (to.isSubwordOrInt()) {
1206                 // cast to {byte,short,char,int}
1207                 emitX2I(from);
1208                 if (to.bitWidth() < 32) {
1209                     // targets other than int require another conversion
1210                     emitI2X(to);
1211                 }
1212             } else {
1213                 // cast to {long,float,double} - this is verbose
1214                 boolean error = false;
1215                 switch (from) {
1216                 case LONG:
1217                     switch (to) {
1218                     case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
1219                     case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
1220                     default:      error = true;               break;
1221                     }
1222                     break;
1223                 case FLOAT:
1224                     switch (to) {
1225                     case LONG :   mv.visitInsn(Opcodes.F2L);  break;
1226                     case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
1227                     default:      error = true;               break;
1228                     }
1229                     break;
1230                 case DOUBLE:
1231                     switch (to) {
1232                     case LONG :   mv.visitInsn(Opcodes.D2L);  break;
1233                     case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
1234                     default:      error = true;               break;
1235                     }
1236                     break;
1237                 default:
1238                     error = true;
1239                     break;
1240                 }
1241                 if (error) {
1242                     throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
1243                 }
1244             }
1245         }
1246     }
1247 
1248     private void emitI2X(Wrapper type) {
1249         switch (type) {
1250         case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
1251         case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
1252         case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
1253         case INT:     /* naught */                break;
1254         case LONG:    mv.visitInsn(Opcodes.I2L);  break;
1255         case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
1256         case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
1257         case BOOLEAN:
1258             // For compatibility with ValueConversions and explicitCastArguments:
1259             mv.visitInsn(Opcodes.ICONST_1);
1260             mv.visitInsn(Opcodes.IAND);
1261             break;
1262         default:   throw new InternalError("unknown type: " + type);
1263         }
1264     }
1265 
1266     private void emitX2I(Wrapper type) {
1267         switch (type) {
1268         case LONG:    mv.visitInsn(Opcodes.L2I);  break;
1269         case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
1270         case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
1271         default:      throw new InternalError("unknown type: " + type);
1272         }
1273     }
1274 
1275     /**
1276      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
1277      */
1278     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
1279         assert(isValidSignature(sig));
1280         String name = "interpret_"+signatureReturn(sig).basicTypeChar();
1281         MethodType type = signatureType(sig);  // sig includes leading argument
1282         type = type.changeParameterType(0, MethodHandle.class);
1283         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
1284         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
1285     }
1286 
1287     private byte[] generateLambdaFormInterpreterEntryPointBytes() {
1288         classFilePrologue();
1289 
1290         // Suppress this method in backtraces displayed to the user.
1291         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1292 
1293         // Don't inline the interpreter entry.
1294         mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
1295 
1296         // create parameter array
1297         emitIconstInsn(invokerType.parameterCount());
1298         mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1299 
1300         // fill parameter array
1301         for (int i = 0; i < invokerType.parameterCount(); i++) {
1302             Class<?> ptype = invokerType.parameterType(i);
1303             mv.visitInsn(Opcodes.DUP);
1304             emitIconstInsn(i);
1305             emitLoadInsn(basicType(ptype), i);
1306             // box if primitive type
1307             if (ptype.isPrimitive()) {
1308                 emitBoxing(Wrapper.forPrimitiveType(ptype));
1309             }
1310             mv.visitInsn(Opcodes.AASTORE);
1311         }
1312         // invoke
1313         emitAloadInsn(0);
1314         mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1315         mv.visitInsn(Opcodes.SWAP);  // swap form and array; avoid local variable
1316         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1317 
1318         // maybe unbox
1319         Class<?> rtype = invokerType.returnType();
1320         if (rtype.isPrimitive() && rtype != void.class) {
1321             emitUnboxing(Wrapper.forPrimitiveType(rtype));
1322         }
1323 
1324         // return statement
1325         emitReturnInsn(basicType(rtype));
1326 
1327         classFileEpilogue();
1328         bogusMethod(invokerType);
1329 
1330         final byte[] classFile = cw.toByteArray();
1331         maybeDump(className, classFile);
1332         return classFile;
1333     }
1334 
1335     /**
1336      * Generate bytecode for a NamedFunction invoker.
1337      */
1338     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1339         MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1340         String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1341         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1342         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1343     }
1344 
1345     private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1346         MethodType dstType = typeForm.erasedType();
1347         classFilePrologue();
1348 
1349         // Suppress this method in backtraces displayed to the user.
1350         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
1351 
1352         // Force inlining of this invoker method.
1353         mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
1354 
1355         // Load receiver
1356         emitAloadInsn(0);
1357 
1358         // Load arguments from array
1359         for (int i = 0; i < dstType.parameterCount(); i++) {
1360             emitAloadInsn(1);
1361             emitIconstInsn(i);
1362             mv.visitInsn(Opcodes.AALOAD);
1363 
1364             // Maybe unbox
1365             Class<?> dptype = dstType.parameterType(i);
1366             if (dptype.isPrimitive()) {
1367                 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
1368                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
1369                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
1370                 emitUnboxing(srcWrapper);
1371                 emitPrimCast(srcWrapper, dstWrapper);
1372             }
1373         }
1374 
1375         // Invoke
1376         String targetDesc = dstType.basicType().toMethodDescriptorString();
1377         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1378 
1379         // Box primitive types
1380         Class<?> rtype = dstType.returnType();
1381         if (rtype != void.class && rtype.isPrimitive()) {
1382             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1383             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
1384             // boolean casts not allowed
1385             emitPrimCast(srcWrapper, dstWrapper);
1386             emitBoxing(dstWrapper);
1387         }
1388 
1389         // If the return type is void we return a null reference.
1390         if (rtype == void.class) {
1391             mv.visitInsn(Opcodes.ACONST_NULL);
1392         }
1393         emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
1394 
1395         classFileEpilogue();
1396         bogusMethod(dstType);
1397 
1398         final byte[] classFile = cw.toByteArray();
1399         maybeDump(className, classFile);
1400         return classFile;
1401     }
1402 
1403     /**
1404      * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1405      * for debugging purposes.
1406      */
1407     private void bogusMethod(Object... os) {
1408         if (DUMP_CLASS_FILES) {
1409             mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1410             for (Object o : os) {
1411                 mv.visitLdcInsn(o.toString());
1412                 mv.visitInsn(Opcodes.POP);
1413             }
1414             mv.visitInsn(Opcodes.RETURN);
1415             mv.visitMaxs(0, 0);
1416             mv.visitEnd();
1417         }
1418     }
1419 }