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