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