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