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