MethodEmitter.java revision 1729:331c52513f4f
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.H_INVOKEINTERFACE;
36import static jdk.internal.org.objectweb.asm.Opcodes.IFEQ;
37import static jdk.internal.org.objectweb.asm.Opcodes.IFGE;
38import static jdk.internal.org.objectweb.asm.Opcodes.IFGT;
39import static jdk.internal.org.objectweb.asm.Opcodes.IFLE;
40import static jdk.internal.org.objectweb.asm.Opcodes.IFLT;
41import static jdk.internal.org.objectweb.asm.Opcodes.IFNE;
42import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL;
43import static jdk.internal.org.objectweb.asm.Opcodes.IFNULL;
44import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ;
45import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE;
46import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ;
47import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE;
48import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGT;
49import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLE;
50import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT;
51import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE;
52import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF;
53import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
54import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
55import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
56import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
57import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
58import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
59import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
60import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
61import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
62import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
63import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
64import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
65import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
66import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
67import static jdk.nashorn.internal.codegen.CompilerConstants.className;
68import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
69import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
70import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
71import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
72import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
73import static jdk.nashorn.internal.runtime.linker.NameCodec.EMPTY_NAME;
74import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
75import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
76
77import java.io.PrintStream;
78import java.lang.reflect.Array;
79import java.util.Collection;
80import java.util.EnumSet;
81import java.util.IdentityHashMap;
82import java.util.List;
83import java.util.Map;
84import jdk.internal.org.objectweb.asm.Handle;
85import jdk.internal.org.objectweb.asm.MethodVisitor;
86import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
87import jdk.nashorn.internal.codegen.CompilerConstants.Call;
88import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
89import jdk.nashorn.internal.codegen.types.ArrayType;
90import jdk.nashorn.internal.codegen.types.BitwiseType;
91import jdk.nashorn.internal.codegen.types.NumericType;
92import jdk.nashorn.internal.codegen.types.Type;
93import jdk.nashorn.internal.ir.FunctionNode;
94import jdk.nashorn.internal.ir.IdentNode;
95import jdk.nashorn.internal.ir.JoinPredecessor;
96import jdk.nashorn.internal.ir.LiteralNode;
97import jdk.nashorn.internal.ir.LocalVariableConversion;
98import jdk.nashorn.internal.ir.Symbol;
99import jdk.nashorn.internal.ir.TryNode;
100import jdk.nashorn.internal.objects.NativeArray;
101import jdk.nashorn.internal.runtime.ArgumentSetter;
102import jdk.nashorn.internal.runtime.Context;
103import jdk.nashorn.internal.runtime.Debug;
104import jdk.nashorn.internal.runtime.JSType;
105import jdk.nashorn.internal.runtime.RewriteException;
106import jdk.nashorn.internal.runtime.Scope;
107import jdk.nashorn.internal.runtime.ScriptObject;
108import jdk.nashorn.internal.runtime.ScriptRuntime;
109import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
110import jdk.nashorn.internal.runtime.linker.Bootstrap;
111import jdk.nashorn.internal.runtime.linker.NameCodec;
112import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
113import jdk.nashorn.internal.runtime.logging.DebugLogger;
114import jdk.nashorn.internal.runtime.options.Options;
115
116/**
117 * This is the main function responsible for emitting method code
118 * in a class. It maintains a type stack and keeps track of control
119 * flow to make sure that the registered instructions don't violate
120 * byte code verification.
121 *
122 * Running Nashorn with -ea will assert as soon as a type stack
123 * becomes corrupt, for easier debugging
124 *
125 * Running Nashorn with -Dnashorn.codegen.debug=true will print
126 * all generated bytecode and labels to stderr, for easier debugging,
127 * including bytecode stack contents
128 */
129public class MethodEmitter {
130    /** The ASM MethodVisitor we are plugged into */
131    private final MethodVisitor method;
132
133    /** Parent classEmitter representing the class of this method */
134    private final ClassEmitter classEmitter;
135
136    /** FunctionNode representing this method, or null if none exists */
137    protected FunctionNode functionNode;
138
139    /** Current type stack for current evaluation */
140    private Label.Stack stack;
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(), false);
175
176    /** Bootstrap for array populators */
177    private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor(), false);
178
179    /**
180     * Constructor - internal use from ClassEmitter only
181     * @see ClassEmitter#method
182     *
183     * @param classEmitter the class emitter weaving the class this method is in
184     * @param method       a method visitor
185     */
186    MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method) {
187        this(classEmitter, method, null);
188    }
189
190    /**
191     * Constructor - internal use from ClassEmitter only
192     * @see ClassEmitter#method
193     *
194     * @param classEmitter the class emitter weaving the class this method is in
195     * @param method       a method visitor
196     * @param functionNode a function node representing this method
197     */
198    MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method, final FunctionNode functionNode) {
199        this.context      = classEmitter.getContext();
200        this.classEmitter = classEmitter;
201        this.method       = method;
202        this.functionNode = functionNode;
203        this.stack        = null;
204        this.log          = context.getLogger(CodeGenerator.class);
205        this.debug        = log.isEnabled();
206    }
207
208    /**
209     * Begin a method
210     */
211    public void begin() {
212        classEmitter.beginMethod(this);
213        newStack();
214        method.visitCode();
215    }
216
217    /**
218     * End a method
219     */
220    public void end() {
221        method.visitMaxs(0, 0);
222        method.visitEnd();
223
224        classEmitter.endMethod(this);
225    }
226
227    boolean isReachable() {
228        return stack != null;
229    }
230
231    private void doesNotContinueSequentially() {
232        stack = null;
233    }
234
235    private void newStack() {
236        stack = new Label.Stack();
237    }
238
239    @Override
240    public String toString() {
241        return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
242    }
243
244    /**
245     * Push a type to the existing stack
246     * @param type the type
247     */
248    void pushType(final Type type) {
249        if (type != null) {
250            stack.push(type);
251        }
252    }
253
254    /**
255     * Pop a type from the existing stack
256     *
257     * @param expected expected type - will assert if wrong
258     *
259     * @return the type that was retrieved
260     */
261    private Type popType(final Type expected) {
262        final Type type = popType();
263        assert type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
264        return type;
265    }
266
267    /**
268     * Pop a type from the existing stack, no matter what it is.
269     *
270     * @return the type
271     */
272    private Type popType() {
273        return stack.pop();
274    }
275
276    /**
277     * Pop a type from the existing stack, ensuring that it is numeric. Boolean type is popped as int type.
278     *
279     * @return the type
280     */
281    private NumericType popNumeric() {
282        final Type type = popType();
283        if(type.isBoolean()) {
284            // Booleans are treated as int for purposes of arithmetic operations
285            return Type.INT;
286        }
287        assert type.isNumeric();
288        return (NumericType)type;
289    }
290
291    /**
292     * Pop a type from the existing stack, ensuring that it is an integer type
293     * (integer or long). Boolean type is popped as int type.
294     *
295     * @return the type
296     */
297    private BitwiseType popBitwise() {
298        final Type type = popType();
299        if(type == Type.BOOLEAN) {
300            return Type.INT;
301        }
302        return (BitwiseType)type;
303    }
304
305    private BitwiseType popInteger() {
306        final Type type = popType();
307        if(type == Type.BOOLEAN) {
308            return Type.INT;
309        }
310        assert type == Type.INT;
311        return (BitwiseType)type;
312    }
313
314    /**
315     * Pop a type from the existing stack, ensuring that it is an array type,
316     * assert if not
317     *
318     * @return the type
319     */
320    private ArrayType popArray() {
321        final Type type = popType();
322        assert type.isArray() : type;
323        return (ArrayType)type;
324    }
325
326    /**
327     * Peek a given number of slots from the top of the stack and return the
328     * type in that slot
329     *
330     * @param pos the number of positions from the top, 0 is the top element
331     *
332     * @return the type at position "pos" on the stack
333     */
334    final Type peekType(final int pos) {
335        return stack.peek(pos);
336    }
337
338    /**
339     * Peek at the type at the top of the stack
340     *
341     * @return the type at the top of the stack
342     */
343    final Type peekType() {
344        return stack.peek();
345    }
346
347    /**
348     * Generate code a for instantiating a new object and push the
349     * object type on the stack
350     *
351     * @param classDescriptor class descriptor for the object type
352     * @param type the type of the new object
353     *
354     * @return the method emitter
355     */
356    MethodEmitter _new(final String classDescriptor, final Type type) {
357        debug("new", classDescriptor);
358        method.visitTypeInsn(NEW, classDescriptor);
359        pushType(type);
360        return this;
361    }
362
363    /**
364     * Generate code a for instantiating a new object and push the
365     * object type on the stack
366     *
367     * @param clazz class type to instatiate
368     *
369     * @return the method emitter
370     */
371    MethodEmitter _new(final Class<?> clazz) {
372        return _new(className(clazz), Type.typeFor(clazz));
373    }
374
375    /**
376     * Generate code to call the empty constructor for a class
377     *
378     * @param clazz class type to instatiate
379     *
380     * @return the method emitter
381     */
382    MethodEmitter newInstance(final Class<?> clazz) {
383        return invoke(constructorNoLookup(clazz));
384    }
385
386    /**
387     * Perform a dup, that is, duplicate the top element and
388     * push the duplicate down a given number of positions
389     * on the stack. This is totally type agnostic.
390     *
391     * @param depth the depth on which to put the copy
392     *
393     * @return the method emitter, or null if depth is illegal and
394     *  has no instruction equivalent.
395     */
396    MethodEmitter dup(final int depth) {
397        if (peekType().dup(method, depth) == null) {
398            return null;
399        }
400
401        debug("dup", depth);
402
403        switch (depth) {
404        case 0: {
405            final int l0 = stack.getTopLocalLoad();
406            pushType(peekType());
407            stack.markLocalLoad(l0);
408            break;
409        }
410        case 1: {
411            final int l0 = stack.getTopLocalLoad();
412            final Type p0 = popType();
413            final int l1 = stack.getTopLocalLoad();
414            final Type p1 = popType();
415            pushType(p0);
416            stack.markLocalLoad(l0);
417            pushType(p1);
418            stack.markLocalLoad(l1);
419            pushType(p0);
420            stack.markLocalLoad(l0);
421            break;
422        }
423        case 2: {
424            final int l0 = stack.getTopLocalLoad();
425            final Type p0 = popType();
426            final int l1 = stack.getTopLocalLoad();
427            final Type p1 = popType();
428            final int l2 = stack.getTopLocalLoad();
429            final Type p2 = popType();
430            pushType(p0);
431            stack.markLocalLoad(l0);
432            pushType(p2);
433            stack.markLocalLoad(l2);
434            pushType(p1);
435            stack.markLocalLoad(l1);
436            pushType(p0);
437            stack.markLocalLoad(l0);
438            break;
439        }
440        default:
441            assert false : "illegal dup depth = " + depth;
442            return null;
443        }
444
445        return this;
446    }
447
448    /**
449     * Perform a dup2, that is, duplicate the top element if it
450     * is a category 2 type, or two top elements if they are category
451     * 1 types, and push them on top of the stack
452     *
453     * @return the method emitter
454     */
455    MethodEmitter dup2() {
456        debug("dup2");
457
458        if (peekType().isCategory2()) {
459            final int l0 = stack.getTopLocalLoad();
460            pushType(peekType());
461            stack.markLocalLoad(l0);
462        } else {
463            final int l0 = stack.getTopLocalLoad();
464            final Type p0 = popType();
465            final int l1 = stack.getTopLocalLoad();
466            final Type p1 = popType();
467            pushType(p0);
468            stack.markLocalLoad(l0);
469            pushType(p1);
470            stack.markLocalLoad(l1);
471            pushType(p0);
472            stack.markLocalLoad(l0);
473            pushType(p1);
474            stack.markLocalLoad(l1);
475        }
476        method.visitInsn(DUP2);
477        return this;
478    }
479
480    /**
481     * Duplicate the top element on the stack and push it
482     *
483     * @return the method emitter
484     */
485    MethodEmitter dup() {
486        return dup(0);
487    }
488
489    /**
490     * Pop the top element of the stack and throw it away
491     *
492     * @return the method emitter
493     */
494    MethodEmitter pop() {
495        debug("pop", peekType());
496        popType().pop(method);
497        return this;
498    }
499
500    /**
501     * Pop the top element of the stack if category 2 type, or the two
502     * top elements of the stack if category 1 types
503     *
504     * @return the method emitter
505     */
506    MethodEmitter pop2() {
507        if (peekType().isCategory2()) {
508            popType();
509        } else {
510            get2n();
511        }
512        return this;
513    }
514
515    /**
516     * Swap the top two elements of the stack. This is totally
517     * type agnostic and works for all types
518     *
519     * @return the method emitter
520     */
521    MethodEmitter swap() {
522        debug("swap");
523
524        final int l0 = stack.getTopLocalLoad();
525        final Type p0 = popType();
526        final int l1 = stack.getTopLocalLoad();
527        final Type p1 = popType();
528        p0.swap(method, p1);
529
530        pushType(p0);
531        stack.markLocalLoad(l0);
532        pushType(p1);
533        stack.markLocalLoad(l1);
534        return this;
535    }
536
537    void pack() {
538        final Type type = peekType();
539        if (type.isInteger()) {
540            convert(PRIMITIVE_FIELD_TYPE);
541        } else if (type.isLong()) {
542            //nop
543        } else if (type.isNumber()) {
544            invokestatic("java/lang/Double", "doubleToRawLongBits", "(D)J");
545        } else {
546            assert false : type + " cannot be packed!";
547        }
548    }
549
550    /**
551     * Initializes a bytecode method parameter
552     * @param symbol the symbol for the parameter
553     * @param type the type of the parameter
554     * @param start the label for the start of the method
555     */
556    void initializeMethodParameter(final Symbol symbol, final Type type, final Label start) {
557        assert symbol.isBytecodeLocal();
558        localVariableDefs.put(symbol, new LocalVariableDef(start.getLabel(), type));
559    }
560
561    /**
562     * Create a new string builder, call the constructor and push the instance to the stack.
563     *
564     * @return the method emitter
565     */
566    MethodEmitter newStringBuilder() {
567        return invoke(constructorNoLookup(StringBuilder.class)).dup();
568    }
569
570    /**
571     * Pop a string and a StringBuilder from the top of the stack and call the append
572     * function of the StringBuilder, appending the string. Pushes the StringBuilder to
573     * the stack when finished.
574     *
575     * @return the method emitter
576     */
577    MethodEmitter stringBuilderAppend() {
578        convert(Type.STRING);
579        return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
580    }
581
582    /**
583     * Pops two integer types from the stack, performs a bitwise and and pushes
584     * the result
585     *
586     * @return the method emitter
587     */
588    MethodEmitter and() {
589        debug("and");
590        pushType(get2i().and(method));
591        return this;
592    }
593
594    /**
595     * Pops two integer types from the stack, performs a bitwise or and pushes
596     * the result
597     *
598     * @return the method emitter
599     */
600    MethodEmitter or() {
601        debug("or");
602        pushType(get2i().or(method));
603        return this;
604    }
605
606    /**
607     * Pops two integer types from the stack, performs a bitwise xor and pushes
608     * the result
609     *
610     * @return the method emitter
611     */
612    MethodEmitter xor() {
613        debug("xor");
614        pushType(get2i().xor(method));
615        return this;
616    }
617
618    /**
619     * Pops two integer types from the stack, performs a bitwise logic shift right and pushes
620     * the result. The shift count, the first element, must be INT.
621     *
622     * @return the method emitter
623     */
624    MethodEmitter shr() {
625        debug("shr");
626        popInteger();
627        pushType(popBitwise().shr(method));
628        return this;
629    }
630
631    /**
632     * Pops two integer types from the stack, performs a bitwise shift left and and pushes
633     * the result. The shift count, the first element, must be INT.
634     *
635     * @return the method emitter
636     */
637    MethodEmitter shl() {
638        debug("shl");
639        popInteger();
640        pushType(popBitwise().shl(method));
641        return this;
642    }
643
644    /**
645     * Pops two integer types from the stack, performs a bitwise arithmetic shift right and pushes
646     * the result. The shift count, the first element, must be INT.
647     *
648     * @return the method emitter
649     */
650    MethodEmitter sar() {
651        debug("sar");
652        popInteger();
653        pushType(popBitwise().sar(method));
654        return this;
655    }
656
657    /**
658     * Pops a numeric type from the stack, negates it and pushes the result
659     *
660     * @return the method emitter
661     */
662    MethodEmitter neg(final int programPoint) {
663        debug("neg");
664        pushType(popNumeric().neg(method, programPoint));
665        return this;
666    }
667
668    /**
669     * Add label for the start of a catch block and push the exception to the
670     * stack
671     *
672     * @param recovery label pointing to start of catch block
673     */
674    void _catch(final Label recovery) {
675        // While in JVM a catch block can be reached through normal control flow, our code generator never does this,
676        // so we might as well presume there's no stack on entry.
677        assert stack == null;
678        recovery.onCatch();
679        label(recovery);
680        beginCatchBlock();
681    }
682
683    /**
684     * Add any number of labels for the start of a catch block and push the exception to the
685     * stack
686     *
687     * @param recoveries labels pointing to start of catch block
688     */
689    void _catch(final Collection<Label> recoveries) {
690        assert stack == null;
691        for(final Label l: recoveries) {
692            label(l);
693        }
694        beginCatchBlock();
695    }
696
697    private void beginCatchBlock() {
698        // It can happen that the catch label wasn't marked as reachable. They are marked as reachable if there's an
699        // assignment in the try block, but it's possible that there was none.
700        if(!isReachable()) {
701            newStack();
702        }
703        pushType(Type.typeFor(Throwable.class));
704    }
705    /**
706     * Start a try/catch block.
707     *
708     * @param entry          start label for try
709     * @param exit           end label for try
710     * @param recovery       start label for catch
711     * @param typeDescriptor type descriptor for exception
712     * @param isOptimismHandler true if this is a hander for {@code UnwarrantedOptimismException}. Normally joining on a
713     * catch handler kills temporary variables, but optimism handlers are an exception, as they need to capture
714     * temporaries as well, so they must remain live.
715     */
716    private void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor, final boolean isOptimismHandler) {
717        recovery.joinFromTry(entry.getStack(), isOptimismHandler);
718        method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
719    }
720
721    /**
722     * Start a try/catch block.
723     *
724     * @param entry    start label for try
725     * @param exit     end label for try
726     * @param recovery start label for catch
727     * @param clazz    exception class
728     */
729    void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
730        _try(entry, exit, recovery, CompilerConstants.className(clazz), clazz == UnwarrantedOptimismException.class);
731    }
732
733    /**
734     * Start a try/catch block. The catch is "Throwable" - i.e. catch-all
735     *
736     * @param entry    start label for try
737     * @param exit     end label for try
738     * @param recovery start label for catch
739     */
740    void _try(final Label entry, final Label exit, final Label recovery) {
741        _try(entry, exit, recovery, null, false);
742    }
743
744    void markLabelAsOptimisticCatchHandler(final Label label, final int liveLocalCount) {
745        label.markAsOptimisticCatchHandler(stack, liveLocalCount);
746    }
747
748    /**
749     * Load the constants array
750     * @return this method emitter
751     */
752    MethodEmitter loadConstants() {
753        getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
754        assert peekType().isArray() : peekType();
755        return this;
756    }
757
758    /**
759     * Push the undefined value for the given type, i.e.
760     * UNDEFINED or UNDEFINEDNUMBER. Currently we have no way of
761     * representing UNDEFINED for INTs and LONGs, so they are not
762     * allowed to be local variables (yet)
763     *
764     * @param type the type for which to push UNDEFINED
765     * @return the method emitter
766     */
767    MethodEmitter loadUndefined(final Type type) {
768        debug("load undefined ", type);
769        pushType(type.loadUndefined(method));
770        return this;
771    }
772
773    MethodEmitter loadForcedInitializer(final Type type) {
774        debug("load forced initializer ", type);
775        pushType(type.loadForcedInitializer(method));
776        return this;
777    }
778
779    /**
780     * Push the empty value for the given type, i.e. EMPTY.
781     *
782     * @param type the type
783     * @return the method emitter
784     */
785    MethodEmitter loadEmpty(final Type type) {
786        debug("load empty ", type);
787        pushType(type.loadEmpty(method));
788        return this;
789    }
790
791    /**
792     * Push null to stack
793     *
794     * @return the method emitter
795     */
796    MethodEmitter loadNull() {
797        debug("aconst_null");
798        pushType(Type.OBJECT.ldc(method, null));
799        return this;
800    }
801
802    /**
803     * Push a handle representing this class top stack
804     *
805     * @param className name of the class
806     *
807     * @return the method emitter
808     */
809    MethodEmitter loadType(final String className) {
810        debug("load type", className);
811        method.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(className));
812        pushType(Type.OBJECT);
813        return this;
814    }
815
816    /**
817     * Push a boolean constant to the stack.
818     *
819     * @param b value of boolean
820     *
821     * @return the method emitter
822     */
823    MethodEmitter load(final boolean b) {
824        debug("load boolean", b);
825        pushType(Type.BOOLEAN.ldc(method, b));
826        return this;
827    }
828
829    /**
830     * Push an int constant to the stack
831     *
832     * @param i value of the int
833     *
834     * @return the method emitter
835     */
836    MethodEmitter load(final int i) {
837        debug("load int", i);
838        pushType(Type.INT.ldc(method, i));
839        return this;
840    }
841
842    /**
843     * Push a double constant to the stack
844     *
845     * @param d value of the double
846     *
847     * @return the method emitter
848     */
849    MethodEmitter load(final double d) {
850        debug("load double", d);
851        pushType(Type.NUMBER.ldc(method, d));
852        return this;
853    }
854
855    /**
856     * Push an long constant to the stack
857     *
858     * @param l value of the long
859     *
860     * @return the method emitter
861     */
862    MethodEmitter load(final long l) {
863        debug("load long", l);
864        pushType(Type.LONG.ldc(method, l));
865        return this;
866    }
867
868    /**
869     * Fetch the length of an array.
870     * @return Array length.
871     */
872    MethodEmitter arraylength() {
873        debug("arraylength");
874        popType(Type.OBJECT);
875        pushType(Type.OBJECT_ARRAY.arraylength(method));
876        return this;
877    }
878
879    /**
880     * Push a String constant to the stack
881     *
882     * @param s value of the String
883     *
884     * @return the method emitter
885     */
886    MethodEmitter load(final String s) {
887        debug("load string", s);
888
889        if (s == null) {
890            loadNull();
891            return this;
892        }
893
894        //NASHORN-142 - split too large string
895        final int length = s.length();
896        if (length > LARGE_STRING_THRESHOLD) {
897
898            _new(StringBuilder.class);
899            dup();
900            load(length);
901            invoke(constructorNoLookup(StringBuilder.class, int.class));
902
903            for (int n = 0; n < length; n += LARGE_STRING_THRESHOLD) {
904                final String part = s.substring(n, Math.min(n + LARGE_STRING_THRESHOLD, length));
905                load(part);
906                stringBuilderAppend();
907            }
908
909            invoke(virtualCallNoLookup(StringBuilder.class, "toString", String.class));
910
911            return this;
912        }
913
914        pushType(Type.OBJECT.ldc(method, s));
915        return this;
916    }
917
918    /**
919     * Pushes the value of an identifier to the stack. If the identifier does not represent a local variable or a
920     * parameter, this will be a no-op.
921     *
922     * @param ident the identifier for the variable being loaded.
923     *
924     * @return the method emitter
925     */
926    MethodEmitter load(final IdentNode ident) {
927        return load(ident.getSymbol(), ident.getType());
928    }
929
930    /**
931     * Pushes the value of the symbol to the stack with the specified type. No type conversion is being performed, and
932     * the type is only being used if the symbol addresses a local variable slot. The value of the symbol is loaded if
933     * it addresses a local variable slot, or it is a parameter (in which case it can also be loaded from a vararg array
934     * or the arguments object). If it is neither, the operation is a no-op.
935     *
936     * @param symbol the symbol addressing the value being loaded
937     * @param type the presumed type of the value when it is loaded from a local variable slot
938     * @return the method emitter
939     */
940    MethodEmitter load(final Symbol symbol, final Type type) {
941        assert symbol != null;
942        if (symbol.hasSlot()) {
943            final int slot = symbol.getSlot(type);
944            debug("load symbol", symbol.getName(), " slot=", slot, "type=", type);
945            load(type, slot);
946           // _try(new Label("dummy"), new Label("dummy2"), recovery);
947           // method.visitTryCatchBlock(new Label(), arg1, arg2, arg3);
948        } else if (symbol.isParam()) {
949            assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
950            final int index = symbol.getFieldIndex();
951            if (functionNode.needsArguments()) {
952                // ScriptObject.getArgument(int) on arguments
953                debug("load symbol", symbol.getName(), " arguments index=", index);
954                loadCompilerConstant(ARGUMENTS);
955                load(index);
956                ScriptObject.GET_ARGUMENT.invoke(this);
957            } else {
958                // array load from __varargs__
959                debug("load symbol", symbol.getName(), " array index=", index);
960                loadCompilerConstant(VARARGS);
961                load(symbol.getFieldIndex());
962                arrayload();
963            }
964        }
965        return this;
966    }
967
968    /**
969     * Push a local variable to the stack, given an explicit bytecode slot.
970     * This is used e.g. for stub generation where we know where items like
971     * "this" and "scope" reside.
972     *
973     * @param type  the type of the variable
974     * @param slot  the slot the variable is in
975     *
976     * @return the method emitter
977     */
978    MethodEmitter load(final Type type, final int slot) {
979        debug("explicit load", type, slot);
980        final Type loadType = type.load(method, slot);
981        assert loadType != null;
982        pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType);
983        assert !preventUndefinedLoad || (slot < stack.localVariableTypes.size() && stack.localVariableTypes.get(slot) != Type.UNKNOWN)
984            : "Attempted load of uninitialized slot " + slot + " (as type " + type + ")";
985        stack.markLocalLoad(slot);
986        return this;
987    }
988
989    private boolean isThisSlot(final int slot) {
990        if (functionNode == null) {
991            return slot == CompilerConstants.JAVA_THIS.slot();
992        }
993        final int thisSlot = getCompilerConstantSymbol(THIS).getSlot(Type.OBJECT);
994        assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
995        assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
996        return slot == thisSlot;
997    }
998
999    /**
1000     * Push a method handle to the stack
1001     *
1002     * @param className  class name
1003     * @param methodName method name
1004     * @param descName   descriptor
1005     * @param flags      flags that describe this handle, e.g. invokespecial new, or invoke virtual
1006     *
1007     * @return the method emitter
1008     */
1009    MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet<Flag> flags) {
1010        final int flag = Flag.getValue(flags);
1011        debug("load handle ");
1012        pushType(Type.OBJECT.ldc(method, new Handle(flag, className, methodName, descName, flag == H_INVOKEINTERFACE)));
1013        return this;
1014    }
1015
1016    private Symbol getCompilerConstantSymbol(final CompilerConstants cc) {
1017        return functionNode.getBody().getExistingSymbol(cc.symbolName());
1018    }
1019
1020    /**
1021     * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
1022     * the scope).
1023     * @return if this method has a slot allocated for the scope variable.
1024     */
1025    boolean hasScope() {
1026        return getCompilerConstantSymbol(SCOPE).hasSlot();
1027    }
1028
1029    MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
1030        return loadCompilerConstant(cc, null);
1031    }
1032
1033    MethodEmitter loadCompilerConstant(final CompilerConstants cc, final Type type) {
1034        if (cc == SCOPE && peekType() == Type.SCOPE) {
1035            dup();
1036            return this;
1037        }
1038        return load(getCompilerConstantSymbol(cc), type != null ? type : getCompilerConstantType(cc));
1039    }
1040
1041    MethodEmitter loadScope() {
1042        return loadCompilerConstant(SCOPE).checkcast(Scope.class);
1043    }
1044
1045    MethodEmitter setSplitState(final int state) {
1046        return loadScope().load(state).invoke(Scope.SET_SPLIT_STATE);
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 bookkeeping 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 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    /**
1614     * Perform a non void return, popping the type from the stack
1615     *
1616     * @param type the type for the return
1617     */
1618    void _return(final Type type) {
1619        debug("return", type);
1620        assert stack.size() == 1 : "Only return value on stack allowed at return point - depth=" + stack.size() + " stack = " + stack;
1621        final Type stackType = peekType();
1622        if (!Type.areEquivalent(type, stackType)) {
1623            convert(type);
1624        }
1625        popType(type)._return(method);
1626        doesNotContinueSequentially();
1627    }
1628
1629    /**
1630     * Perform a return using the stack top value as the guide for the type
1631     */
1632    void _return() {
1633        _return(peekType());
1634    }
1635
1636    /**
1637     * Perform a void return.
1638     */
1639    void returnVoid() {
1640        debug("return [void]");
1641        assert stack.isEmpty() : stack;
1642        method.visitInsn(RETURN);
1643        doesNotContinueSequentially();
1644    }
1645
1646    /**
1647     * Perform a comparison of two number types that are popped from the stack
1648     *
1649     * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
1650     *
1651     * @return the method emitter
1652     */
1653    MethodEmitter cmp(final boolean isCmpG) {
1654        pushType(get2n().cmp(method, isCmpG));
1655        return this;
1656    }
1657
1658    /**
1659     * Helper function for jumps, conditional or not
1660     * @param opcode  opcode for jump
1661     * @param label   destination
1662     * @param n       elements on stack to compare, 0-2
1663     */
1664    private void jump(final int opcode, final Label label, final int n) {
1665        for (int i = 0; i < n; i++) {
1666            assert peekType().isInteger() || peekType().isBoolean() || peekType().isObject() : "expecting integer type or object for jump, but found " + peekType();
1667            popType();
1668        }
1669        joinTo(label);
1670        method.visitJumpInsn(opcode, label.getLabel());
1671    }
1672
1673    /**
1674     * Generate an if_acmpeq
1675     *
1676     * @param label label to true case
1677     */
1678    void if_acmpeq(final Label label) {
1679        debug("if_acmpeq", label);
1680        jump(IF_ACMPEQ, label, 2);
1681    }
1682
1683    /**
1684     * Generate an if_acmpne
1685     *
1686     * @param label label to true case
1687     */
1688    void if_acmpne(final Label label) {
1689        debug("if_acmpne", label);
1690        jump(IF_ACMPNE, label, 2);
1691    }
1692
1693    /**
1694     * Generate an ifnull
1695     *
1696     * @param label label to true case
1697     */
1698    void ifnull(final Label label) {
1699        debug("ifnull", label);
1700        jump(IFNULL, label, 1);
1701    }
1702
1703    /**
1704     * Generate an ifnonnull
1705     *
1706     * @param label label to true case
1707     */
1708    void ifnonnull(final Label label) {
1709        debug("ifnonnull", label);
1710        jump(IFNONNULL, label, 1);
1711    }
1712
1713    /**
1714     * Generate an ifeq
1715     *
1716     * @param label label to true case
1717     */
1718    void ifeq(final Label label) {
1719        debug("ifeq ", label);
1720        jump(IFEQ, label, 1);
1721    }
1722
1723    /**
1724     * Generate an if_icmpeq
1725     *
1726     * @param label label to true case
1727     */
1728    void if_icmpeq(final Label label) {
1729        debug("if_icmpeq", label);
1730        jump(IF_ICMPEQ, label, 2);
1731    }
1732
1733    /**
1734     * Generate an if_ne
1735     *
1736     * @param label label to true case
1737     */
1738    void ifne(final Label label) {
1739        debug("ifne", label);
1740        jump(IFNE, label, 1);
1741    }
1742
1743    /**
1744     * Generate an if_icmpne
1745     *
1746     * @param label label to true case
1747     */
1748    void if_icmpne(final Label label) {
1749        debug("if_icmpne", label);
1750        jump(IF_ICMPNE, label, 2);
1751    }
1752
1753    /**
1754     * Generate an iflt
1755     *
1756     * @param label label to true case
1757     */
1758    void iflt(final Label label) {
1759        debug("iflt", label);
1760        jump(IFLT, label, 1);
1761    }
1762
1763    /**
1764     * Generate an if_icmplt
1765     *
1766     * @param label label to true case
1767     */
1768    void if_icmplt(final Label label) {
1769        debug("if_icmplt", label);
1770        jump(IF_ICMPLT, label, 2);
1771    }
1772
1773    /**
1774     * Generate an ifle
1775     *
1776     * @param label label to true case
1777     */
1778    void ifle(final Label label) {
1779        debug("ifle", label);
1780        jump(IFLE, label, 1);
1781    }
1782
1783    /**
1784     * Generate an if_icmple
1785     *
1786     * @param label label to true case
1787     */
1788    void if_icmple(final Label label) {
1789        debug("if_icmple", label);
1790        jump(IF_ICMPLE, label, 2);
1791    }
1792
1793    /**
1794     * Generate an ifgt
1795     *
1796     * @param label label to true case
1797     */
1798    void ifgt(final Label label) {
1799        debug("ifgt", label);
1800        jump(IFGT, label, 1);
1801    }
1802
1803    /**
1804     * Generate an if_icmpgt
1805     *
1806     * @param label label to true case
1807     */
1808    void if_icmpgt(final Label label) {
1809        debug("if_icmpgt", label);
1810        jump(IF_ICMPGT, label, 2);
1811    }
1812
1813    /**
1814     * Generate an ifge
1815     *
1816     * @param label label to true case
1817     */
1818    void ifge(final Label label) {
1819        debug("ifge", label);
1820        jump(IFGE, label, 1);
1821    }
1822
1823    /**
1824     * Generate an if_icmpge
1825     *
1826     * @param label label to true case
1827     */
1828    void if_icmpge(final Label label) {
1829        debug("if_icmpge", label);
1830        jump(IF_ICMPGE, label, 2);
1831    }
1832
1833    /**
1834     * Unconditional jump to a label
1835     *
1836     * @param label destination label
1837     */
1838    void _goto(final Label label) {
1839        debug("goto", label);
1840        jump(GOTO, label, 0);
1841        doesNotContinueSequentially(); //whoever reaches the point after us provides the stack, because we don't
1842    }
1843
1844    /**
1845     * Unconditional jump to the start label of a loop. It differs from ordinary {@link #_goto(Label)} in that it will
1846     * preserve the current label stack, as the next instruction after the goto is loop body that the loop will come
1847     * back to. Also used to jump at the start label of the continuation handler, as it behaves much like a loop test in
1848     * the sense that after it is evaluated, it also jumps backwards.
1849     *
1850     * @param loopStart start label of a loop
1851     */
1852    void gotoLoopStart(final Label loopStart) {
1853        debug("goto (loop)", loopStart);
1854        jump(GOTO, loopStart, 0);
1855    }
1856
1857    /**
1858     * Unconditional jump without any control flow and data flow testing. You should not normally use this method when
1859     * generating code, except if you're very sure that you know what you're doing. Normally only used for the
1860     * admittedly torturous control flow of continuation handler plumbing.
1861     * @param target the target of the jump
1862     */
1863    void uncheckedGoto(final Label target) {
1864        method.visitJumpInsn(GOTO, target.getLabel());
1865    }
1866
1867    /**
1868     * Potential transfer of control to a catch block.
1869     *
1870     * @param catchLabel destination catch label
1871     */
1872    void canThrow(final Label catchLabel) {
1873        catchLabel.joinFromTry(stack, false);
1874    }
1875
1876    /**
1877     * A join in control flow - helper function that makes sure all entry stacks
1878     * discovered for the join point so far are equivalent
1879     *
1880     * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
1881     * we have never been here before. Then we are expected to carry a stack with us.
1882     *
1883     * @param label label
1884     */
1885    private void joinTo(final Label label) {
1886        assert isReachable();
1887        label.joinFrom(stack);
1888    }
1889
1890    /**
1891     * Register a new label, enter it here.
1892     * @param label
1893     */
1894    void label(final Label label) {
1895        breakLabel(label, -1);
1896    }
1897
1898    /**
1899     * Register a new break target label, enter it here.
1900     *
1901     * @param label the label
1902     * @param liveLocals the number of live locals at this label
1903     */
1904    void breakLabel(final Label label, final int liveLocals) {
1905        if (!isReachable()) {
1906            // If we emit a label, and the label's stack is null, it must not be reachable.
1907            assert (label.getStack() == null) != label.isReachable();
1908        } else {
1909            joinTo(label);
1910        }
1911        // Use label's stack as we might have no stack.
1912        final Label.Stack labelStack = label.getStack();
1913        stack = labelStack == null ? null : labelStack.clone();
1914        if(stack != null && label.isBreakTarget() && liveLocals != -1) {
1915            // This has to be done because we might not have another frame to provide us with its firstTemp if the label
1916            // is only reachable through a break or continue statement; also in this case, the frame can actually
1917            // give us a higher number of live locals, e.g. if it comes from a catch. Typical example:
1918            // for(;;) { try{ throw 0; } catch(e) { break; } }.
1919            // Since the for loop can only be exited through the break in the catch block, it'll bring with it the
1920            // "e" as a live local, and we need to trim it off here.
1921            assert stack.firstTemp >= liveLocals;
1922            stack.firstTemp = liveLocals;
1923        }
1924        debug_label(label);
1925        method.visitLabel(label.getLabel());
1926    }
1927
1928    /**
1929     * Pop element from stack, convert to given type
1930     *
1931     * @param to type to convert to
1932     *
1933     * @return the method emitter
1934     */
1935    MethodEmitter convert(final Type to) {
1936        final Type from = peekType();
1937        final Type type = from.convert(method, to);
1938        if (type != null) {
1939            if (!from.isEquivalentTo(to)) {
1940                debug("convert", from, "->", to);
1941            }
1942            if (type != from) {
1943                final int l0 = stack.getTopLocalLoad();
1944                popType();
1945                pushType(type);
1946                // NOTE: conversions from a primitive type are considered to preserve the "load" property of the value
1947                // on the stack. Otherwise we could introduce temporary locals in a deoptimized rest-of (e.g. doing an
1948                // "i < x.length" where "i" is int and ".length" gets deoptimized to long would end up converting i to
1949                // long with "ILOAD i; I2L; LSTORE tmp; LLOAD tmp;"). Such additional temporary would cause an error
1950                // when restoring the state of the function for rest-of execution, as the not-yet deoptimized variant
1951                // would have the (now invalidated) assumption that "x.length" is an int, so it wouldn't have the I2L,
1952                // and therefore neither the subsequent LSTORE tmp; LLOAD tmp;. By making sure conversions from a
1953                // primitive type don't erase the "load" information, we don't introduce temporaries in the deoptimized
1954                // rest-of that didn't exist in the more optimistic version that triggered the deoptimization.
1955                // NOTE: as a more general observation, we could theoretically track the operations required to
1956                // reproduce any stack value as long as they are all local loads, constant loads, and stack operations.
1957                // We won't go there in the current system
1958                if(!from.isObject()) {
1959                    stack.markLocalLoad(l0);
1960                }
1961            }
1962        }
1963        return this;
1964    }
1965
1966    /**
1967     * Helper function - expect two types that are equivalent
1968     *
1969     * @return common type
1970     */
1971    private Type get2() {
1972        final Type p0 = popType();
1973        final Type p1 = popType();
1974        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1975        return p0;
1976    }
1977
1978    /**
1979     * Helper function - expect two types that are integer types and equivalent
1980     *
1981     * @return common type
1982     */
1983    private BitwiseType get2i() {
1984        final BitwiseType p0 = popBitwise();
1985        final BitwiseType p1 = popBitwise();
1986        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1987        return p0;
1988    }
1989
1990    /**
1991     * Helper function - expect two types that are numbers and equivalent
1992     *
1993     * @return common type
1994     */
1995    private NumericType get2n() {
1996        final NumericType p0 = popNumeric();
1997        final NumericType p1 = popNumeric();
1998        assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1999        return p0;
2000    }
2001
2002    /**
2003     * Pop two numbers, perform addition and push result
2004     *
2005     * @return the method emitter
2006     */
2007    MethodEmitter add(final int programPoint) {
2008        debug("add");
2009        pushType(get2().add(method, programPoint));
2010        return this;
2011    }
2012
2013    /**
2014     * Pop two numbers, perform subtraction and push result
2015     *
2016     * @return the method emitter
2017     */
2018    MethodEmitter sub(final int programPoint) {
2019        debug("sub");
2020        pushType(get2n().sub(method, programPoint));
2021        return this;
2022    }
2023
2024    /**
2025     * Pop two numbers, perform multiplication and push result
2026     *
2027     * @return the method emitter
2028     */
2029    MethodEmitter mul(final int programPoint) {
2030        debug("mul ");
2031        pushType(get2n().mul(method, programPoint));
2032        return this;
2033    }
2034
2035    /**
2036     * Pop two numbers, perform division and push result
2037     *
2038     * @return the method emitter
2039     */
2040    MethodEmitter div(final int programPoint) {
2041        debug("div");
2042        pushType(get2n().div(method, programPoint));
2043        return this;
2044    }
2045
2046    /**
2047     * Pop two numbers, calculate remainder and push result
2048     *
2049     * @return the method emitter
2050     */
2051    MethodEmitter rem(final int programPoint) {
2052        debug("rem");
2053        pushType(get2n().rem(method, programPoint));
2054        return this;
2055    }
2056
2057    /**
2058     * Retrieve the top <tt>count</tt> types on the stack without modifying it.
2059     *
2060     * @param count number of types to return
2061     * @return array of Types
2062     */
2063    protected Type[] getTypesFromStack(final int count) {
2064        return stack.getTopTypes(count);
2065    }
2066
2067    int[] getLocalLoadsOnStack(final int from, final int to) {
2068        return stack.getLocalLoads(from, to);
2069    }
2070
2071    int getStackSize() {
2072        return stack.size();
2073    }
2074
2075    int getFirstTemp() {
2076        return stack.firstTemp;
2077    }
2078
2079    int getUsedSlotsWithLiveTemporaries() {
2080        return stack.getUsedSlotsWithLiveTemporaries();
2081    }
2082
2083    /**
2084     * Helper function to generate a function signature based on stack contents
2085     * and argument count and return type
2086     *
2087     * @param returnType return type
2088     * @param argCount   argument count
2089     *
2090     * @return function signature for stack contents
2091     */
2092    private String getDynamicSignature(final Type returnType, final int argCount) {
2093        final Type[]         paramTypes = new Type[argCount];
2094
2095        int pos = 0;
2096        for (int i = argCount - 1; i >= 0; i--) {
2097            Type pt = stack.peek(pos++);
2098            // "erase" specific ScriptObject subtype info - except for NativeArray.
2099            // NativeArray is used for array/List/Deque conversion for Java calls.
2100            if (ScriptObject.class.isAssignableFrom(pt.getTypeClass()) &&
2101                !NativeArray.class.isAssignableFrom(pt.getTypeClass())) {
2102                pt = Type.SCRIPT_OBJECT;
2103            }
2104            paramTypes[i] = pt;
2105        }
2106        final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
2107        for (int i = 0; i < argCount; i++) {
2108            popType(paramTypes[argCount - i - 1]);
2109        }
2110
2111        return descriptor;
2112    }
2113
2114    MethodEmitter invalidateSpecialName(final String name) {
2115        switch (name) {
2116        case "apply":
2117        case "call":
2118            debug("invalidate_name", "name=", name);
2119            load("Function");
2120            invoke(ScriptRuntime.INVALIDATE_RESERVED_BUILTIN_NAME);
2121            break;
2122        default:
2123            break;
2124        }
2125        return this;
2126    }
2127
2128    /**
2129     * Generate a dynamic new
2130     *
2131     * @param argCount  number of arguments
2132     * @param flags     callsite flags
2133     *
2134     * @return the method emitter
2135     */
2136    MethodEmitter dynamicNew(final int argCount, final int flags) {
2137        return dynamicNew(argCount, flags, null);
2138    }
2139
2140    /**
2141     * Generate a dynamic new
2142     *
2143     * @param argCount  number of arguments
2144     * @param flags     callsite flags
2145     * @param msg        additional message to be used when reporting error
2146     *
2147     * @return the method emitter
2148     */
2149    MethodEmitter dynamicNew(final int argCount, final int flags, final String msg) {
2150        assert !isOptimistic(flags);
2151        debug("dynamic_new", "argcount=", argCount);
2152        final String signature = getDynamicSignature(Type.OBJECT, argCount);
2153        method.visitInvokeDynamicInsn(
2154                msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
2155                signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.NEW);
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        return dynamicCall(returnType, argCount, flags, null);
2171    }
2172
2173    /**
2174     * Generate a dynamic call
2175     *
2176     * @param returnType return type
2177     * @param argCount   number of arguments
2178     * @param flags      callsite flags
2179     * @param msg        additional message to be used when reporting error
2180     *
2181     * @return the method emitter
2182     */
2183    MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags, final String msg) {
2184        debug("dynamic_call", "args=", argCount, "returnType=", returnType);
2185        final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
2186        debug("   signature", signature);
2187        method.visitInvokeDynamicInsn(
2188                msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
2189                signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.CALL);
2190        pushType(returnType);
2191
2192        return this;
2193    }
2194
2195    MethodEmitter dynamicArrayPopulatorCall(final int argCount, final int startIndex) {
2196        debug("populate_array", "args=", argCount, "startIndex=", startIndex);
2197        final String signature = getDynamicSignature(Type.OBJECT_ARRAY, argCount);
2198        method.visitInvokeDynamicInsn("populateArray", signature, POPULATE_ARRAY_BOOTSTRAP, startIndex);
2199        pushType(Type.OBJECT_ARRAY);
2200        return this;
2201    }
2202
2203    /**
2204     * Generate dynamic getter. Pop scope from stack. Push result
2205     *
2206     * @param valueType type of the value to set
2207     * @param name      name of property
2208     * @param flags     call site flags
2209     * @param isMethod  should it prefer retrieving methods
2210     * @param isIndex   is this an index operation?
2211     * @return the method emitter
2212     */
2213    MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
2214        if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
2215            return load(name).dynamicGetIndex(valueType, flags, isMethod);
2216        }
2217
2218        debug("dynamic_get", name, valueType, getProgramPoint(flags));
2219
2220        Type type = valueType;
2221        if (type.isObject() || type.isBoolean()) {
2222            type = Type.OBJECT; //promote e.g strings to object generic setter
2223        }
2224
2225        popType(Type.SCOPE);
2226        method.visitInvokeDynamicInsn(NameCodec.encode(name),
2227                Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, isIndex));
2228
2229        pushType(type);
2230        convert(valueType); //most probably a nop
2231
2232        return this;
2233    }
2234
2235    /**
2236     * Generate dynamic setter. Pop receiver and property from stack.
2237     *
2238     * @param name  name of property
2239     * @param flags call site flags
2240     * @param isIndex is this an index operation?
2241     */
2242    void dynamicSet(final String name, final int flags, final boolean isIndex) {
2243        if (name.length() > LARGE_STRING_THRESHOLD) { // use setIndex for extremely long names
2244            load(name).swap().dynamicSetIndex(flags);
2245            return;
2246        }
2247
2248        assert !isOptimistic(flags);
2249        debug("dynamic_set", name, peekType());
2250
2251        Type type = peekType();
2252        if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
2253            type = Type.OBJECT;
2254            convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
2255        }
2256        popType(type);
2257        popType(Type.SCOPE);
2258
2259        method.visitInvokeDynamicInsn(NameCodec.encode(name),
2260                methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags | dynSetOperation(isIndex));
2261    }
2262
2263     /**
2264     * Dynamic getter for indexed structures. Pop index and receiver from stack,
2265     * generate appropriate signatures based on types
2266     *
2267     * @param result result type for getter
2268     * @param flags call site flags for getter
2269     * @param isMethod should it prefer retrieving methods
2270     *
2271     * @return the method emitter
2272     */
2273    MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
2274        assert result.getTypeClass().isPrimitive() || result.getTypeClass() == Object.class;
2275        debug("dynamic_get_index", peekType(1), "[", peekType(), "]", getProgramPoint(flags));
2276
2277        Type resultType = result;
2278        if (result.isBoolean()) {
2279            resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
2280        }
2281
2282        Type index = peekType();
2283        if (index.isObject() || index.isBoolean()) {
2284            index = Type.OBJECT; //e.g. string->object
2285            convert(Type.OBJECT);
2286        }
2287        popType();
2288
2289        popType(Type.OBJECT);
2290
2291        final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
2292
2293        method.visitInvokeDynamicInsn(EMPTY_NAME, signature, LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, true));
2294        pushType(resultType);
2295
2296        if (result.isBoolean()) {
2297            convert(Type.BOOLEAN);
2298        }
2299
2300        return this;
2301    }
2302
2303    private static String getProgramPoint(final int flags) {
2304        if((flags & CALLSITE_OPTIMISTIC) == 0) {
2305            return "";
2306        }
2307        return "pp=" + String.valueOf((flags & (-1 << CALLSITE_PROGRAM_POINT_SHIFT)) >> CALLSITE_PROGRAM_POINT_SHIFT);
2308    }
2309
2310    /**
2311     * Dynamic setter for indexed structures. Pop value, index and receiver from
2312     * stack, generate appropriate signature based on types
2313     *
2314     * @param flags call site flags for setter
2315     */
2316    void dynamicSetIndex(final int flags) {
2317        assert !isOptimistic(flags);
2318        debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
2319
2320        Type value = peekType();
2321        if (value.isObject() || value.isBoolean()) {
2322            value = Type.OBJECT; //e.g. STRING->OBJECT - one descriptor for all object types
2323            convert(Type.OBJECT);
2324        }
2325        popType();
2326
2327        Type index = peekType();
2328        if (index.isObject() || index.isBoolean()) {
2329            index = Type.OBJECT; //e.g. string->object
2330            convert(Type.OBJECT);
2331        }
2332        popType(index);
2333
2334        final Type receiver = popType(Type.OBJECT);
2335        assert receiver.isObject();
2336
2337        method.visitInvokeDynamicInsn(EMPTY_NAME,
2338                methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()),
2339                LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.SET_ELEMENT);
2340    }
2341
2342    /**
2343     * Load a key value in the proper form.
2344     *
2345     * @param key
2346     */
2347    //TODO move this and break it apart
2348    MethodEmitter loadKey(final Object key) {
2349        if (key instanceof IdentNode) {
2350            method.visitLdcInsn(((IdentNode) key).getName());
2351        } else if (key instanceof LiteralNode) {
2352            method.visitLdcInsn(((LiteralNode<?>)key).getString());
2353        } else {
2354            method.visitLdcInsn(JSType.toString(key));
2355        }
2356        pushType(Type.OBJECT); //STRING
2357        return this;
2358    }
2359
2360     @SuppressWarnings("fallthrough")
2361     private static Type fieldType(final String desc) {
2362         switch (desc) {
2363         case "Z":
2364         case "B":
2365         case "C":
2366         case "S":
2367         case "I":
2368             return Type.INT;
2369         case "F":
2370             assert false;
2371         case "D":
2372             return Type.NUMBER;
2373         case "J":
2374             return Type.LONG;
2375         default:
2376             assert desc.startsWith("[") || desc.startsWith("L") : desc + " is not an object type";
2377             switch (desc.charAt(0)) {
2378             case 'L':
2379                 return Type.OBJECT;
2380             case '[':
2381                 return Type.typeFor(Array.newInstance(fieldType(desc.substring(1)).getTypeClass(), 0).getClass());
2382             default:
2383                 assert false;
2384             }
2385             return Type.OBJECT;
2386         }
2387     }
2388
2389     /**
2390      * Generate get for a field access
2391      *
2392      * @param fa the field access
2393      *
2394      * @return the method emitter
2395      */
2396    MethodEmitter getField(final FieldAccess fa) {
2397        return fa.get(this);
2398    }
2399
2400     /**
2401      * Generate set for a field access
2402      *
2403      * @param fa the field access
2404      */
2405    void putField(final FieldAccess fa) {
2406        fa.put(this);
2407    }
2408
2409    /**
2410     * Get the value of a non-static field, pop the receiver from the stack,
2411     * push value to the stack
2412     *
2413     * @param className        class
2414     * @param fieldName        field name
2415     * @param fieldDescriptor  field descriptor
2416     *
2417     * @return the method emitter
2418     */
2419    MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
2420        debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
2421        final Type receiver = popType();
2422        assert receiver.isObject();
2423        method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
2424        pushType(fieldType(fieldDescriptor));
2425        return this;
2426    }
2427
2428    /**
2429     * Get the value of a static field, push it to the stack
2430     *
2431     * @param className        class
2432     * @param fieldName        field name
2433     * @param fieldDescriptor  field descriptor
2434     *
2435     * @return the method emitter
2436     */
2437    MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
2438        debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
2439        method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
2440        pushType(fieldType(fieldDescriptor));
2441        return this;
2442    }
2443
2444    /**
2445     * Pop value and field from stack and write to a non-static field
2446     *
2447     * @param className       class
2448     * @param fieldName       field name
2449     * @param fieldDescriptor field descriptor
2450     */
2451    void putField(final String className, final String fieldName, final String fieldDescriptor) {
2452        debug("putfield", "receiver=", peekType(1), "value=", peekType());
2453        popType(fieldType(fieldDescriptor));
2454        popType(Type.OBJECT);
2455        method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
2456    }
2457
2458    /**
2459     * Pop value from stack and write to a static field
2460     *
2461     * @param className       class
2462     * @param fieldName       field name
2463     * @param fieldDescriptor field descriptor
2464     */
2465    void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
2466        debug("putfield", "value=", peekType());
2467        popType(fieldType(fieldDescriptor));
2468        method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
2469    }
2470
2471    /**
2472     * Register line number at a label
2473     *
2474     * @param line  line number
2475     */
2476    void lineNumber(final int line) {
2477        if (context.getEnv()._debug_lines) {
2478            debug_label("[LINE]", line);
2479            final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
2480            method.visitLabel(l);
2481            method.visitLineNumber(line, l);
2482        }
2483    }
2484
2485    void beforeJoinPoint(final JoinPredecessor joinPredecessor) {
2486        LocalVariableConversion next = joinPredecessor.getLocalVariableConversion();
2487        while(next != null) {
2488            final Symbol symbol = next.getSymbol();
2489            if(next.isLive()) {
2490                emitLocalVariableConversion(next, true);
2491            } else {
2492                markDeadLocalVariable(symbol);
2493            }
2494            next = next.getNext();
2495        }
2496    }
2497
2498    void beforeTry(final TryNode tryNode, final Label recovery) {
2499        LocalVariableConversion next = tryNode.getLocalVariableConversion();
2500        while(next != null) {
2501            if(next.isLive()) {
2502                final Type to = emitLocalVariableConversion(next, false);
2503                recovery.getStack().onLocalStore(to, next.getSymbol().getSlot(to), true);
2504            }
2505            next = next.getNext();
2506        }
2507    }
2508
2509    private static int dynGetOperation(final boolean isMethod, final boolean isIndex) {
2510        if (isMethod) {
2511            return isIndex ? NashornCallSiteDescriptor.GET_METHOD_ELEMENT : NashornCallSiteDescriptor.GET_METHOD_PROPERTY;
2512        } else {
2513            return isIndex ? NashornCallSiteDescriptor.GET_ELEMENT : NashornCallSiteDescriptor.GET_PROPERTY;
2514        }
2515    }
2516
2517    private static int dynSetOperation(final boolean isIndex) {
2518        return isIndex ? NashornCallSiteDescriptor.SET_ELEMENT : NashornCallSiteDescriptor.SET_PROPERTY;
2519    }
2520
2521    private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) {
2522        final Type from = conversion.getFrom();
2523        final Type to = conversion.getTo();
2524        final Symbol symbol = conversion.getSymbol();
2525        assert symbol.isBytecodeLocal();
2526        if(from == Type.UNDEFINED) {
2527            loadUndefined(to);
2528        } else {
2529            load(symbol, from).convert(to);
2530        }
2531        store(symbol, to, onlySymbolLiveValue);
2532        return to;
2533    }
2534
2535    /*
2536     * Debugging below
2537     */
2538
2539    private final FieldAccess ERR_STREAM       = staticField(System.class, "err", PrintStream.class);
2540    private final Call        PRINT            = virtualCallNoLookup(PrintStream.class, "print", void.class, Object.class);
2541    private final Call        PRINTLN          = virtualCallNoLookup(PrintStream.class, "println", void.class, Object.class);
2542    private final Call        PRINT_STACKTRACE = virtualCallNoLookup(Throwable.class, "printStackTrace", void.class);
2543
2544    /**
2545     * Emit a System.err.print statement of whatever is on top of the bytecode stack
2546     */
2547     void print() {
2548         getField(ERR_STREAM);
2549         swap();
2550         convert(Type.OBJECT);
2551         invoke(PRINT);
2552     }
2553
2554    /**
2555     * Emit a System.err.println statement of whatever is on top of the bytecode stack
2556     */
2557     void println() {
2558         getField(ERR_STREAM);
2559         swap();
2560         convert(Type.OBJECT);
2561         invoke(PRINTLN);
2562     }
2563
2564     /**
2565      * Emit a System.err.print statement
2566      * @param string string to print
2567      */
2568     void print(final String string) {
2569         getField(ERR_STREAM);
2570         load(string);
2571         invoke(PRINT);
2572     }
2573
2574     /**
2575      * Emit a System.err.println statement
2576      * @param string string to print
2577      */
2578     void println(final String string) {
2579         getField(ERR_STREAM);
2580         load(string);
2581         invoke(PRINTLN);
2582     }
2583
2584     /**
2585      * Print a stacktrace to S
2586      */
2587     void stacktrace() {
2588         _new(Throwable.class);
2589         dup();
2590         invoke(constructorNoLookup(Throwable.class));
2591         invoke(PRINT_STACKTRACE);
2592     }
2593
2594    private static int linePrefix = 0;
2595
2596    /**
2597     * Debug function that outputs generated bytecode and stack contents
2598     *
2599     * @param args debug information to print
2600     */
2601    @SuppressWarnings("unused")
2602    private void debug(final Object... args) {
2603        if (debug) {
2604            debug(30, args);
2605        }
2606    }
2607
2608    private void debug(final String arg) {
2609        if (debug) {
2610            debug(30, arg);
2611        }
2612    }
2613
2614    private void debug(final Object arg0, final Object arg1) {
2615        if (debug) {
2616            debug(30, new Object[] { arg0, arg1 });
2617        }
2618    }
2619
2620    private void debug(final Object arg0, final Object arg1, final Object arg2) {
2621        if (debug) {
2622            debug(30, new Object[] { arg0, arg1, arg2 });
2623        }
2624    }
2625
2626    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3) {
2627        if (debug) {
2628            debug(30, new Object[] { arg0, arg1, arg2, arg3 });
2629        }
2630    }
2631
2632    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4) {
2633        if (debug) {
2634            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4 });
2635        }
2636    }
2637
2638    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5) {
2639        if (debug) {
2640            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5 });
2641        }
2642    }
2643
2644    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5, final Object arg6) {
2645        if (debug) {
2646            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5, arg6 });
2647        }
2648    }
2649
2650    /**
2651     * Debug function that outputs generated bytecode and stack contents
2652     * for a label - indentation is currently the only thing that differs
2653     *
2654     * @param args debug information to print
2655     */
2656    private void debug_label(final Object... args) {
2657        if (debug) {
2658            debug(22, args);
2659        }
2660    }
2661
2662    private void debug(final int padConstant, final Object... args) {
2663        if (debug) {
2664            final StringBuilder sb = new StringBuilder();
2665            int pad;
2666
2667            sb.append('#');
2668            sb.append(++linePrefix);
2669
2670            pad = 5 - sb.length();
2671            while (pad > 0) {
2672                sb.append(' ');
2673                pad--;
2674            }
2675
2676            if (isReachable() && !stack.isEmpty()) {
2677                sb.append("{");
2678                sb.append(stack.size());
2679                sb.append(":");
2680                for (int pos = 0; pos < stack.size(); pos++) {
2681                    final Type t = stack.peek(pos);
2682
2683                    if (t == Type.SCOPE) {
2684                        sb.append("scope");
2685                    } else if (t == Type.THIS) {
2686                        sb.append("this");
2687                    } else if (t.isObject()) {
2688                        String desc = t.getDescriptor();
2689                        int i;
2690                        for (i = 0; desc.charAt(i) == '[' && i < desc.length(); i++) {
2691                            sb.append('[');
2692                        }
2693                        desc = desc.substring(i);
2694                        final int slash = desc.lastIndexOf('/');
2695                        if (slash != -1) {
2696                            desc = desc.substring(slash + 1, desc.length() - 1);
2697                        }
2698                        if ("Object".equals(desc)) {
2699                            sb.append('O');
2700                        } else {
2701                            sb.append(desc);
2702                        }
2703                    } else {
2704                        sb.append(t.getDescriptor());
2705                    }
2706                    final int loadIndex = stack.localLoads[stack.sp - 1 - pos];
2707                    if(loadIndex != Label.Stack.NON_LOAD) {
2708                        sb.append('(').append(loadIndex).append(')');
2709                    }
2710                    if (pos + 1 < stack.size()) {
2711                        sb.append(' ');
2712                    }
2713                }
2714                sb.append('}');
2715                sb.append(' ');
2716            }
2717
2718            pad = padConstant - sb.length();
2719            while (pad > 0) {
2720                sb.append(' ');
2721                pad--;
2722            }
2723
2724            for (final Object arg : args) {
2725                sb.append(arg);
2726                sb.append(' ');
2727            }
2728
2729            if (context.getEnv() != null) { //early bootstrap code doesn't have inited context yet
2730                log.info(sb);
2731                if (DEBUG_TRACE_LINE == linePrefix) {
2732                    new Throwable().printStackTrace(log.getOutputStream());
2733                }
2734            }
2735        }
2736    }
2737
2738    /**
2739     * Set the current function node being emitted
2740     * @param functionNode the function node
2741     */
2742    void setFunctionNode(final FunctionNode functionNode) {
2743        this.functionNode = functionNode;
2744    }
2745
2746    /**
2747     * Invoke to enforce assertions preventing load from a local variable slot that's known to not have been written to.
2748     * Used by CodeGenerator, as it strictly enforces tracking of stores. Simpler uses of MethodEmitter, e.g. those
2749     * for creating initializers for structure  classes, array getters, etc. don't have strict tracking of stores,
2750     * therefore they would fail if they had this assertion turned on.
2751     */
2752    void setPreventUndefinedLoad() {
2753        this.preventUndefinedLoad = true;
2754    }
2755
2756    private static boolean isOptimistic(final int flags) {
2757        return (flags & CALLSITE_OPTIMISTIC) != 0;
2758    }
2759}
2760