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