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