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