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