MethodEmitter.java revision 1002:2f0161551858
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.codegen;
27
28import static jdk.internal.org.objectweb.asm.Opcodes.ATHROW;
29import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
30import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
31import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
32import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
33import static jdk.internal.org.objectweb.asm.Opcodes.GOTO;
34import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
35import static jdk.internal.org.objectweb.asm.Opcodes.IFEQ;
36import static jdk.internal.org.objectweb.asm.Opcodes.IFGE;
37import static jdk.internal.org.objectweb.asm.Opcodes.IFGT;
38import static jdk.internal.org.objectweb.asm.Opcodes.IFLE;
39import static jdk.internal.org.objectweb.asm.Opcodes.IFLT;
40import static jdk.internal.org.objectweb.asm.Opcodes.IFNE;
41import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL;
42import static jdk.internal.org.objectweb.asm.Opcodes.IFNULL;
43import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ;
44import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE;
45import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ;
46import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE;
47import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGT;
48import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLE;
49import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT;
50import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE;
51import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF;
52import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
53import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
54import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
55import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
56import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
57import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
58import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
59import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
60import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
61import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
62import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
63import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
64import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
65import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
66import static jdk.nashorn.internal.codegen.CompilerConstants.className;
67import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
68import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
69import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
70import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
71import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
72import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
73import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
74
75import java.io.PrintStream;
76import java.lang.reflect.Array;
77import java.util.Collection;
78import java.util.EnumSet;
79import java.util.IdentityHashMap;
80import java.util.List;
81import java.util.Map;
82import jdk.internal.dynalink.support.NameCodec;
83import jdk.internal.org.objectweb.asm.Handle;
84import jdk.internal.org.objectweb.asm.MethodVisitor;
85import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
86import jdk.nashorn.internal.codegen.CompilerConstants.Call;
87import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
88import jdk.nashorn.internal.codegen.types.ArrayType;
89import jdk.nashorn.internal.codegen.types.BitwiseType;
90import jdk.nashorn.internal.codegen.types.NumericType;
91import jdk.nashorn.internal.codegen.types.Type;
92import jdk.nashorn.internal.ir.BreakableNode;
93import jdk.nashorn.internal.ir.FunctionNode;
94import jdk.nashorn.internal.ir.IdentNode;
95import jdk.nashorn.internal.ir.JoinPredecessor;
96import jdk.nashorn.internal.ir.LexicalContext;
97import jdk.nashorn.internal.ir.LiteralNode;
98import jdk.nashorn.internal.ir.LocalVariableConversion;
99import jdk.nashorn.internal.ir.RuntimeNode;
100import jdk.nashorn.internal.ir.Symbol;
101import jdk.nashorn.internal.ir.TryNode;
102import jdk.nashorn.internal.objects.Global;
103import jdk.nashorn.internal.runtime.ArgumentSetter;
104import jdk.nashorn.internal.runtime.Context;
105import jdk.nashorn.internal.runtime.Debug;
106import jdk.nashorn.internal.runtime.JSType;
107import jdk.nashorn.internal.runtime.RewriteException;
108import jdk.nashorn.internal.runtime.ScriptObject;
109import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
110import jdk.nashorn.internal.runtime.linker.Bootstrap;
111import jdk.nashorn.internal.runtime.logging.DebugLogger;
112import jdk.nashorn.internal.runtime.options.Options;
113
114/**
115 * This is the main function responsible for emitting method code
116 * in a class. It maintains a type stack and keeps track of control
117 * flow to make sure that the registered instructions don't violate
118 * byte code verification.
119 *
120 * Running Nashorn with -ea will assert as soon as a type stack
121 * becomes corrupt, for easier debugging
122 *
123 * Running Nashorn with -Dnashorn.codegen.debug=true will print
124 * all generated bytecode and labels to stderr, for easier debugging,
125 * including bytecode stack contents
126 */
127public class MethodEmitter implements Emitter {
128    /** The ASM MethodVisitor we are plugged into */
129    private final MethodVisitor method;
130
131    /** Parent classEmitter representing the class of this method */
132    private final ClassEmitter classEmitter;
133
134    /** FunctionNode representing this method, or null if none exists */
135    protected FunctionNode functionNode;
136
137    /** Current type stack for current evaluation */
138    private Label.Stack stack;
139
140    /** Check whether this emitter ever has a function return point */
141    private boolean hasReturn;
142
143    private boolean preventUndefinedLoad;
144
145    /**
146     * Map of live local variable definitions.
147     */
148    private final Map<Symbol, LocalVariableDef> localVariableDefs = new IdentityHashMap<>();
149
150    /** The context */
151    private final Context context;
152
153    /** Threshold in chars for when string constants should be split */
154    static final int LARGE_STRING_THRESHOLD = 32 * 1024;
155
156    /** Debug flag, should we dump all generated bytecode along with stacks? */
157    private final DebugLogger log;
158    private final boolean     debug;
159
160    /** dump stack on a particular line, or -1 if disabled */
161    private static final int DEBUG_TRACE_LINE;
162
163    static {
164        final String tl = Options.getStringProperty("nashorn.codegen.debug.trace", "-1");
165        int line = -1;
166        try {
167            line = Integer.parseInt(tl);
168        } catch (final NumberFormatException e) {
169            //fallthru
170        }
171        DEBUG_TRACE_LINE = line;
172    }
173
174    /** Bootstrap for normal indy:s */
175    private static final Handle LINKERBOOTSTRAP  = new Handle(H_INVOKESTATIC, Bootstrap.BOOTSTRAP.className(), Bootstrap.BOOTSTRAP.name(), Bootstrap.BOOTSTRAP.descriptor());
176
177    /** Bootstrap for runtime node indy:s */
178    private static final Handle RUNTIMEBOOTSTRAP = new Handle(H_INVOKESTATIC, RuntimeCallSite.BOOTSTRAP.className(), RuntimeCallSite.BOOTSTRAP.name(), RuntimeCallSite.BOOTSTRAP.descriptor());
179
180    /** Bootstrap for array populators */
181    private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor());
182
183    /** Bootstrap for global name invalidation */
184    private static final Handle INVALIDATE_NAME_BOOTSTRAP = new Handle(H_INVOKESTATIC, Global.BOOTSTRAP.className(), Global.BOOTSTRAP.name(), Global.BOOTSTRAP.descriptor());
185
186    /**
187     * Constructor - internal use from ClassEmitter only
188     * @see ClassEmitter#method
189     *
190     * @param classEmitter the class emitter weaving the class this method is in
191     * @param method       a method visitor
192     */
193    MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method) {
194        this(classEmitter, method, null);
195    }
196
197    /**
198     * Constructor - internal use from ClassEmitter only
199     * @see ClassEmitter#method
200     *
201     * @param classEmitter the class emitter weaving the class this method is in
202     * @param method       a method visitor
203     * @param functionNode a function node representing this method
204     */
205    MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method, final FunctionNode functionNode) {
206        this.context      = classEmitter.getContext();
207        this.classEmitter = classEmitter;
208        this.method       = method;
209        this.functionNode = functionNode;
210        this.stack        = null;
211        this.log          = context.getLogger(CodeGenerator.class);
212        this.debug        = log.isEnabled();
213    }
214
215    /**
216     * Begin a method
217     * @see Emitter
218     */
219    @Override
220    public void begin() {
221        classEmitter.beginMethod(this);
222        newStack();
223        method.visitCode();
224    }
225
226    /**
227     * End a method
228     * @see Emitter
229     */
230    @Override
231    public void end() {
232        method.visitMaxs(0, 0);
233        method.visitEnd();
234
235        classEmitter.endMethod(this);
236    }
237
238    boolean isReachable() {
239        return stack != null;
240    }
241
242    private void doesNotContinueSequentially() {
243        stack = null;
244    }
245
246    private void newStack() {
247        stack = new Label.Stack();
248    }
249
250    @Override
251    public String toString() {
252        return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
253    }
254
255    /**
256     * Push a type to the existing stack
257     * @param type the type
258     */
259    void pushType(final Type type) {
260        if (type != null) {
261            stack.push(type);
262        }
263    }
264
265    /**
266     * Pop a type from the existing stack
267     *
268     * @param expected expected type - will assert if wrong
269     *
270     * @return the type that was retrieved
271     */
272    private Type popType(final Type expected) {
273        final Type type = popType();
274        assert type.isObject() && expected.isObject() ||
275            type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
276        return type;
277    }
278
279    /**
280     * Pop a type from the existing stack, no matter what it is.
281     *
282     * @return the type
283     */
284    private Type popType() {
285        return stack.pop();
286    }
287
288    /**
289     * Pop a type from the existing stack, ensuring that it is numeric. Boolean type is popped as int type.
290     *
291     * @return the type
292     */
293    private NumericType popNumeric() {
294        final Type type = popType();
295        if(type.isBoolean()) {
296            // Booleans are treated as int for purposes of arithmetic operations
297            return Type.INT;
298        }
299        assert type.isNumeric();
300        return (NumericType)type;
301    }
302
303    /**
304     * Pop a type from the existing stack, ensuring that it is an integer type
305     * (integer or long). Boolean type is popped as int type.
306     *
307     * @return the type
308     */
309    private BitwiseType popBitwise() {
310        final Type type = popType();
311        if(type == Type.BOOLEAN) {
312            return Type.INT;
313        }
314        return (BitwiseType)type;
315    }
316
317    private BitwiseType popInteger() {
318        final Type type = popType();
319        if(type == Type.BOOLEAN) {
320            return Type.INT;
321        }
322        assert type == Type.INT;
323        return (BitwiseType)type;
324    }
325
326    /**
327     * Pop a type from the existing stack, ensuring that it is an array type,
328     * assert if not
329     *
330     * @return the type
331     */
332    private ArrayType popArray() {
333        final Type type = popType();
334        assert type.isArray() : type;
335        return (ArrayType)type;
336    }
337
338    /**
339     * Peek a given number of slots from the top of the stack and return the
340     * type in that slot
341     *
342     * @param pos the number of positions from the top, 0 is the top element
343     *
344     * @return the type at position "pos" on the stack
345     */
346    final Type peekType(final int pos) {
347        return stack.peek(pos);
348    }
349
350    /**
351     * Peek at the type at the top of the stack
352     *
353     * @return the type at the top of the stack
354     */
355    final Type peekType() {
356        return stack.peek();
357    }
358
359    /**
360     * Generate code a for instantiating a new object and push the
361     * object type on the stack
362     *
363     * @param classDescriptor class descriptor for the object type
364     * @param type the type of the new object
365     *
366     * @return the method emitter
367     */
368    MethodEmitter _new(final String classDescriptor, final Type type) {
369        debug("new", classDescriptor);
370        method.visitTypeInsn(NEW, classDescriptor);
371        pushType(type);
372        return this;
373    }
374
375    /**
376     * Generate code a for instantiating a new object and push the
377     * object type on the stack
378     *
379     * @param clazz class type to instatiate
380     *
381     * @return the method emitter
382     */
383    MethodEmitter _new(final Class<?> clazz) {
384        return _new(className(clazz), Type.typeFor(clazz));
385    }
386
387    /**
388     * Generate code to call the empty constructor for a class
389     *
390     * @param clazz class type to instatiate
391     *
392     * @return the method emitter
393     */
394    MethodEmitter newInstance(final Class<?> clazz) {
395        return invoke(constructorNoLookup(clazz));
396    }
397
398    /**
399     * Perform a dup, that is, duplicate the top element and
400     * push the duplicate down a given number of positions
401     * on the stack. This is totally type agnostic.
402     *
403     * @param depth the depth on which to put the copy
404     *
405     * @return the method emitter, or null if depth is illegal and
406     *  has no instruction equivalent.
407     */
408    MethodEmitter dup(final int depth) {
409        if (peekType().dup(method, depth) == null) {
410            return null;
411        }
412
413        debug("dup", depth);
414
415        switch (depth) {
416        case 0: {
417            final int l0 = stack.getTopLocalLoad();
418            pushType(peekType());
419            stack.markLocalLoad(l0);
420            break;
421        }
422        case 1: {
423            final int l0 = stack.getTopLocalLoad();
424            final Type p0 = popType();
425            final int l1 = stack.getTopLocalLoad();
426            final Type p1 = popType();
427            pushType(p0);
428            stack.markLocalLoad(l0);
429            pushType(p1);
430            stack.markLocalLoad(l1);
431            pushType(p0);
432            stack.markLocalLoad(l0);
433            break;
434        }
435        case 2: {
436            final int l0 = stack.getTopLocalLoad();
437            final Type p0 = popType();
438            final int l1 = stack.getTopLocalLoad();
439            final Type p1 = popType();
440            final int l2 = stack.getTopLocalLoad();
441            final Type p2 = popType();
442            pushType(p0);
443            stack.markLocalLoad(l0);
444            pushType(p2);
445            stack.markLocalLoad(l2);
446            pushType(p1);
447            stack.markLocalLoad(l1);
448            pushType(p0);
449            stack.markLocalLoad(l0);
450            break;
451        }
452        default:
453            assert false : "illegal dup depth = " + depth;
454            return null;
455        }
456
457        return this;
458    }
459
460    /**
461     * Perform a dup2, that is, duplicate the top element if it
462     * is a category 2 type, or two top elements if they are category
463     * 1 types, and push them on top of the stack
464     *
465     * @return the method emitter
466     */
467    MethodEmitter dup2() {
468        debug("dup2");
469
470        if (peekType().isCategory2()) {
471            final int l0 = stack.getTopLocalLoad();
472            pushType(peekType());
473            stack.markLocalLoad(l0);
474        } else {
475            final int l0 = stack.getTopLocalLoad();
476            final Type p0 = popType();
477            final int l1 = stack.getTopLocalLoad();
478            final Type p1 = popType();
479            pushType(p0);
480            stack.markLocalLoad(l0);
481            pushType(p1);
482            stack.markLocalLoad(l1);
483            pushType(p0);
484            stack.markLocalLoad(l0);
485            pushType(p1);
486            stack.markLocalLoad(l1);
487        }
488        method.visitInsn(DUP2);
489        return this;
490    }
491
492    /**
493     * Duplicate the top element on the stack and push it
494     *
495     * @return the method emitter
496     */
497    MethodEmitter dup() {
498        return dup(0);
499    }
500
501    /**
502     * Pop the top element of the stack and throw it away
503     *
504     * @return the method emitter
505     */
506    MethodEmitter pop() {
507        debug("pop", peekType());
508        popType().pop(method);
509        return this;
510    }
511
512    /**
513     * Pop the top element of the stack if category 2 type, or the two
514     * top elements of the stack if category 1 types
515     *
516     * @return the method emitter
517     */
518    MethodEmitter pop2() {
519        if (peekType().isCategory2()) {
520            popType();
521        } else {
522            get2n();
523        }
524        return this;
525    }
526
527    /**
528     * Swap the top two elements of the stack. This is totally
529     * type agnostic and works for all types
530     *
531     * @return the method emitter
532     */
533    MethodEmitter swap() {
534        debug("swap");
535
536        final int l0 = stack.getTopLocalLoad();
537        final Type p0 = popType();
538        final int l1 = stack.getTopLocalLoad();
539        final Type p1 = popType();
540        p0.swap(method, p1);
541
542        pushType(p0);
543        stack.markLocalLoad(l0);
544        pushType(p1);
545        stack.markLocalLoad(l1);
546        return this;
547    }
548
549    void pack() {
550        final Type type = peekType();
551        if (type.isInteger()) {
552            convert(PRIMITIVE_FIELD_TYPE);
553        } else if (type.isLong()) {
554            //nop
555        } else if (type.isNumber()) {
556            invokestatic("java/lang/Double", "doubleToRawLongBits", "(D)J");
557        } else {
558            assert false : type + " cannot be packed!";
559        }
560        //all others are nops, objects aren't packed
561    }
562
563    /**
564     * Initializes a bytecode method parameter
565     * @param symbol the symbol for the parameter
566     * @param type the type of the parameter
567     * @param start the label for the start of the method
568     */
569    void initializeMethodParameter(final Symbol symbol, final Type type, final Label start) {
570        assert symbol.isBytecodeLocal();
571        localVariableDefs.put(symbol, new LocalVariableDef(start.getLabel(), type));
572    }
573
574    /**
575     * Create a new string builder, call the constructor and push the instance to the stack.
576     *
577     * @return the method emitter
578     */
579    MethodEmitter newStringBuilder() {
580        return invoke(constructorNoLookup(StringBuilder.class)).dup();
581    }
582
583    /**
584     * Pop a string and a StringBuilder from the top of the stack and call the append
585     * function of the StringBuilder, appending the string. Pushes the StringBuilder to
586     * the stack when finished.
587     *
588     * @return the method emitter
589     */
590    MethodEmitter stringBuilderAppend() {
591        convert(Type.STRING);
592        return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
593    }
594
595    /**
596     * Pops two integer types from the stack, performs a bitwise and and pushes
597     * the result
598     *
599     * @return the method emitter
600     */
601    MethodEmitter and() {
602        debug("and");
603        pushType(get2i().and(method));
604        return this;
605    }
606
607    /**
608     * Pops two integer types from the stack, performs a bitwise or and pushes
609     * the result
610     *
611     * @return the method emitter
612     */
613    MethodEmitter or() {
614        debug("or");
615        pushType(get2i().or(method));
616        return this;
617    }
618
619    /**
620     * Pops two integer types from the stack, performs a bitwise xor and pushes
621     * the result
622     *
623     * @return the method emitter
624     */
625    MethodEmitter xor() {
626        debug("xor");
627        pushType(get2i().xor(method));
628        return this;
629    }
630
631    /**
632     * Pops two integer types from the stack, performs a bitwise logic shift right and pushes
633     * the result. The shift count, the first element, must be INT.
634     *
635     * @return the method emitter
636     */
637    MethodEmitter shr() {
638        debug("shr");
639        popInteger();
640        pushType(popBitwise().shr(method));
641        return this;
642    }
643
644    /**
645     * Pops two integer types from the stack, performs a bitwise shift left and and pushes
646     * the result. The shift count, the first element, must be INT.
647     *
648     * @return the method emitter
649     */
650    MethodEmitter shl() {
651        debug("shl");
652        popInteger();
653        pushType(popBitwise().shl(method));
654        return this;
655    }
656
657    /**
658     * Pops two integer types from the stack, performs a bitwise arithmetic shift right and pushes
659     * the result. The shift count, the first element, must be INT.
660     *
661     * @return the method emitter
662     */
663    MethodEmitter sar() {
664        debug("sar");
665        popInteger();
666        pushType(popBitwise().sar(method));
667        return this;
668    }
669
670    /**
671     * Pops a numeric type from the stack, negates it and pushes the result
672     *
673     * @return the method emitter
674     */
675    MethodEmitter neg(final int programPoint) {
676        debug("neg");
677        pushType(popNumeric().neg(method, programPoint));
678        return this;
679    }
680
681    /**
682     * Add label for the start of a catch block and push the exception to the
683     * stack
684     *
685     * @param recovery label pointing to start of catch block
686     */
687    void _catch(final Label recovery) {
688        // While in JVM a catch block can be reached through normal control flow, our code generator never does this,
689        // so we might as well presume there's no stack on entry.
690        assert stack == null;
691        recovery.onCatch();
692        label(recovery);
693        beginCatchBlock();
694    }
695
696    /**
697     * Add any number of labels for the start of a catch block and push the exception to the
698     * stack
699     *
700     * @param recoveries labels pointing to start of catch block
701     */
702    void _catch(final Collection<Label> recoveries) {
703        assert stack == null;
704        for(final Label l: recoveries) {
705            label(l);
706        }
707        beginCatchBlock();
708    }
709
710    private void beginCatchBlock() {
711        // It can happen that the catch label wasn't marked as reachable. They are marked as reachable if there's an
712        // assignment in the try block, but it's possible that there was none.
713        if(!isReachable()) {
714            newStack();
715        }
716        pushType(Type.typeFor(Throwable.class));
717    }
718    /**
719     * Start a try/catch block.
720     *
721     * @param entry          start label for try
722     * @param exit           end label for try
723     * @param recovery       start label for catch
724     * @param typeDescriptor type descriptor for exception
725     * @param isOptimismHandler true if this is a hander for {@code UnwarrantedOptimismException}. Normally joining on a
726     * catch handler kills temporary variables, but optimism handlers are an exception, as they need to capture
727     * temporaries as well, so they must remain live.
728     */
729    private void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor, final boolean isOptimismHandler) {
730        recovery.joinFromTry(entry.getStack(), isOptimismHandler);
731        method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
732    }
733
734    /**
735     * Start a try/catch block.
736     *
737     * @param entry    start label for try
738     * @param exit     end label for try
739     * @param recovery start label for catch
740     * @param clazz    exception class
741     */
742    void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
743        _try(entry, exit, recovery, CompilerConstants.className(clazz), clazz == UnwarrantedOptimismException.class);
744    }
745
746    /**
747     * Start a try/catch block. The catch is "Throwable" - i.e. catch-all
748     *
749     * @param entry    start label for try
750     * @param exit     end label for try
751     * @param recovery start label for catch
752     */
753    void _try(final Label entry, final Label exit, final Label recovery) {
754        _try(entry, exit, recovery, (String)null, false);
755    }
756
757    void markLabelAsOptimisticCatchHandler(final Label label, final int liveLocalCount) {
758        label.markAsOptimisticCatchHandler(stack, liveLocalCount);
759    }
760
761    /**
762     * Load the constants array
763     * @return this method emitter
764     */
765    MethodEmitter loadConstants() {
766        getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
767        assert peekType().isArray() : peekType();
768        return this;
769    }
770
771    /**
772     * Push the undefined value for the given type, i.e.
773     * UNDEFINED or UNDEFINEDNUMBER. Currently we have no way of
774     * representing UNDEFINED for INTs and LONGs, so they are not
775     * allowed to be local variables (yet)
776     *
777     * @param type the type for which to push UNDEFINED
778     * @return the method emitter
779     */
780    MethodEmitter loadUndefined(final Type type) {
781        debug("load undefined ", type);
782        pushType(type.loadUndefined(method));
783        return this;
784    }
785
786    MethodEmitter loadForcedInitializer(final Type type) {
787        debug("load forced initializer ", type);
788        pushType(type.loadForcedInitializer(method));
789        return this;
790    }
791
792    /**
793     * Push the empty value for the given type, i.e. EMPTY.
794     *
795     * @param type the type
796     * @return the method emitter
797     */
798    MethodEmitter loadEmpty(final Type type) {
799        debug("load empty ", type);
800        pushType(type.loadEmpty(method));
801        return this;
802    }
803
804    /**
805     * Push null to stack
806     *
807     * @return the method emitter
808     */
809    MethodEmitter loadNull() {
810        debug("aconst_null");
811        pushType(Type.OBJECT.ldc(method, null));
812        return this;
813    }
814
815    /**
816     * Push a handle representing this class top stack
817     *
818     * @param className name of the class
819     *
820     * @return the method emitter
821     */
822    MethodEmitter loadType(final String className) {
823        debug("load type", className);
824        method.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(className));
825        pushType(Type.OBJECT);
826        return this;
827    }
828
829    /**
830     * Push a boolean constant to the stack.
831     *
832     * @param b value of boolean
833     *
834     * @return the method emitter
835     */
836    MethodEmitter load(final boolean b) {
837        debug("load boolean", b);
838        pushType(Type.BOOLEAN.ldc(method, b));
839        return this;
840    }
841
842    /**
843     * Push an int constant to the stack
844     *
845     * @param i value of the int
846     *
847     * @return the method emitter
848     */
849    MethodEmitter load(final int i) {
850        debug("load int", i);
851        pushType(Type.INT.ldc(method, i));
852        return this;
853    }
854
855    /**
856     * Push a double constant to the stack
857     *
858     * @param d value of the double
859     *
860     * @return the method emitter
861     */
862    MethodEmitter load(final double d) {
863        debug("load double", d);
864        pushType(Type.NUMBER.ldc(method, d));
865        return this;
866    }
867
868    /**
869     * Push an long constant to the stack
870     *
871     * @param l value of the long
872     *
873     * @return the method emitter
874     */
875    MethodEmitter load(final long l) {
876        debug("load long", l);
877        pushType(Type.LONG.ldc(method, l));
878        return this;
879    }
880
881    /**
882     * Fetch the length of an array.
883     * @return Array length.
884     */
885    MethodEmitter arraylength() {
886        debug("arraylength");
887        popType(Type.OBJECT);
888        pushType(Type.OBJECT_ARRAY.arraylength(method));
889        return this;
890    }
891
892    /**
893     * Push a String constant to the stack
894     *
895     * @param s value of the String
896     *
897     * @return the method emitter
898     */
899    MethodEmitter load(final String s) {
900        debug("load string", s);
901
902        if (s == null) {
903            loadNull();
904            return this;
905        }
906
907        //NASHORN-142 - split too large string
908        final int length = s.length();
909        if (length > LARGE_STRING_THRESHOLD) {
910
911            _new(StringBuilder.class);
912            dup();
913            load(length);
914            invoke(constructorNoLookup(StringBuilder.class, int.class));
915
916            for (int n = 0; n < length; n += LARGE_STRING_THRESHOLD) {
917                final String part = s.substring(n, Math.min(n + LARGE_STRING_THRESHOLD, length));
918                load(part);
919                stringBuilderAppend();
920            }
921
922            invoke(virtualCallNoLookup(StringBuilder.class, "toString", String.class));
923
924            return this;
925        }
926
927        pushType(Type.OBJECT.ldc(method, s));
928        return this;
929    }
930
931    /**
932     * Pushes the value of an identifier to the stack. If the identifier does not represent a local variable or a
933     * parameter, this will be a no-op.
934     *
935     * @param ident the identifier for the variable being loaded.
936     *
937     * @return the method emitter
938     */
939    MethodEmitter load(final IdentNode ident) {
940        return load(ident.getSymbol(), ident.getType());
941    }
942
943    /**
944     * Pushes the value of the symbol to the stack with the specified type. No type conversion is being performed, and
945     * the type is only being used if the symbol addresses a local variable slot. The value of the symbol is loaded if
946     * it addresses a local variable slot, or it is a parameter (in which case it can also be loaded from a vararg array
947     * or the arguments object). If it is neither, the operation is a no-op.
948     *
949     * @param symbol the symbol addressing the value being loaded
950     * @param type the presumed type of the value when it is loaded from a local variable slot
951     * @return the method emitter
952     */
953    MethodEmitter load(final Symbol symbol, final Type type) {
954        assert symbol != null;
955        if (symbol.hasSlot()) {
956            final int slot = symbol.getSlot(type);
957            debug("load symbol", symbol.getName(), " slot=", slot, "type=", type);
958            load(type, slot);
959           // _try(new Label("dummy"), new Label("dummy2"), recovery);
960           // method.visitTryCatchBlock(new Label(), arg1, arg2, arg3);
961        } else if (symbol.isParam()) {
962            assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
963            final int index = symbol.getFieldIndex();
964            if (functionNode.needsArguments()) {
965                // ScriptObject.getArgument(int) on arguments
966                debug("load symbol", symbol.getName(), " arguments index=", index);
967                loadCompilerConstant(ARGUMENTS);
968                load(index);
969                ScriptObject.GET_ARGUMENT.invoke(this);
970            } else {
971                // array load from __varargs__
972                debug("load symbol", symbol.getName(), " array index=", index);
973                loadCompilerConstant(VARARGS);
974                load(symbol.getFieldIndex());
975                arrayload();
976            }
977        }
978        return this;
979    }
980
981    /**
982     * Push a local variable to the stack, given an explicit bytecode slot.
983     * This is used e.g. for stub generation where we know where items like
984     * "this" and "scope" reside.
985     *
986     * @param type  the type of the variable
987     * @param slot  the slot the variable is in
988     *
989     * @return the method emitter
990     */
991    MethodEmitter load(final Type type, final int slot) {
992        debug("explicit load", type, slot);
993        final Type loadType = type.load(method, slot);
994        assert loadType != null;
995        pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType);
996        assert !preventUndefinedLoad || (slot < stack.localVariableTypes.size() && stack.localVariableTypes.get(slot) != Type.UNKNOWN)
997            : "Attempted load of uninitialized slot " + slot + " (as type " + type + ")";
998        stack.markLocalLoad(slot);
999        return this;
1000    }
1001
1002    private boolean isThisSlot(final int slot) {
1003        if (functionNode == null) {
1004            return slot == CompilerConstants.JAVA_THIS.slot();
1005        }
1006        final int thisSlot = getCompilerConstantSymbol(THIS).getSlot(Type.OBJECT);
1007        assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
1008        assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
1009        return slot == thisSlot;
1010    }
1011
1012    /**
1013     * Push a method handle to the stack
1014     *
1015     * @param className  class name
1016     * @param methodName method name
1017     * @param descName   descriptor
1018     * @param flags      flags that describe this handle, e.g. invokespecial new, or invoke virtual
1019     *
1020     * @return the method emitter
1021     */
1022    MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet<Flag> flags) {
1023        debug("load handle ");
1024        pushType(Type.OBJECT.ldc(method, new Handle(Flag.getValue(flags), className, methodName, descName)));
1025        return this;
1026    }
1027
1028    private Symbol getCompilerConstantSymbol(final CompilerConstants cc) {
1029        return functionNode.getBody().getExistingSymbol(cc.symbolName());
1030    }
1031
1032    /**
1033     * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
1034     * the scope).
1035     * @return if this method has a slot allocated for the scope variable.
1036     */
1037    boolean hasScope() {
1038        return getCompilerConstantSymbol(SCOPE).hasSlot();
1039    }
1040
1041    MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
1042        return loadCompilerConstant(cc, null);
1043    }
1044
1045    MethodEmitter loadCompilerConstant(final CompilerConstants cc, final Type type) {
1046        if (cc == SCOPE && peekType() == Type.SCOPE) {
1047            dup();
1048            return this;
1049        }
1050        return load(getCompilerConstantSymbol(cc), type != null ? type : getCompilerConstantType(cc));
1051    }
1052
1053    void storeCompilerConstant(final CompilerConstants cc) {
1054        storeCompilerConstant(cc, null);
1055    }
1056
1057    void storeCompilerConstant(final CompilerConstants cc, final Type type) {
1058        final Symbol symbol = getCompilerConstantSymbol(cc);
1059        if(!symbol.hasSlot()) {
1060            return;
1061        }
1062        debug("store compiler constant ", symbol);
1063        store(symbol, type != null ? type : getCompilerConstantType(cc));
1064    }
1065
1066    private static Type getCompilerConstantType(final CompilerConstants cc) {
1067        final Class<?> constantType = cc.type();
1068        assert constantType != null;
1069        return Type.typeFor(constantType);
1070    }
1071
1072    /**
1073     * Load an element from an array, determining type automatically
1074     * @return the method emitter
1075     */
1076    MethodEmitter arrayload() {
1077        debug("Xaload");
1078        popType(Type.INT);
1079        pushType(popArray().aload(method));
1080        return this;
1081    }
1082
1083    /**
1084     * Pop a value, an index and an array from the stack and store
1085     * the value at the given index in the array.
1086     */
1087    void arraystore() {
1088        debug("Xastore");
1089        final Type value = popType();
1090        final Type index = popType(Type.INT);
1091        assert index.isInteger() : "array index is not integer, but " + index;
1092        final ArrayType array = popArray();
1093
1094        assert value.isEquivalentTo(array.getElementType()) : "Storing "+value+" into "+array;
1095        assert array.isObject();
1096        array.astore(method);
1097    }
1098
1099    /**
1100     * Pop a value from the stack and store it in a local variable represented
1101     * by the given identifier. If the symbol has no slot, this is a NOP
1102     *
1103     * @param ident identifier to store stack to
1104     */
1105    void store(final IdentNode ident) {
1106        final Type type = ident.getType();
1107        final Symbol symbol = ident.getSymbol();
1108        if(type == Type.UNDEFINED) {
1109            assert peekType() == Type.UNDEFINED;
1110            store(symbol, Type.OBJECT);
1111        } else {
1112            store(symbol, type);
1113        }
1114    }
1115
1116    /**
1117     * Represents a definition of a local variable with a type. Used for local variable table building.
1118     */
1119    private static class LocalVariableDef {
1120        // The start label from where this definition lives.
1121        private final jdk.internal.org.objectweb.asm.Label label;
1122        // The currently live type of the local variable.
1123        private final Type type;
1124
1125        LocalVariableDef(final jdk.internal.org.objectweb.asm.Label label, final Type type) {
1126            this.label = label;
1127            this.type = type;
1128        }
1129
1130    }
1131
1132    void closeLocalVariable(final Symbol symbol, final Label label) {
1133        final LocalVariableDef def = localVariableDefs.get(symbol);
1134        if(def != null) {
1135            endLocalValueDef(symbol, def, label.getLabel());
1136        }
1137        if(isReachable()) {
1138            markDeadLocalVariable(symbol);
1139        }
1140    }
1141
1142    void markDeadLocalVariable(final Symbol symbol) {
1143        if(!symbol.isDead()) {
1144            markDeadSlots(symbol.getFirstSlot(), symbol.slotCount());
1145        }
1146    }
1147
1148    void markDeadSlots(final int firstSlot, final int slotCount) {
1149        stack.markDeadLocalVariables(firstSlot, slotCount);
1150    }
1151
1152    private void endLocalValueDef(final Symbol symbol, final LocalVariableDef def, final jdk.internal.org.objectweb.asm.Label label) {
1153        String name = symbol.getName();
1154        if (name.equals(THIS.symbolName())) {
1155            name = THIS_DEBUGGER.symbolName();
1156        }
1157        method.visitLocalVariable(name, def.type.getDescriptor(), null, def.label, label, symbol.getSlot(def.type));
1158    }
1159
1160    void store(final Symbol symbol, final Type type) {
1161        store(symbol, type, true);
1162    }
1163
1164    /**
1165     * Pop a value from the stack and store it in a variable denoted by the given symbol. The variable should be either
1166     * a local variable, or a function parameter (and not a scoped variable). For local variables, this method will also
1167     * do the bookeeping of the local variable table as well as mark values in all alternative slots for the symbol as
1168     * dead. In this regard it differs from {@link #storeHidden(Type, int)}.
1169     *
1170     * @param symbol the symbol to store into.
1171     * @param type the type to store
1172     * @param onlySymbolLiveValue if true, this is the sole live value for the symbol. If false, currently live values should
1173     * be kept live.
1174     */
1175    void store(final Symbol symbol, final Type type, final boolean onlySymbolLiveValue) {
1176        assert symbol != null : "No symbol to store";
1177        if (symbol.hasSlot()) {
1178            final boolean isLiveType = symbol.hasSlotFor(type);
1179            final LocalVariableDef existingDef = localVariableDefs.get(symbol);
1180            if(existingDef == null || existingDef.type != type) {
1181                final jdk.internal.org.objectweb.asm.Label here = new jdk.internal.org.objectweb.asm.Label();
1182                if(isLiveType) {
1183                    final LocalVariableDef newDef = new LocalVariableDef(here, type);
1184                    localVariableDefs.put(symbol, newDef);
1185                }
1186                method.visitLabel(here);
1187                if(existingDef != null) {
1188                    endLocalValueDef(symbol, existingDef, here);
1189                }
1190            }
1191            if(isLiveType) {
1192                final int slot = symbol.getSlot(type);
1193                debug("store symbol", symbol.getName(), " type=", type, " slot=", slot);
1194                storeHidden(type, slot, onlySymbolLiveValue);
1195            } else {
1196                if(onlySymbolLiveValue) {
1197                    markDeadLocalVariable(symbol);
1198                }
1199                debug("dead store symbol ", symbol.getName(), " type=", type);
1200                pop();
1201            }
1202        } else if (symbol.isParam()) {
1203            assert !symbol.isScope();
1204            assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
1205            final int index = symbol.getFieldIndex();
1206            if (functionNode.needsArguments()) {
1207                convert(Type.OBJECT);
1208                debug("store symbol", symbol.getName(), " arguments index=", index);
1209                loadCompilerConstant(ARGUMENTS);
1210                load(index);
1211                ArgumentSetter.SET_ARGUMENT.invoke(this);
1212            } else {
1213                convert(Type.OBJECT);
1214                // varargs without arguments object - just do array store to __varargs__
1215                debug("store symbol", symbol.getName(), " array index=", index);
1216                loadCompilerConstant(VARARGS);
1217                load(index);
1218                ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this);
1219            }
1220        } else {
1221            debug("dead store symbol ", symbol.getName(), " type=", type);
1222            pop();
1223        }
1224    }
1225
1226    /**
1227     * Pop a value from the stack and store it in a local variable slot. Note that in contrast with
1228     * {@link #store(Symbol, Type)}, this method does not adjust the local variable table, nor marks slots for
1229     * alternative value types for the symbol as being dead. For that reason, this method is usually not called
1230     * directly. Notable exceptions are temporary internal locals (e.g. quick store, last-catch-condition, etc.) that
1231     * are not desired to show up in the local variable table.
1232     *
1233     * @param type the type to pop
1234     * @param slot the slot
1235     */
1236    void storeHidden(final Type type, final int slot) {
1237        storeHidden(type, slot, true);
1238    }
1239
1240    void storeHidden(final Type type, final int slot, final boolean onlyLiveSymbolValue) {
1241        explicitStore(type, slot);
1242        stack.onLocalStore(type, slot, onlyLiveSymbolValue);
1243    }
1244
1245    void storeTemp(final Type type, final int slot) {
1246        explicitStore(type, slot);
1247        defineTemporaryLocalVariable(slot, slot + type.getSlots());
1248        onLocalStore(type, slot);
1249    }
1250
1251    void onLocalStore(final Type type, final int slot) {
1252        stack.onLocalStore(type, slot, true);
1253    }
1254
1255    private void explicitStore(final Type type, final int slot) {
1256        assert slot != -1;
1257        debug("explicit store", type, slot);
1258        popType(type);
1259        type.store(method, slot);
1260    }
1261
1262    /**
1263     * Marks a range of slots as belonging to a defined local variable. The slots will start out with no live value
1264     * in them.
1265     * @param fromSlot first slot, inclusive.
1266     * @param toSlot last slot, exclusive.
1267     */
1268    void defineBlockLocalVariable(final int fromSlot, final int toSlot) {
1269        stack.defineBlockLocalVariable(fromSlot, toSlot);
1270    }
1271
1272    /**
1273     * Marks a range of slots as belonging to a defined temporary local variable. The slots will start out with no
1274     * live value in them.
1275     * @param fromSlot first slot, inclusive.
1276     * @param toSlot last slot, exclusive.
1277     */
1278    void defineTemporaryLocalVariable(final int fromSlot, final int toSlot) {
1279        stack.defineTemporaryLocalVariable(fromSlot, toSlot);
1280    }
1281
1282    /**
1283     * Defines a new temporary local variable and returns its allocated index.
1284     * @param width the required width (in slots) for the new variable.
1285     * @return the bytecode slot index where the newly allocated local begins.
1286     */
1287    int defineTemporaryLocalVariable(final int width) {
1288        return stack.defineTemporaryLocalVariable(width);
1289    }
1290
1291    void undefineLocalVariables(final int fromSlot, final boolean canTruncateSymbol) {
1292        if(isReachable()) {
1293            stack.undefineLocalVariables(fromSlot, canTruncateSymbol);
1294        }
1295    }
1296
1297    List<Type> getLocalVariableTypes() {
1298        return stack.localVariableTypes;
1299    }
1300
1301    List<Type> getWidestLiveLocals(final List<Type> localTypes) {
1302        return stack.getWidestLiveLocals(localTypes);
1303    }
1304
1305    String markSymbolBoundariesInLvarTypesDescriptor(final String lvarDescriptor) {
1306        return stack.markSymbolBoundariesInLvarTypesDescriptor(lvarDescriptor);
1307    }
1308
1309    /**
1310     * Increment/Decrement a local integer by the given value.
1311     *
1312     * @param slot the int slot
1313     * @param increment the amount to increment
1314     */
1315    void iinc(final int slot, final int increment) {
1316        debug("iinc");
1317        method.visitIincInsn(slot, increment);
1318    }
1319
1320    /**
1321     * Pop an exception object from the stack and generate code
1322     * for throwing it
1323     */
1324    public void athrow() {
1325        debug("athrow");
1326        final Type receiver = popType(Type.OBJECT);
1327        assert Throwable.class.isAssignableFrom(receiver.getTypeClass()) : receiver.getTypeClass();
1328        method.visitInsn(ATHROW);
1329        doesNotContinueSequentially();
1330    }
1331
1332    /**
1333     * Pop an object from the stack and perform an instanceof
1334     * operation, given a classDescriptor to compare it to.
1335     * Push the boolean result 1/0 as an int to the stack
1336     *
1337     * @param classDescriptor descriptor of the class to type check against
1338     *
1339     * @return the method emitter
1340     */
1341    MethodEmitter _instanceof(final String classDescriptor) {
1342        debug("instanceof", classDescriptor);
1343        popType(Type.OBJECT);
1344        method.visitTypeInsn(INSTANCEOF, classDescriptor);
1345        pushType(Type.INT);
1346        return this;
1347    }
1348
1349    /**
1350     * Pop an object from the stack and perform an instanceof
1351     * operation, given a classDescriptor to compare it to.
1352     * Push the boolean result 1/0 as an int to the stack
1353     *
1354     * @param clazz the type to check instanceof against
1355     *
1356     * @return the method emitter
1357     */
1358    MethodEmitter _instanceof(final Class<?> clazz) {
1359        return _instanceof(CompilerConstants.className(clazz));
1360    }
1361
1362    /**
1363     * Perform a checkcast operation on the object at the top of the
1364     * stack.
1365     *
1366     * @param classDescriptor descriptor of the class to type check against
1367     *
1368     * @return the method emitter
1369     */
1370    MethodEmitter checkcast(final String classDescriptor) {
1371        debug("checkcast", classDescriptor);
1372        assert peekType().isObject();
1373        method.visitTypeInsn(CHECKCAST, classDescriptor);
1374        return this;
1375    }
1376
1377    /**
1378     * Perform a checkcast operation on the object at the top of the
1379     * stack.
1380     *
1381     * @param clazz class to checkcast against
1382     *
1383     * @return the method emitter
1384     */
1385    MethodEmitter checkcast(final Class<?> clazz) {
1386        return checkcast(CompilerConstants.className(clazz));
1387    }
1388
1389    /**
1390     * Instantiate a new array given a length that is popped
1391     * from the stack and the array type
1392     *
1393     * @param arrayType the type of the array
1394     *
1395     * @return the method emitter
1396     */
1397    MethodEmitter newarray(final ArrayType arrayType) {
1398        debug("newarray ", "arrayType=", arrayType);
1399        popType(Type.INT); //LENGTH
1400        pushType(arrayType.newarray(method));
1401        return this;
1402    }
1403
1404    /**
1405     * Instantiate a multidimensional array with a given number of dimensions.
1406     * On the stack are dim lengths of the sub arrays.
1407     *
1408     * @param arrayType type of the array
1409     * @param dims      number of dimensions
1410     *
1411     * @return the method emitter
1412     */
1413    MethodEmitter multinewarray(final ArrayType arrayType, final int dims) {
1414        debug("multianewarray ", arrayType, dims);
1415        for (int i = 0; i < dims; i++) {
1416            popType(Type.INT); //LENGTH
1417        }
1418        pushType(arrayType.newarray(method, dims));
1419        return this;
1420    }
1421
1422    /**
1423     * Helper function to pop and type check the appropriate arguments
1424     * from the stack given a method signature
1425     *
1426     * @param signature method signature
1427     *
1428     * @return return type of method
1429     */
1430    private Type fixParamStack(final String signature) {
1431        final Type[] params = Type.getMethodArguments(signature);
1432        for (int i = params.length - 1; i >= 0; i--) {
1433            popType(params[i]);
1434        }
1435        final Type returnType = Type.getMethodReturnType(signature);
1436        return returnType;
1437    }
1438
1439    /**
1440     * Generate an invocation to a Call structure
1441     * @see CompilerConstants
1442     *
1443     * @param call the call object
1444     *
1445     * @return the method emitter
1446     */
1447    MethodEmitter invoke(final Call call) {
1448        return call.invoke(this);
1449    }
1450
1451    private MethodEmitter invoke(final int opcode, final String className, final String methodName, final String methodDescriptor, final boolean hasReceiver) {
1452        final Type returnType = fixParamStack(methodDescriptor);
1453
1454        if (hasReceiver) {
1455            popType(Type.OBJECT);
1456        }
1457
1458        method.visitMethodInsn(opcode, className, methodName, methodDescriptor, opcode == INVOKEINTERFACE);
1459
1460        if (returnType != null) {
1461            pushType(returnType);
1462        }
1463
1464        return this;
1465    }
1466
1467    /**
1468     * Pop receiver from stack, perform an invoke special
1469     *
1470     * @param className        class name
1471     * @param methodName       method name
1472     * @param methodDescriptor descriptor
1473     *
1474     * @return the method emitter
1475     */
1476    MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
1477        debug("invokespecial", className, ".", methodName, methodDescriptor);
1478        return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
1479    }
1480
1481    /**
1482     * Pop receiver from stack, perform an invoke virtual, push return value if any
1483     *
1484     * @param className        class name
1485     * @param methodName       method name
1486     * @param methodDescriptor descriptor
1487     *
1488     * @return the method emitter
1489     */
1490    MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
1491        debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
1492        return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
1493    }
1494
1495    /**
1496     * Perform an invoke static and push the return value if any
1497     *
1498     * @param className        class name
1499     * @param methodName       method name
1500     * @param methodDescriptor descriptor
1501     *
1502     * @return the method emitter
1503     */
1504    MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
1505        debug("invokestatic", className, ".", methodName, methodDescriptor);
1506        invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
1507        return this;
1508    }
1509
1510    /**
1511     * Perform an invoke static and replace the return type if we know better, e.g. Global.allocate
1512     * that allocates an array should return an ObjectArray type as a NativeArray counts as that
1513     *
1514     * @param className        class name
1515     * @param methodName       method name
1516     * @param methodDescriptor descriptor
1517     * @param returnType       return type override
1518     *
1519     * @return the method emitter
1520     */
1521    MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor, final Type returnType) {
1522        invokestatic(className, methodName, methodDescriptor);
1523        popType();
1524        pushType(returnType);
1525        return this;
1526    }
1527
1528    /**
1529     * Pop receiver from stack, perform an invoke interface and push return value if any
1530     *
1531     * @param className        class name
1532     * @param methodName       method name
1533     * @param methodDescriptor descriptor
1534     *
1535     * @return the method emitter
1536     */
1537    MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
1538        debug("invokeinterface", className, ".", methodName, methodDescriptor);
1539        return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
1540    }
1541
1542    static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
1543        final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
1544        for (int i = 0; i < table.length; i++) {
1545            internalLabels[i] = table[i].getLabel();
1546        }
1547        return internalLabels;
1548    }
1549
1550    /**
1551     * Generate a lookup switch, popping the switch value from the stack
1552     *
1553     * @param defaultLabel default label
1554     * @param values       case values for the table
1555     * @param table        default label
1556     */
1557    void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
1558        debug("lookupswitch", peekType());
1559        adjustStackForSwitch(defaultLabel, table);
1560        method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
1561        doesNotContinueSequentially();
1562    }
1563
1564    /**
1565     * Generate a table switch
1566     * @param lo            low value
1567     * @param hi            high value
1568     * @param defaultLabel  default label
1569     * @param table         label table
1570     */
1571    void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
1572        debug("tableswitch", peekType());
1573        adjustStackForSwitch(defaultLabel, table);
1574        method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
1575        doesNotContinueSequentially();
1576    }
1577
1578    private void adjustStackForSwitch(final Label defaultLabel, final Label... table) {
1579        popType(Type.INT);
1580        joinTo(defaultLabel);
1581        for(final Label label: table) {
1582            joinTo(label);
1583        }
1584    }
1585
1586    /**
1587     * Abstraction for performing a conditional jump of any type
1588     *
1589     * @see MethodEmitter.Condition
1590     *
1591     * @param cond      the condition to test
1592     * @param trueLabel the destination label is condition is true
1593     */
1594    void conditionalJump(final Condition cond, final Label trueLabel) {
1595        conditionalJump(cond, cond != Condition.GT && cond != Condition.GE, trueLabel);
1596    }
1597
1598    /**
1599     * Abstraction for performing a conditional jump of any type,
1600     * including a dcmpg/dcmpl semantic for doubles.
1601     *
1602     * @param cond      the condition to test
1603     * @param isCmpG    is this a dcmpg for numbers, false if it's a dcmpl
1604     * @param trueLabel the destination label if condition is true
1605     */
1606    void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
1607        if (peekType().isCategory2()) {
1608            debug("[ld]cmp isCmpG=", isCmpG);
1609            pushType(get2n().cmp(method, isCmpG));
1610            jump(Condition.toUnary(cond), trueLabel, 1);
1611        } else {
1612            debug("if", cond);
1613            jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
1614        }
1615    }
1616
1617    MethodEmitter registerReturn() {
1618        setHasReturn();
1619        return this;
1620    }
1621
1622    void setHasReturn() {
1623        this.hasReturn = true;
1624    }
1625
1626    /**
1627     * Perform a non void return, popping the type from the stack
1628     *
1629     * @param type the type for the return
1630     */
1631    void _return(final Type type) {
1632        debug("return", type);
1633        assert stack.size() == 1 : "Only return value on stack allowed at return point - depth=" + stack.size() + " stack = " + stack;
1634        final Type stackType = peekType();
1635        if (!Type.areEquivalent(type, stackType)) {
1636            convert(type);
1637        }
1638        popType(type)._return(method);
1639        doesNotContinueSequentially();
1640    }
1641
1642    /**
1643     * Perform a return using the stack top value as the guide for the type
1644     */
1645    void _return() {
1646        _return(peekType());
1647    }
1648
1649    /**
1650     * Perform a void return.
1651     */
1652    void returnVoid() {
1653        debug("return [void]");
1654        assert stack.isEmpty() : stack;
1655        method.visitInsn(RETURN);
1656        doesNotContinueSequentially();
1657    }
1658
1659    /**
1660     * Goto, possibly when splitting is taking place. If
1661     * a splitNode exists, we need to handle the case that the
1662     * jump target is another method
1663     *
1664     * @param label destination label
1665     * @param targetNode the node to which the destination label belongs (the label is normally a break or continue
1666     * label)
1667     */
1668    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
1669        _goto(label);
1670    }
1671
1672    /**
1673     * Perform a comparison of two number types that are popped from the stack
1674     *
1675     * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
1676     *
1677     * @return the method emitter
1678     */
1679    MethodEmitter cmp(final boolean isCmpG) {
1680        pushType(get2n().cmp(method, isCmpG));
1681        return this;
1682    }
1683
1684    /**
1685     * Helper function for jumps, conditional or not
1686     * @param opcode  opcode for jump
1687     * @param label   destination
1688     * @param n       elements on stack to compare, 0-2
1689     */
1690    private void jump(final int opcode, final Label label, final int n) {
1691        for (int i = 0; i < n; i++) {
1692            assert peekType().isInteger() || peekType().isBoolean() || peekType().isObject() : "expecting integer type or object for jump, but found " + peekType();
1693            popType();
1694        }
1695        joinTo(label);
1696        method.visitJumpInsn(opcode, label.getLabel());
1697    }
1698
1699    /**
1700     * Generate an if_acmpeq
1701     *
1702     * @param label label to true case
1703     */
1704    void if_acmpeq(final Label label) {
1705        debug("if_acmpeq", label);
1706        jump(IF_ACMPEQ, label, 2);
1707    }
1708
1709    /**
1710     * Generate an if_acmpne
1711     *
1712     * @param label label to true case
1713     */
1714    void if_acmpne(final Label label) {
1715        debug("if_acmpne", label);
1716        jump(IF_ACMPNE, label, 2);
1717    }
1718
1719    /**
1720     * Generate an ifnull
1721     *
1722     * @param label label to true case
1723     */
1724    void ifnull(final Label label) {
1725        debug("ifnull", label);
1726        jump(IFNULL, label, 1);
1727    }
1728
1729    /**
1730     * Generate an ifnonnull
1731     *
1732     * @param label label to true case
1733     */
1734    void ifnonnull(final Label label) {
1735        debug("ifnonnull", label);
1736        jump(IFNONNULL, label, 1);
1737    }
1738
1739    /**
1740     * Generate an ifeq
1741     *
1742     * @param label label to true case
1743     */
1744    void ifeq(final Label label) {
1745        debug("ifeq ", label);
1746        jump(IFEQ, label, 1);
1747    }
1748
1749    /**
1750     * Generate an if_icmpeq
1751     *
1752     * @param label label to true case
1753     */
1754    void if_icmpeq(final Label label) {
1755        debug("if_icmpeq", label);
1756        jump(IF_ICMPEQ, label, 2);
1757    }
1758
1759    /**
1760     * Generate an if_ne
1761     *
1762     * @param label label to true case
1763     */
1764    void ifne(final Label label) {
1765        debug("ifne", label);
1766        jump(IFNE, label, 1);
1767    }
1768
1769    /**
1770     * Generate an if_icmpne
1771     *
1772     * @param label label to true case
1773     */
1774    void if_icmpne(final Label label) {
1775        debug("if_icmpne", label);
1776        jump(IF_ICMPNE, label, 2);
1777    }
1778
1779    /**
1780     * Generate an iflt
1781     *
1782     * @param label label to true case
1783     */
1784    void iflt(final Label label) {
1785        debug("iflt", label);
1786        jump(IFLT, label, 1);
1787    }
1788
1789    /**
1790     * Generate an if_icmplt
1791     *
1792     * @param label label to true case
1793     */
1794    void if_icmplt(final Label label) {
1795        debug("if_icmplt", label);
1796        jump(IF_ICMPLT, label, 2);
1797    }
1798
1799    /**
1800     * Generate an ifle
1801     *
1802     * @param label label to true case
1803     */
1804    void ifle(final Label label) {
1805        debug("ifle", label);
1806        jump(IFLE, label, 1);
1807    }
1808
1809    /**
1810     * Generate an if_icmple
1811     *
1812     * @param label label to true case
1813     */
1814    void if_icmple(final Label label) {
1815        debug("if_icmple", label);
1816        jump(IF_ICMPLE, label, 2);
1817    }
1818
1819    /**
1820     * Generate an ifgt
1821     *
1822     * @param label label to true case
1823     */
1824    void ifgt(final Label label) {
1825        debug("ifgt", label);
1826        jump(IFGT, label, 1);
1827    }
1828
1829    /**
1830     * Generate an if_icmpgt
1831     *
1832     * @param label label to true case
1833     */
1834    void if_icmpgt(final Label label) {
1835        debug("if_icmpgt", label);
1836        jump(IF_ICMPGT, label, 2);
1837    }
1838
1839    /**
1840     * Generate an ifge
1841     *
1842     * @param label label to true case
1843     */
1844    void ifge(final Label label) {
1845        debug("ifge", label);
1846        jump(IFGE, label, 1);
1847    }
1848
1849    /**
1850     * Generate an if_icmpge
1851     *
1852     * @param label label to true case
1853     */
1854    void if_icmpge(final Label label) {
1855        debug("if_icmpge", label);
1856        jump(IF_ICMPGE, label, 2);
1857    }
1858
1859    /**
1860     * Unconditional jump to a label
1861     *
1862     * @param label destination label
1863     */
1864    void _goto(final Label label) {
1865        debug("goto", label);
1866        jump(GOTO, label, 0);
1867        doesNotContinueSequentially(); //whoever reaches the point after us provides the stack, because we don't
1868    }
1869
1870    /**
1871     * Unconditional jump to the start label of a loop. It differs from ordinary {@link #_goto(Label)} in that it will
1872     * preserve the current label stack, as the next instruction after the goto is loop body that the loop will come
1873     * back to. Also used to jump at the start label of the continuation handler, as it behaves much like a loop test in
1874     * the sense that after it is evaluated, it also jumps backwards.
1875     *
1876     * @param loopStart start label of a loop
1877     */
1878    void gotoLoopStart(final Label loopStart) {
1879        debug("goto (loop)", loopStart);
1880        jump(GOTO, loopStart, 0);
1881    }
1882
1883    /**
1884     * Unconditional jump without any control flow and data flow testing. You should not normally use this method when
1885     * generating code, except if you're very sure that you know what you're doing. Normally only used for the
1886     * admittedly torturous control flow of continuation handler plumbing.
1887     * @param target the target of the jump
1888     */
1889    void uncheckedGoto(final Label target) {
1890        method.visitJumpInsn(GOTO, target.getLabel());
1891    }
1892
1893    /**
1894     * Potential transfer of control to a catch block.
1895     *
1896     * @param catchLabel destination catch label
1897     */
1898    void canThrow(final Label catchLabel) {
1899        catchLabel.joinFromTry(stack, false);
1900    }
1901
1902    /**
1903     * A join in control flow - helper function that makes sure all entry stacks
1904     * discovered for the join point so far are equivalent
1905     *
1906     * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
1907     * we have never been here before. Then we are expected to carry a stack with us.
1908     *
1909     * @param label label
1910     */
1911    private void joinTo(final Label label) {
1912        assert isReachable();
1913        label.joinFrom(stack);
1914    }
1915
1916    /**
1917     * Register a new label, enter it here.
1918     * @param label
1919     */
1920    void label(final Label label) {
1921        breakLabel(label, -1);
1922    }
1923
1924    /**
1925     * Register a new break target label, enter it here.
1926     *
1927     * @param label the label
1928     * @param liveLocals the number of live locals at this label
1929     */
1930    void breakLabel(final Label label, final int liveLocals) {
1931        if (!isReachable()) {
1932            // If we emit a label, and the label's stack is null, it must not be reachable.
1933            assert (label.getStack() == null) != label.isReachable();
1934        } else {
1935            joinTo(label);
1936        }
1937        // Use label's stack as we might have no stack.
1938        final Label.Stack labelStack = label.getStack();
1939        stack = labelStack == null ? null : labelStack.clone();
1940        if(stack != null && label.isBreakTarget() && liveLocals != -1) {
1941            // This has to be done because we might not have another frame to provide us with its firstTemp if the label
1942            // is only reachable through a break or continue statement; also in this case, the frame can actually
1943            // give us a higher number of live locals, e.g. if it comes from a catch. Typical example:
1944            // for(;;) { try{ throw 0; } catch(e) { break; } }.
1945            // Since the for loop can only be exited through the break in the catch block, it'll bring with it the
1946            // "e" as a live local, and we need to trim it off here.
1947            assert stack.firstTemp >= liveLocals;
1948            stack.firstTemp = liveLocals;
1949        }
1950        debug_label(label);
1951        method.visitLabel(label.getLabel());
1952    }
1953
1954    /**
1955     * Pop element from stack, convert to given type
1956     *
1957     * @param to type to convert to
1958     *
1959     * @return the method emitter
1960     */
1961    MethodEmitter convert(final Type to) {
1962        final Type from = peekType();
1963        final Type type = from.convert(method, to);
1964        if (type != null) {
1965            if (!from.isEquivalentTo(to)) {
1966                debug("convert", from, "->", to);
1967            }
1968            if (type != from) {
1969                final int l0 = stack.getTopLocalLoad();
1970                popType();
1971                pushType(type);
1972                // NOTE: conversions from a primitive type are considered to preserve the "load" property of the value
1973                // on the stack. Otherwise we could introduce temporary locals in a deoptimized rest-of (e.g. doing an
1974                // "i < x.length" where "i" is int and ".length" gets deoptimized to long would end up converting i to
1975                // long with "ILOAD i; I2L; LSTORE tmp; LLOAD tmp;"). Such additional temporary would cause an error
1976                // when restoring the state of the function for rest-of execution, as the not-yet deoptimized variant
1977                // would have the (now invalidated) assumption that "x.length" is an int, so it wouldn't have the I2L,
1978                // and therefore neither the subsequent LSTORE tmp; LLOAD tmp;. By making sure conversions from a
1979                // primitive type don't erase the "load" information, we don't introduce temporaries in the deoptimized
1980                // rest-of that didn't exist in the more optimistic version that triggered the deoptimization.
1981                // NOTE: as a more general observation, we could theoretically track the operations required to
1982                // reproduce any stack value as long as they are all local loads, constant loads, and stack operations.
1983                // We won't go there in the current system
1984                if(!from.isObject()) {
1985                    stack.markLocalLoad(l0);
1986                }
1987            }
1988        }
1989        return this;
1990    }
1991
1992    /**
1993     * Helper function - expect two types that are equivalent
1994     *
1995     * @return common type
1996     */
1997    private Type get2() {
1998        final Type p0 = popType();
1999        final Type p1 = popType();
2000        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
2001        return p0;
2002    }
2003
2004    /**
2005     * Helper function - expect two types that are integer types and equivalent
2006     *
2007     * @return common type
2008     */
2009    private BitwiseType get2i() {
2010        final BitwiseType p0 = popBitwise();
2011        final BitwiseType p1 = popBitwise();
2012        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
2013        return p0;
2014    }
2015
2016    /**
2017     * Helper function - expect two types that are numbers and equivalent
2018     *
2019     * @return common type
2020     */
2021    private NumericType get2n() {
2022        final NumericType p0 = popNumeric();
2023        final NumericType p1 = popNumeric();
2024        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
2025        return p0;
2026    }
2027
2028    /**
2029     * Pop two numbers, perform addition and push result
2030     *
2031     * @return the method emitter
2032     */
2033    MethodEmitter add(final int programPoint) {
2034        debug("add");
2035        pushType(get2().add(method, programPoint));
2036        return this;
2037    }
2038
2039    /**
2040     * Pop two numbers, perform subtraction and push result
2041     *
2042     * @return the method emitter
2043     */
2044    MethodEmitter sub(final int programPoint) {
2045        debug("sub");
2046        pushType(get2n().sub(method, programPoint));
2047        return this;
2048    }
2049
2050    /**
2051     * Pop two numbers, perform multiplication and push result
2052     *
2053     * @return the method emitter
2054     */
2055    MethodEmitter mul(final int programPoint) {
2056        debug("mul ");
2057        pushType(get2n().mul(method, programPoint));
2058        return this;
2059    }
2060
2061    /**
2062     * Pop two numbers, perform division and push result
2063     *
2064     * @return the method emitter
2065     */
2066    MethodEmitter div(final int programPoint) {
2067        debug("div");
2068        pushType(get2n().div(method, programPoint));
2069        return this;
2070    }
2071
2072    /**
2073     * Pop two numbers, calculate remainder and push result
2074     *
2075     * @return the method emitter
2076     */
2077    MethodEmitter rem(final int programPoint) {
2078        debug("rem");
2079        pushType(get2n().rem(method, programPoint));
2080        return this;
2081    }
2082
2083    /**
2084     * Retrieve the top <tt>count</tt> types on the stack without modifying it.
2085     *
2086     * @param count number of types to return
2087     * @return array of Types
2088     */
2089    protected Type[] getTypesFromStack(final int count) {
2090        return stack.getTopTypes(count);
2091    }
2092
2093    int[] getLocalLoadsOnStack(final int from, final int to) {
2094        return stack.getLocalLoads(from, to);
2095    }
2096
2097    int getStackSize() {
2098        return stack.size();
2099    }
2100
2101    int getFirstTemp() {
2102        return stack.firstTemp;
2103    }
2104
2105    int getUsedSlotsWithLiveTemporaries() {
2106        return stack.getUsedSlotsWithLiveTemporaries();
2107    }
2108
2109    /**
2110     * Helper function to generate a function signature based on stack contents
2111     * and argument count and return type
2112     *
2113     * @param returnType return type
2114     * @param argCount   argument count
2115     *
2116     * @return function signature for stack contents
2117     */
2118    private String getDynamicSignature(final Type returnType, final int argCount) {
2119        final Type[]         paramTypes = new Type[argCount];
2120
2121        int pos = 0;
2122        for (int i = argCount - 1; i >= 0; i--) {
2123            paramTypes[i] = stack.peek(pos++);
2124        }
2125        final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
2126        for (int i = 0; i < argCount; i++) {
2127            popType(paramTypes[argCount - i - 1]);
2128        }
2129
2130        return descriptor;
2131    }
2132
2133    MethodEmitter invalidateSpecialName(final String name) {
2134        //this is a nop if the global hasn't registered this as a special name - we can just ignore it
2135        if (Global.instance().isSpecialName(name)) {
2136            debug("dynamic_invalidate_name", "name=", name);
2137            method.visitInvokeDynamicInsn(name, "()V", INVALIDATE_NAME_BOOTSTRAP);
2138        }
2139        return this;
2140    }
2141
2142    /**
2143     * Generate a dynamic new
2144     *
2145     * @param argCount  number of arguments
2146     * @param flags     callsite flags
2147     *
2148     * @return the method emitter
2149     */
2150    MethodEmitter dynamicNew(final int argCount, final int flags) {
2151        assert !isOptimistic(flags);
2152        debug("dynamic_new", "argcount=", argCount);
2153        final String signature = getDynamicSignature(Type.OBJECT, argCount);
2154        method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
2155        pushType(Type.OBJECT); //TODO fix result type
2156        return this;
2157    }
2158
2159    /**
2160     * Generate a dynamic call
2161     *
2162     * @param returnType return type
2163     * @param argCount   number of arguments
2164     * @param flags      callsite flags
2165     *
2166     * @return the method emitter
2167     */
2168    MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
2169        debug("dynamic_call", "args=", argCount, "returnType=", returnType);
2170        final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
2171        debug("   signature", signature);
2172        method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
2173        pushType(returnType);
2174
2175        return this;
2176    }
2177
2178    MethodEmitter dynamicArrayPopulatorCall(final int argCount, final int startIndex) {
2179        debug("populate_array", "args=", argCount, "startIndex=", startIndex);
2180        final String signature = getDynamicSignature(Type.OBJECT_ARRAY, argCount);
2181        method.visitInvokeDynamicInsn("populateArray", signature, POPULATE_ARRAY_BOOTSTRAP, startIndex);
2182        pushType(Type.OBJECT_ARRAY);
2183        return this;
2184    }
2185
2186    /**
2187     * Generate a dynamic call for a runtime node
2188     *
2189     * @param name       tag for the invoke dynamic for this runtime node
2190     * @param returnType return type
2191     * @param request    RuntimeNode request
2192     *
2193     * @return the method emitter
2194     */
2195    MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
2196        debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
2197        final String signature = getDynamicSignature(returnType, request.getArity());
2198        debug("   signature", signature);
2199        method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
2200        pushType(returnType);
2201
2202        return this;
2203    }
2204
2205    /**
2206     * Generate dynamic getter. Pop scope from stack. Push result
2207     *
2208     * @param valueType type of the value to set
2209     * @param name      name of property
2210     * @param flags     call site flags
2211     * @param isMethod  should it prefer retrieving methods
2212     *
2213     * @return the method emitter
2214     */
2215    MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
2216        debug("dynamic_get", name, valueType, getProgramPoint(flags));
2217
2218        Type type = valueType;
2219        if (type.isObject() || type.isBoolean()) {
2220            type = Type.OBJECT; //promote e.g strings to object generic setter
2221        }
2222
2223        popType(Type.SCOPE);
2224        method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
2225                NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
2226
2227        pushType(type);
2228        convert(valueType); //most probably a nop
2229
2230        return this;
2231    }
2232
2233    /**
2234     * Generate dynamic setter. Pop receiver and property from stack.
2235     *
2236     * @param name  name of property
2237     * @param flags call site flags
2238     */
2239     void dynamicSet(final String name, final int flags) {
2240         assert !isOptimistic(flags);
2241         debug("dynamic_set", name, peekType());
2242
2243        Type type = peekType();
2244        if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
2245            type = Type.OBJECT;
2246            convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
2247        }
2248        popType(type);
2249        popType(Type.SCOPE);
2250
2251        method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
2252    }
2253
2254     /**
2255     * Dynamic getter for indexed structures. Pop index and receiver from stack,
2256     * generate appropriate signatures based on types
2257     *
2258     * @param result result type for getter
2259     * @param flags call site flags for getter
2260     * @param isMethod should it prefer retrieving methods
2261     *
2262     * @return the method emitter
2263     */
2264    MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
2265        assert result.getTypeClass().isPrimitive() || result.getTypeClass() == Object.class;
2266        debug("dynamic_get_index", peekType(1), "[", peekType(), "]", getProgramPoint(flags));
2267
2268        Type resultType = result;
2269        if (result.isBoolean()) {
2270            resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
2271        }
2272
2273        Type index = peekType();
2274        if (index.isObject() || index.isBoolean()) {
2275            index = Type.OBJECT; //e.g. string->object
2276            convert(Type.OBJECT);
2277        }
2278        popType();
2279
2280        popType(Type.OBJECT);
2281
2282        final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
2283
2284        method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod", signature, LINKERBOOTSTRAP, flags);
2285        pushType(resultType);
2286
2287        if (result.isBoolean()) {
2288            convert(Type.BOOLEAN);
2289        }
2290
2291        return this;
2292    }
2293
2294    private static String getProgramPoint(final int flags) {
2295        if((flags & CALLSITE_OPTIMISTIC) == 0) {
2296            return "";
2297        }
2298        return "pp=" + String.valueOf((flags & (-1 << CALLSITE_PROGRAM_POINT_SHIFT)) >> CALLSITE_PROGRAM_POINT_SHIFT);
2299    }
2300
2301    /**
2302     * Dynamic setter for indexed structures. Pop value, index and receiver from
2303     * stack, generate appropriate signature based on types
2304     *
2305     * @param flags call site flags for setter
2306     */
2307    void dynamicSetIndex(final int flags) {
2308        assert !isOptimistic(flags);
2309        debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
2310
2311        Type value = peekType();
2312        if (value.isObject() || value.isBoolean()) {
2313            value = Type.OBJECT; //e.g. STRING->OBJECT - one descriptor for all object types
2314            convert(Type.OBJECT);
2315        }
2316        popType();
2317
2318        Type index = peekType();
2319        if (index.isObject() || index.isBoolean()) {
2320            index = Type.OBJECT; //e.g. string->object
2321            convert(Type.OBJECT);
2322        }
2323        popType(index);
2324
2325        final Type receiver = popType(Type.OBJECT);
2326        assert receiver.isObject();
2327
2328        method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags);
2329    }
2330
2331    /**
2332     * Load a key value in the proper form.
2333     *
2334     * @param key
2335     */
2336    //TODO move this and break it apart
2337    MethodEmitter loadKey(final Object key) {
2338        if (key instanceof IdentNode) {
2339            method.visitLdcInsn(((IdentNode) key).getName());
2340        } else if (key instanceof LiteralNode) {
2341            method.visitLdcInsn(((LiteralNode<?>)key).getString());
2342        } else {
2343            method.visitLdcInsn(JSType.toString(key));
2344        }
2345        pushType(Type.OBJECT); //STRING
2346        return this;
2347    }
2348
2349     @SuppressWarnings("fallthrough")
2350     private static Type fieldType(final String desc) {
2351         switch (desc) {
2352         case "Z":
2353         case "B":
2354         case "C":
2355         case "S":
2356         case "I":
2357             return Type.INT;
2358         case "F":
2359             assert false;
2360         case "D":
2361             return Type.NUMBER;
2362         case "J":
2363             return Type.LONG;
2364         default:
2365             assert desc.startsWith("[") || desc.startsWith("L") : desc + " is not an object type";
2366             switch (desc.charAt(0)) {
2367             case 'L':
2368                 return Type.OBJECT;
2369             case '[':
2370                 return Type.typeFor(Array.newInstance(fieldType(desc.substring(1)).getTypeClass(), 0).getClass());
2371             default:
2372                 assert false;
2373             }
2374             return Type.OBJECT;
2375         }
2376     }
2377
2378     /**
2379      * Generate get for a field access
2380      *
2381      * @param fa the field access
2382      *
2383      * @return the method emitter
2384      */
2385    MethodEmitter getField(final FieldAccess fa) {
2386        return fa.get(this);
2387    }
2388
2389     /**
2390      * Generate set for a field access
2391      *
2392      * @param fa the field access
2393      */
2394    void putField(final FieldAccess fa) {
2395        fa.put(this);
2396    }
2397
2398    /**
2399     * Get the value of a non-static field, pop the receiver from the stack,
2400     * push value to the stack
2401     *
2402     * @param className        class
2403     * @param fieldName        field name
2404     * @param fieldDescriptor  field descriptor
2405     *
2406     * @return the method emitter
2407     */
2408    MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
2409        debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
2410        final Type receiver = popType();
2411        assert receiver.isObject();
2412        method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
2413        pushType(fieldType(fieldDescriptor));
2414        return this;
2415    }
2416
2417    /**
2418     * Get the value of a static field, push it to the stack
2419     *
2420     * @param className        class
2421     * @param fieldName        field name
2422     * @param fieldDescriptor  field descriptor
2423     *
2424     * @return the method emitter
2425     */
2426    MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
2427        debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
2428        method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
2429        pushType(fieldType(fieldDescriptor));
2430        return this;
2431    }
2432
2433    /**
2434     * Pop value and field from stack and write to a non-static field
2435     *
2436     * @param className       class
2437     * @param fieldName       field name
2438     * @param fieldDescriptor field descriptor
2439     */
2440    void putField(final String className, final String fieldName, final String fieldDescriptor) {
2441        debug("putfield", "receiver=", peekType(1), "value=", peekType());
2442        popType(fieldType(fieldDescriptor));
2443        popType(Type.OBJECT);
2444        method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
2445    }
2446
2447    /**
2448     * Pop value from stack and write to a static field
2449     *
2450     * @param className       class
2451     * @param fieldName       field name
2452     * @param fieldDescriptor field descriptor
2453     */
2454    void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
2455        debug("putfield", "value=", peekType());
2456        popType(fieldType(fieldDescriptor));
2457        method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
2458    }
2459
2460    /**
2461     * Register line number at a label
2462     *
2463     * @param line  line number
2464     */
2465    void lineNumber(final int line) {
2466        if (context.getEnv()._debug_lines) {
2467            debug_label("[LINE]", line);
2468            final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
2469            method.visitLabel(l);
2470            method.visitLineNumber(line, l);
2471        }
2472    }
2473
2474    void beforeJoinPoint(final JoinPredecessor joinPredecessor) {
2475        LocalVariableConversion next = joinPredecessor.getLocalVariableConversion();
2476        while(next != null) {
2477            final Symbol symbol = next.getSymbol();
2478            if(next.isLive()) {
2479                emitLocalVariableConversion(next, true);
2480            } else {
2481                markDeadLocalVariable(symbol);
2482            }
2483            next = next.getNext();
2484        }
2485    }
2486
2487    void beforeTry(final TryNode tryNode, final Label recovery) {
2488        LocalVariableConversion next = tryNode.getLocalVariableConversion();
2489        while(next != null) {
2490            if(next.isLive()) {
2491                final Type to = emitLocalVariableConversion(next, false);
2492                recovery.getStack().onLocalStore(to, next.getSymbol().getSlot(to), true);
2493            }
2494            next = next.getNext();
2495        }
2496    }
2497
2498    private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) {
2499        final Type from = conversion.getFrom();
2500        final Type to = conversion.getTo();
2501        final Symbol symbol = conversion.getSymbol();
2502        assert symbol.isBytecodeLocal();
2503        if(from == Type.UNDEFINED) {
2504            loadUndefined(to);
2505        } else {
2506            load(symbol, from).convert(to);
2507        }
2508        store(symbol, to, onlySymbolLiveValue);
2509        return to;
2510    }
2511
2512    /*
2513     * Debugging below
2514     */
2515
2516    private final FieldAccess ERR_STREAM       = staticField(System.class, "err", PrintStream.class);
2517    private final Call        PRINT            = virtualCallNoLookup(PrintStream.class, "print", void.class, Object.class);
2518    private final Call        PRINTLN          = virtualCallNoLookup(PrintStream.class, "println", void.class, Object.class);
2519    private final Call        PRINT_STACKTRACE = virtualCallNoLookup(Throwable.class, "printStackTrace", void.class);
2520
2521    /**
2522     * Emit a System.err.print statement of whatever is on top of the bytecode stack
2523     */
2524     void print() {
2525         getField(ERR_STREAM);
2526         swap();
2527         convert(Type.OBJECT);
2528         invoke(PRINT);
2529     }
2530
2531    /**
2532     * Emit a System.err.println statement of whatever is on top of the bytecode stack
2533     */
2534     void println() {
2535         getField(ERR_STREAM);
2536         swap();
2537         convert(Type.OBJECT);
2538         invoke(PRINTLN);
2539     }
2540
2541     /**
2542      * Emit a System.err.print statement
2543      * @param string string to print
2544      */
2545     void print(final String string) {
2546         getField(ERR_STREAM);
2547         load(string);
2548         invoke(PRINT);
2549     }
2550
2551     /**
2552      * Emit a System.err.println statement
2553      * @param string string to print
2554      */
2555     void println(final String string) {
2556         getField(ERR_STREAM);
2557         load(string);
2558         invoke(PRINTLN);
2559     }
2560
2561     /**
2562      * Print a stacktrace to S
2563      */
2564     void stacktrace() {
2565         _new(Throwable.class);
2566         dup();
2567         invoke(constructorNoLookup(Throwable.class));
2568         invoke(PRINT_STACKTRACE);
2569     }
2570
2571    private static int linePrefix = 0;
2572
2573    /**
2574     * Debug function that outputs generated bytecode and stack contents
2575     *
2576     * @param args debug information to print
2577     */
2578    private void debug(final Object... args) {
2579        if (debug) {
2580            debug(30, args);
2581        }
2582    }
2583
2584    /**
2585     * Debug function that outputs generated bytecode and stack contents
2586     * for a label - indentation is currently the only thing that differs
2587     *
2588     * @param args debug information to print
2589     */
2590    private void debug_label(final Object... args) {
2591        if (debug) {
2592            debug(22, args);
2593        }
2594    }
2595
2596    private void debug(final int padConstant, final Object... args) {
2597        if (debug) {
2598            final StringBuilder sb = new StringBuilder();
2599            int pad;
2600
2601            sb.append('#');
2602            sb.append(++linePrefix);
2603
2604            pad = 5 - sb.length();
2605            while (pad > 0) {
2606                sb.append(' ');
2607                pad--;
2608            }
2609
2610            if (isReachable() && !stack.isEmpty()) {
2611                sb.append("{");
2612                sb.append(stack.size());
2613                sb.append(":");
2614                for (int pos = 0; pos < stack.size(); pos++) {
2615                    final Type t = stack.peek(pos);
2616
2617                    if (t == Type.SCOPE) {
2618                        sb.append("scope");
2619                    } else if (t == Type.THIS) {
2620                        sb.append("this");
2621                    } else if (t.isObject()) {
2622                        String desc = t.getDescriptor();
2623                        int i;
2624                        for (i = 0; desc.charAt(i) == '[' && i < desc.length(); i++) {
2625                            sb.append('[');
2626                        }
2627                        desc = desc.substring(i);
2628                        final int slash = desc.lastIndexOf('/');
2629                        if (slash != -1) {
2630                            desc = desc.substring(slash + 1, desc.length() - 1);
2631                        }
2632                        if ("Object".equals(desc)) {
2633                            sb.append('O');
2634                        } else {
2635                            sb.append(desc);
2636                        }
2637                    } else {
2638                        sb.append(t.getDescriptor());
2639                    }
2640                    final int loadIndex = stack.localLoads[stack.sp - 1 - pos];
2641                    if(loadIndex != Label.Stack.NON_LOAD) {
2642                        sb.append('(').append(loadIndex).append(')');
2643                    }
2644                    if (pos + 1 < stack.size()) {
2645                        sb.append(' ');
2646                    }
2647                }
2648                sb.append('}');
2649                sb.append(' ');
2650            }
2651
2652            pad = padConstant - sb.length();
2653            while (pad > 0) {
2654                sb.append(' ');
2655                pad--;
2656            }
2657
2658            for (final Object arg : args) {
2659                sb.append(arg);
2660                sb.append(' ');
2661            }
2662
2663            if (context.getEnv() != null) { //early bootstrap code doesn't have inited context yet
2664                log.info(sb);
2665                if (DEBUG_TRACE_LINE == linePrefix) {
2666                    new Throwable().printStackTrace(log.getOutputStream());
2667                }
2668            }
2669        }
2670    }
2671
2672    /**
2673     * Set the current function node being emitted
2674     * @param functionNode the function node
2675     */
2676    void setFunctionNode(final FunctionNode functionNode) {
2677        this.functionNode = functionNode;
2678    }
2679
2680    boolean hasReturn() {
2681        return hasReturn;
2682    }
2683
2684    /**
2685     * Invoke to enforce assertions preventing load from a local variable slot that's known to not have been written to.
2686     * Used by CodeGenerator, as it strictly enforces tracking of stores. Simpler uses of MethodEmitter, e.g. those
2687     * for creating initializers for structure  classes, array getters, etc. don't have strict tracking of stores,
2688     * therefore they would fail if they had this assertion turned on.
2689     */
2690    void setPreventUndefinedLoad() {
2691        this.preventUndefinedLoad = true;
2692    }
2693
2694    private static boolean isOptimistic(final int flags) {
2695        return (flags & CALLSITE_OPTIMISTIC) != 0;
2696    }
2697}
2698