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