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