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