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