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_ICMPNE;
  47 import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF;
  48 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
  49 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
  50 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
  51 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
  52 import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
  53 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
  54 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
  55 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
  56 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
  57 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
  58 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
  59 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
  60 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
  61 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
  62 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
  63 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
  64 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
  65 import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
  66 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
  67 
  68 import java.io.PrintStream;
  69 import java.lang.reflect.Array;
  70 import java.util.EnumSet;
  71 import java.util.List;
  72 import jdk.internal.dynalink.support.NameCodec;
  73 import jdk.internal.org.objectweb.asm.Handle;
  74 import jdk.internal.org.objectweb.asm.MethodVisitor;
  75 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
  76 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  77 import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
  78 import jdk.nashorn.internal.codegen.types.ArrayType;
  79 import jdk.nashorn.internal.codegen.types.BitwiseType;
  80 import jdk.nashorn.internal.codegen.types.NumericType;
  81 import jdk.nashorn.internal.codegen.types.Type;
  82 import jdk.nashorn.internal.ir.FunctionNode;
  83 import jdk.nashorn.internal.ir.IdentNode;
  84 import jdk.nashorn.internal.ir.LexicalContext;
  85 import jdk.nashorn.internal.ir.LiteralNode;
  86 import jdk.nashorn.internal.ir.RuntimeNode;
  87 import jdk.nashorn.internal.ir.Symbol;
  88 import jdk.nashorn.internal.runtime.ArgumentSetter;
  89 import jdk.nashorn.internal.runtime.Debug;
  90 import jdk.nashorn.internal.runtime.DebugLogger;
  91 import jdk.nashorn.internal.runtime.JSType;
  92 import jdk.nashorn.internal.runtime.ScriptEnvironment;
  93 import jdk.nashorn.internal.runtime.ScriptObject;
  94 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  95 import jdk.nashorn.internal.runtime.options.Options;
  96 
  97 /**
  98  * This is the main function responsible for emitting method code
  99  * in a class. It maintains a type stack and keeps track of control
 100  * flow to make sure that the registered instructions don't violate
 101  * byte code verification.
 102  *
 103  * Running Nashorn with -ea will assert as soon as a type stack
 104  * becomes corrupt, for easier debugging
 105  *
 106  * Running Nashorn with -Dnashorn.codegen.debug=true will print
 107  * all generated bytecode and labels to stderr, for easier debugging,
 108  * including bytecode stack contents
 109  */
 110 public class MethodEmitter implements Emitter {
 111     /** The ASM MethodVisitor we are plugged into */
 112     private final MethodVisitor method;
 113 
 114     /** Current type stack for current evaluation */
 115     private Label.Stack stack;
 116 
 117     /** Parent classEmitter representing the class of this method */
 118     private final ClassEmitter classEmitter;
 119 
 120     /** FunctionNode representing this method, or null if none exists */
 121     protected FunctionNode functionNode;
 122 
 123     /** Check whether this emitter ever has a function return point */
 124     private boolean hasReturn;
 125 
 126     /** The script environment */
 127     private final ScriptEnvironment env;
 128 
 129     /** Threshold in chars for when string constants should be split */
 130     static final int LARGE_STRING_THRESHOLD = 32 * 1024;
 131 
 132     /** Debug flag, should we dump all generated bytecode along with stacks? */
 133     private static final DebugLogger LOG   = new DebugLogger("codegen", "nashorn.codegen.debug");
 134     private static final boolean     DEBUG = LOG.isEnabled();
 135 
 136     /** dump stack on a particular line, or -1 if disabled */
 137     private static final int DEBUG_TRACE_LINE;
 138 
 139     static {
 140         final String tl = Options.getStringProperty("nashorn.codegen.debug.trace", "-1");
 141         int line = -1;
 142         try {
 143             line = Integer.parseInt(tl);
 144         } catch (final NumberFormatException e) {
 145             //fallthru
 146         }
 147         DEBUG_TRACE_LINE = line;
 148     }
 149 
 150     /** Bootstrap for normal indy:s */
 151     private static final Handle LINKERBOOTSTRAP  = new Handle(H_INVOKESTATIC, Bootstrap.BOOTSTRAP.className(), Bootstrap.BOOTSTRAP.name(), Bootstrap.BOOTSTRAP.descriptor());
 152 
 153     /** Bootstrap for runtime node indy:s */
 154     private static final Handle RUNTIMEBOOTSTRAP = new Handle(H_INVOKESTATIC, RuntimeCallSite.BOOTSTRAP.className(), RuntimeCallSite.BOOTSTRAP.name(), RuntimeCallSite.BOOTSTRAP.descriptor());
 155 
 156     /**
 157      * Constructor - internal use from ClassEmitter only
 158      * @see ClassEmitter#method
 159      *
 160      * @param classEmitter the class emitter weaving the class this method is in
 161      * @param method       a method visitor
 162      */
 163     MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method) {
 164         this(classEmitter, method, null);
 165     }
 166 
 167     /**
 168      * Constructor - internal use from ClassEmitter only
 169      * @see ClassEmitter#method
 170      *
 171      * @param classEmitter the class emitter weaving the class this method is in
 172      * @param method       a method visitor
 173      * @param functionNode a function node representing this method
 174      */
 175     MethodEmitter(final ClassEmitter classEmitter, final MethodVisitor method, final FunctionNode functionNode) {
 176         this.env          = classEmitter.getEnv();
 177         this.classEmitter = classEmitter;
 178         this.method       = method;
 179         this.functionNode = functionNode;
 180         this.stack        = null;
 181     }
 182 
 183     /**
 184      * Begin a method
 185      * @see Emitter
 186      */
 187     @Override
 188     public void begin() {
 189         classEmitter.beginMethod(this);
 190         newStack();
 191         method.visitCode();
 192     }
 193 
 194     /**
 195      * End a method
 196      * @see Emitter
 197      */
 198     @Override
 199     public void end() {
 200         method.visitMaxs(0, 0);
 201         method.visitEnd();
 202 
 203         classEmitter.endMethod(this);
 204     }
 205 
 206     private void newStack() {
 207         stack = new Label.Stack();
 208     }
 209 
 210     @Override
 211     public String toString() {
 212         return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
 213     }
 214 
 215     /**
 216      * Push a type to the existing stack
 217      * @param type the type
 218      */
 219     private void pushType(final Type type) {
 220         if (type != null) {
 221             stack.push(type);
 222         }
 223     }
 224 
 225     /**
 226      * Pop a type from the existing stack
 227      *
 228      * @param expected expected type - will assert if wrong
 229      *
 230      * @return the type that was retrieved
 231      */
 232     private Type popType(final Type expected) {
 233         final Type type = stack.pop();
 234         assert type.isObject() && expected.isObject() ||
 235             type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
 236         return type;
 237     }
 238 
 239     /**
 240      * Pop a type from the existing stack, no matter what it is.
 241      *
 242      * @return the type
 243      */
 244     private Type popType() {
 245         return stack.pop();
 246     }
 247 
 248     /**
 249      * Pop a type from the existing stack, ensuring that it is numeric,
 250      * assert if not
 251      *
 252      * @return the type
 253      */
 254     private NumericType popNumeric() {
 255         final Type type = stack.pop();
 256         assert type.isNumeric() : type + " is not numeric";
 257         return (NumericType)type;
 258     }
 259 
 260     /**
 261      * Pop a type from the existing stack, ensuring that it is an integer type
 262      * (integer or long), assert if not
 263      *
 264      * @return the type
 265      */
 266     private BitwiseType popInteger() {
 267         final Type type = stack.pop();
 268         assert type.isInteger() || type.isLong() : type + " is not an integer or long";
 269         return (BitwiseType)type;
 270     }
 271 
 272     /**
 273      * Pop a type from the existing stack, ensuring that it is an array type,
 274      * assert if not
 275      *
 276      * @return the type
 277      */
 278     private ArrayType popArray() {
 279         final Type type = stack.pop();
 280         assert type.isArray() : type;
 281         return (ArrayType)type;
 282     }
 283 
 284     /**
 285      * Peek a given number of slots from the top of the stack and return the
 286      * type in that slot
 287      *
 288      * @param pos the number of positions from the top, 0 is the top element
 289      *
 290      * @return the type at position "pos" on the stack
 291      */
 292     final Type peekType(final int pos) {
 293         return stack.peek(pos);
 294     }
 295 
 296     /**
 297      * Peek at the type at the top of the stack
 298      *
 299      * @return the type at the top of the stack
 300      */
 301     final Type peekType() {
 302         return stack.peek();
 303     }
 304 
 305     /**
 306      * Generate code a for instantiating a new object and push the
 307      * object type on the stack
 308      *
 309      * @param classDescriptor class descriptor for the object type
 310      *
 311      * @return the method emitter
 312      */
 313     MethodEmitter _new(final String classDescriptor) {
 314         debug("new", classDescriptor);
 315         method.visitTypeInsn(NEW, classDescriptor);
 316         pushType(Type.OBJECT);
 317         return this;
 318     }
 319 
 320     /**
 321      * Generate code a for instantiating a new object and push the
 322      * object type on the stack
 323      *
 324      * @param clazz class type to instatiate
 325      *
 326      * @return the method emitter
 327      */
 328     MethodEmitter _new(final Class<?> clazz) {
 329         return _new(className(clazz));
 330     }
 331 
 332     /**
 333      * Generate code to call the empty constructor for a class
 334      *
 335      * @param clazz class type to instatiate
 336      *
 337      * @return the method emitter
 338      */
 339     MethodEmitter newInstance(final Class<?> clazz) {
 340         return invoke(constructorNoLookup(clazz));
 341     }
 342 
 343     /**
 344      * Perform a dup, that is, duplicate the top element and
 345      * push the duplicate down a given number of positions
 346      * on the stack. This is totally type agnostic.
 347      *
 348      * @param depth the depth on which to put the copy
 349      *
 350      * @return the method emitter, or null if depth is illegal and
 351      *  has no instruction equivalent.
 352      */
 353     MethodEmitter dup(final int depth) {
 354         if (peekType().dup(method, depth) == null) {
 355             return null;
 356         }
 357 
 358         debug("dup", depth);
 359 
 360         switch (depth) {
 361         case 0:
 362             pushType(peekType());
 363             break;
 364         case 1: {
 365             final Type p0 = popType();
 366             final Type p1 = popType();
 367             pushType(p0);
 368             pushType(p1);
 369             pushType(p0);
 370             break;
 371         }
 372         case 2: {
 373             final Type p0 = popType();
 374             final Type p1 = popType();
 375             final Type p2 = popType();
 376             pushType(p0);
 377             pushType(p2);
 378             pushType(p1);
 379             pushType(p0);
 380             break;
 381         }
 382         default:
 383             assert false : "illegal dup depth = " + depth;
 384             return null;
 385         }
 386 
 387         return this;
 388     }
 389 
 390     /**
 391      * Perform a dup2, that is, duplicate the top element if it
 392      * is a category 2 type, or two top elements if they are category
 393      * 1 types, and push them on top of the stack
 394      *
 395      * @return the method emitter
 396      */
 397     MethodEmitter dup2() {
 398         debug("dup2");
 399 
 400         if (peekType().isCategory2()) {
 401             pushType(peekType());
 402         } else {
 403             final Type type = get2();
 404             pushType(type);
 405             pushType(type);
 406             pushType(type);
 407             pushType(type);
 408         }
 409         method.visitInsn(DUP2);
 410         return this;
 411     }
 412 
 413     /**
 414      * Duplicate the top element on the stack and push it
 415      *
 416      * @return the method emitter
 417      */
 418     MethodEmitter dup() {
 419         return dup(0);
 420     }
 421 
 422     /**
 423      * Pop the top element of the stack and throw it away
 424      *
 425      * @return the method emitter
 426      */
 427     MethodEmitter pop() {
 428         debug("pop", peekType());
 429         popType().pop(method);
 430         return this;
 431     }
 432 
 433     /**
 434      * Pop the top element of the stack if category 2 type, or the two
 435      * top elements of the stack if category 1 types
 436      *
 437      * @return the method emitter
 438      */
 439     MethodEmitter pop2() {
 440         if (peekType().isCategory2()) {
 441             popType();
 442         } else {
 443             get2n();
 444         }
 445         return this;
 446     }
 447 
 448     /**
 449      * Swap the top two elements of the stack. This is totally
 450      * type agnostic and works for all types
 451      *
 452      * @return the method emitter
 453      */
 454     MethodEmitter swap() {
 455         debug("swap");
 456 
 457         final Type p0 = popType();
 458         final Type p1 = popType();
 459         p0.swap(method, p1);
 460 
 461         pushType(p0);
 462         pushType(p1);
 463         debug("after ", p0, p1);
 464         return this;
 465     }
 466 
 467     /**
 468      * Add a local variable. This is a nop if the symbol has no slot
 469      *
 470      * @param symbol symbol for the local variable
 471      * @param start  start of scope
 472      * @param end    end of scope
 473      */
 474     void localVariable(final Symbol symbol, final Label start, final Label end) {
 475         if (!symbol.hasSlot()) {
 476             return;
 477         }
 478 
 479         String name = symbol.getName();
 480 
 481         if (name.equals(THIS.symbolName())) {
 482             name = THIS_DEBUGGER.symbolName();
 483         }
 484 
 485         method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
 486     }
 487 
 488     /**
 489      * Create a new string builder, call the constructor and push the instance to the stack.
 490      *
 491      * @return the method emitter
 492      */
 493     MethodEmitter newStringBuilder() {
 494         return invoke(constructorNoLookup(StringBuilder.class)).dup();
 495     }
 496 
 497     /**
 498      * Pop a string and a StringBuilder from the top of the stack and call the append
 499      * function of the StringBuilder, appending the string. Pushes the StringBuilder to
 500      * the stack when finished.
 501      *
 502      * @return the method emitter
 503      */
 504     MethodEmitter stringBuilderAppend() {
 505         convert(Type.STRING);
 506         return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
 507     }
 508 
 509     /**
 510      * Pops two integer types from the stack, performs a bitwise and and pushes
 511      * the result
 512      *
 513      * @return the method emitter
 514      */
 515     MethodEmitter and() {
 516         debug("and");
 517         pushType(get2i().and(method));
 518         return this;
 519     }
 520 
 521     /**
 522      * Pops two integer types from the stack, performs a bitwise or and pushes
 523      * the result
 524      *
 525      * @return the method emitter
 526      */
 527     MethodEmitter or() {
 528         debug("or");
 529         pushType(get2i().or(method));
 530         return this;
 531     }
 532 
 533     /**
 534      * Pops two integer types from the stack, performs a bitwise xor and pushes
 535      * the result
 536      *
 537      * @return the method emitter
 538      */
 539     MethodEmitter xor() {
 540         debug("xor");
 541         pushType(get2i().xor(method));
 542         return this;
 543     }
 544 
 545     /**
 546      * Pops two integer types from the stack, performs a bitwise logic shift right and pushes
 547      * the result. The shift count, the first element, must be INT.
 548      *
 549      * @return the method emitter
 550      */
 551     MethodEmitter shr() {
 552         debug("shr");
 553         popType(Type.INT);
 554         pushType(popInteger().shr(method));
 555         return this;
 556     }
 557 
 558     /**
 559      * Pops two integer types from the stack, performs a bitwise shift left and and pushes
 560      * the result. The shift count, the first element, must be INT.
 561      *
 562      * @return the method emitter
 563      */
 564     MethodEmitter shl() {
 565         debug("shl");
 566         popType(Type.INT);
 567         pushType(popInteger().shl(method));
 568         return this;
 569     }
 570 
 571     /**
 572      * Pops two integer types from the stack, performs a bitwise arithetic shift right and pushes
 573      * the result. The shift count, the first element, must be INT.
 574      *
 575      * @return the method emitter
 576      */
 577     MethodEmitter sar() {
 578         debug("sar");
 579         popType(Type.INT);
 580         pushType(popInteger().sar(method));
 581         return this;
 582     }
 583 
 584     /**
 585      * Pops a numeric type from the stack, negates it and pushes the result
 586      *
 587      * @return the method emitter
 588      */
 589     MethodEmitter neg() {
 590         debug("neg");
 591         pushType(popNumeric().neg(method));
 592         return this;
 593     }
 594 
 595     /**
 596      * Add label for the start of a catch block and push the exception to the
 597      * stack
 598      *
 599      * @param recovery label pointing to start of catch block
 600      */
 601     void _catch(final Label recovery) {
 602         stack.clear();
 603         stack.push(Type.OBJECT);
 604         label(recovery);
 605     }
 606 
 607     /**
 608      * Start a try/catch block.
 609      *
 610      * @param entry          start label for try
 611      * @param exit           end label for try
 612      * @param recovery       start label for catch
 613      * @param typeDescriptor type descriptor for exception
 614      */
 615     void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
 616         method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
 617     }
 618 
 619     /**
 620      * Start a try/catch block.
 621      *
 622      * @param entry    start label for try
 623      * @param exit     end label for try
 624      * @param recovery start label for catch
 625      * @param clazz    exception class
 626      */
 627     void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
 628         method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
 629     }
 630 
 631     /**
 632      * Start a try/catch block. The catch is "Throwable" - i.e. catch-all
 633      *
 634      * @param entry    start label for try
 635      * @param exit     end label for try
 636      * @param recovery start label for catch
 637      */
 638     void _try(final Label entry, final Label exit, final Label recovery) {
 639         _try(entry, exit, recovery, (String)null);
 640     }
 641 
 642 
 643     /**
 644      * Load the constants array
 645      * @return this method emitter
 646      */
 647     MethodEmitter loadConstants() {
 648         getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
 649         assert peekType().isArray() : peekType();
 650         return this;
 651     }
 652 
 653     /**
 654      * Push the undefined value for the given type, i.e.
 655      * UNDEFINED or UNDEFINEDNUMBER. Currently we have no way of
 656      * representing UNDEFINED for INTs and LONGs, so they are not
 657      * allowed to be local variables (yet)
 658      *
 659      * @param type the type for which to push UNDEFINED
 660      * @return the method emitter
 661      */
 662     MethodEmitter loadUndefined(final Type type) {
 663         debug("load undefined ", type);
 664         pushType(type.loadUndefined(method));
 665         return this;
 666     }
 667 
 668     /**
 669      * Push the empty value for the given type, i.e. EMPTY.
 670      *
 671      * @param type the type
 672      * @return the method emitter
 673      */
 674     MethodEmitter loadEmpty(final Type type) {
 675         debug("load empty ", type);
 676         pushType(type.loadEmpty(method));
 677         return this;
 678     }
 679 
 680     /**
 681      * Push null to stack
 682      *
 683      * @return the method emitter
 684      */
 685     MethodEmitter loadNull() {
 686         debug("aconst_null");
 687         pushType(Type.OBJECT.ldc(method, null));
 688         return this;
 689     }
 690 
 691     /**
 692      * Push a handle representing this class top stack
 693      *
 694      * @param className name of the class
 695      *
 696      * @return the method emitter
 697      */
 698     MethodEmitter loadType(final String className) {
 699         debug("load type", className);
 700         method.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(className));
 701         pushType(Type.OBJECT);
 702         return this;
 703     }
 704 
 705     /**
 706      * Push a boolean constant to the stack.
 707      *
 708      * @param b value of boolean
 709      *
 710      * @return the method emitter
 711      */
 712     MethodEmitter load(final boolean b) {
 713         debug("load boolean", b);
 714         pushType(Type.BOOLEAN.ldc(method, b));
 715         return this;
 716     }
 717 
 718     /**
 719      * Push an int constant to the stack
 720      *
 721      * @param i value of the int
 722      *
 723      * @return the method emitter
 724      */
 725     MethodEmitter load(final int i) {
 726         debug("load int", i);
 727         pushType(Type.INT.ldc(method, i));
 728         return this;
 729     }
 730 
 731     /**
 732      * Push a double constant to the stack
 733      *
 734      * @param d value of the double
 735      *
 736      * @return the method emitter
 737      */
 738     MethodEmitter load(final double d) {
 739         debug("load double", d);
 740         pushType(Type.NUMBER.ldc(method, d));
 741         return this;
 742     }
 743 
 744     /**
 745      * Push an long constant to the stack
 746      *
 747      * @param l value of the long
 748      *
 749      * @return the method emitter
 750      */
 751     MethodEmitter load(final long l) {
 752         debug("load long", l);
 753         pushType(Type.LONG.ldc(method, l));
 754         return this;
 755     }
 756 
 757     /**
 758      * Fetch the length of an array.
 759      * @return Array length.
 760      */
 761     MethodEmitter arraylength() {
 762         debug("arraylength");
 763         popType(Type.OBJECT);
 764         pushType(Type.OBJECT_ARRAY.arraylength(method));
 765         return this;
 766     }
 767 
 768     /**
 769      * Push a String constant to the stack
 770      *
 771      * @param s value of the String
 772      *
 773      * @return the method emitter
 774      */
 775     MethodEmitter load(final String s) {
 776         debug("load string", s);
 777 
 778         if (s == null) {
 779             loadNull();
 780             return this;
 781         }
 782 
 783         //NASHORN-142 - split too large string
 784         final int length = s.length();
 785         if (length > LARGE_STRING_THRESHOLD) {
 786 
 787             _new(StringBuilder.class);
 788             dup();
 789             load(length);
 790             invoke(constructorNoLookup(StringBuilder.class, int.class));
 791 
 792             for (int n = 0; n < length; n += LARGE_STRING_THRESHOLD) {
 793                 final String part = s.substring(n, Math.min(n + LARGE_STRING_THRESHOLD, length));
 794                 load(part);
 795                 stringBuilderAppend();
 796             }
 797 
 798             invoke(virtualCallNoLookup(StringBuilder.class, "toString", String.class));
 799 
 800             return this;
 801         }
 802 
 803         pushType(Type.OBJECT.ldc(method, s));
 804         return this;
 805     }
 806 
 807     /**
 808      * Push a local variable to the stack. If the symbol representing
 809      * the local variable doesn't have a slot, this is a NOP
 810      *
 811      * @param symbol the symbol representing the local variable.
 812      *
 813      * @return the method emitter
 814      */
 815     MethodEmitter load(final Symbol symbol) {
 816         assert symbol != null;
 817         if (symbol.hasSlot()) {
 818             final int slot = symbol.getSlot();
 819             debug("load symbol", symbol.getName(), " slot=", slot);
 820             final Type type = symbol.getSymbolType().load(method, slot);
 821             pushType(type == Type.OBJECT && symbol.isThis() ? Type.THIS : type);
 822         } else if (symbol.isParam()) {
 823             assert !symbol.isScope();
 824             assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
 825             final int index = symbol.getFieldIndex();
 826             if (functionNode.needsArguments()) {
 827                 // ScriptObject.getArgument(int) on arguments
 828                 debug("load symbol", symbol.getName(), " arguments index=", index);
 829                 loadCompilerConstant(ARGUMENTS);
 830                 load(index);
 831                 ScriptObject.GET_ARGUMENT.invoke(this);
 832             } else {
 833                 // array load from __varargs__
 834                 debug("load symbol", symbol.getName(), " array index=", index);
 835                 loadCompilerConstant(VARARGS);
 836                 load(symbol.getFieldIndex());
 837                 arrayload();
 838             }
 839         }
 840         return this;
 841     }
 842 
 843     /**
 844      * Push a local variable to the stack, given an explicit bytecode slot
 845      * This is used e.g. for stub generation where we know where items like
 846      * "this" and "scope" reside.
 847      *
 848      * @param type  the type of the variable
 849      * @param slot  the slot the variable is in
 850      *
 851      * @return the method emitter
 852      */
 853     MethodEmitter load(final Type type, final int slot) {
 854         debug("explicit load", type, slot);
 855         final Type loadType = type.load(method, slot);
 856         pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType);
 857         return this;
 858     }
 859 
 860     private boolean isThisSlot(final int slot) {
 861         if (functionNode == null) {
 862             return slot == CompilerConstants.JAVA_THIS.slot();
 863         }
 864         final int thisSlot = compilerConstant(THIS).getSlot();
 865         assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
 866         assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
 867         return slot == thisSlot;
 868     }
 869 
 870     /**
 871      * Push a method handle to the stack
 872      *
 873      * @param className  class name
 874      * @param methodName method name
 875      * @param descName   descriptor
 876      * @param flags      flags that describe this handle, e.g. invokespecial new, or invoke virtual
 877      *
 878      * @return the method emitter
 879      */
 880     MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet<Flag> flags) {
 881         debug("load handle ");
 882         pushType(Type.OBJECT.ldc(method, new Handle(Flag.getValue(flags), className, methodName, descName)));
 883         return this;
 884     }
 885 
 886     private Symbol compilerConstant(final CompilerConstants cc) {
 887         return functionNode.getBody().getExistingSymbol(cc.symbolName());
 888     }
 889 
 890     /**
 891      * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
 892      * the scope).
 893      * @return if this method has a slot allocated for the scope variable.
 894      */
 895     boolean hasScope() {
 896         return compilerConstant(SCOPE).hasSlot();
 897     }
 898 
 899     MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
 900         final Symbol symbol = compilerConstant(cc);
 901         if (cc == SCOPE && peekType() == Type.SCOPE) {
 902             dup();
 903             return this;
 904         }
 905         return load(symbol);
 906     }
 907 
 908     void storeCompilerConstant(final CompilerConstants cc) {
 909         final Symbol symbol = compilerConstant(cc);
 910         debug("store compiler constant ", symbol);
 911         store(symbol);
 912     }
 913 
 914     /**
 915      * Load an element from an array, determining type automatically
 916      * @return the method emitter
 917      */
 918     MethodEmitter arrayload() {
 919         debug("Xaload");
 920         popType(Type.INT);
 921         pushType(popArray().aload(method));
 922         return this;
 923     }
 924 
 925     /**
 926      * Pop a value, an index and an array from the stack and store
 927      * the value at the given index in the array.
 928      */
 929     void arraystore() {
 930         debug("Xastore");
 931         final Type value = popType();
 932         final Type index = popType(Type.INT);
 933         assert index.isInteger() : "array index is not integer, but " + index;
 934         final ArrayType array = popArray();
 935 
 936         assert value.isEquivalentTo(array.getElementType()) : "Storing "+value+" into "+array;
 937         assert array.isObject();
 938         array.astore(method);
 939     }
 940 
 941     /**
 942      * Pop a value from the stack and store it in a local variable represented
 943      * by the given symbol. If the symbol has no slot, this is a NOP
 944      *
 945      * @param symbol symbol to store stack to
 946      */
 947     void store(final Symbol symbol) {
 948         assert symbol != null : "No symbol to store";
 949         if (symbol.hasSlot()) {
 950             final int slot = symbol.getSlot();
 951             debug("store symbol", symbol.getName(), " slot=", slot);
 952             popType(symbol.getSymbolType()).store(method, slot);
 953         } else if (symbol.isParam()) {
 954             assert !symbol.isScope();
 955             assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters";
 956             final int index = symbol.getFieldIndex();
 957             if (functionNode.needsArguments()) {
 958                 debug("store symbol", symbol.getName(), " arguments index=", index);
 959                 loadCompilerConstant(ARGUMENTS);
 960                 load(index);
 961                 ArgumentSetter.SET_ARGUMENT.invoke(this);
 962             } else {
 963                 // varargs without arguments object - just do array store to __varargs__
 964                 debug("store symbol", symbol.getName(), " array index=", index);
 965                 loadCompilerConstant(VARARGS);
 966                 load(index);
 967                 ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this);
 968             }
 969         }
 970     }
 971 
 972     /**
 973      * Pop a value from the stack and store it in a given local variable
 974      * slot.
 975      *
 976      * @param type the type to pop
 977      * @param slot the slot
 978      */
 979     void store(final Type type, final int slot) {
 980         popType(type);
 981         type.store(method, slot);
 982     }
 983 
 984     /**
 985      * Increment/Decrement a local integer by the given value.
 986      *
 987      * @param slot the int slot
 988      * @param increment the amount to increment
 989      */
 990     void iinc(final int slot, final int increment) {
 991         debug("iinc");
 992         method.visitIincInsn(slot, increment);
 993     }
 994 
 995     /**
 996      * Pop an exception object from the stack and generate code
 997      * for throwing it
 998      */
 999     public void athrow() {
1000         debug("athrow");
1001         final Type receiver = popType(Type.OBJECT);
1002         assert receiver.isObject();
1003         method.visitInsn(ATHROW);
1004         stack = null;
1005     }
1006 
1007     /**
1008      * Pop an object from the stack and perform an instanceof
1009      * operation, given a classDescriptor to compare it to.
1010      * Push the boolean result 1/0 as an int to the stack
1011      *
1012      * @param classDescriptor descriptor of the class to type check against
1013      *
1014      * @return the method emitter
1015      */
1016     MethodEmitter _instanceof(final String classDescriptor) {
1017         debug("instanceof", classDescriptor);
1018         popType(Type.OBJECT);
1019         method.visitTypeInsn(INSTANCEOF, classDescriptor);
1020         pushType(Type.INT);
1021         return this;
1022     }
1023 
1024     /**
1025      * Pop an object from the stack and perform an instanceof
1026      * operation, given a classDescriptor to compare it to.
1027      * Push the boolean result 1/0 as an int to the stack
1028      *
1029      * @param clazz the type to check instanceof against
1030      *
1031      * @return the method emitter
1032      */
1033     MethodEmitter _instanceof(final Class<?> clazz) {
1034         return _instanceof(CompilerConstants.className(clazz));
1035     }
1036 
1037     /**
1038      * Perform a checkcast operation on the object at the top of the
1039      * stack.
1040      *
1041      * @param classDescriptor descriptor of the class to type check against
1042      *
1043      * @return the method emitter
1044      */
1045     MethodEmitter checkcast(final String classDescriptor) {
1046         debug("checkcast", classDescriptor);
1047         assert peekType().isObject();
1048         method.visitTypeInsn(CHECKCAST, classDescriptor);
1049         return this;
1050     }
1051 
1052     /**
1053      * Perform a checkcast operation on the object at the top of the
1054      * stack.
1055      *
1056      * @param clazz class to checkcast against
1057      *
1058      * @return the method emitter
1059      */
1060     MethodEmitter checkcast(final Class<?> clazz) {
1061         return checkcast(CompilerConstants.className(clazz));
1062     }
1063 
1064     /**
1065      * Instantiate a new array given a length that is popped
1066      * from the stack and the array type
1067      *
1068      * @param arrayType the type of the array
1069      *
1070      * @return the method emitter
1071      */
1072     MethodEmitter newarray(final ArrayType arrayType) {
1073         debug("newarray ", "arrayType=", arrayType);
1074         popType(Type.INT); //LENGTH
1075         pushType(arrayType.newarray(method));
1076         return this;
1077     }
1078 
1079     /**
1080      * Instantiate a multidimensional array with a given number of dimensions.
1081      * On the stack are dim lengths of the sub arrays.
1082      *
1083      * @param arrayType type of the array
1084      * @param dims      number of dimensions
1085      *
1086      * @return the method emitter
1087      */
1088     MethodEmitter multinewarray(final ArrayType arrayType, final int dims) {
1089         debug("multianewarray ", arrayType, dims);
1090         for (int i = 0; i < dims; i++) {
1091             popType(Type.INT); //LENGTH
1092         }
1093         pushType(arrayType.newarray(method, dims));
1094         return this;
1095     }
1096 
1097     /**
1098      * Helper function to pop and type check the appropriate arguments
1099      * from the stack given a method signature
1100      *
1101      * @param signature method signature
1102      *
1103      * @return return type of method
1104      */
1105     private Type fixParamStack(final String signature) {
1106         final Type[] params = Type.getMethodArguments(signature);
1107         for (int i = params.length - 1; i >= 0; i--) {
1108             popType(params[i]);
1109         }
1110         final Type returnType = Type.getMethodReturnType(signature);
1111         return returnType;
1112     }
1113 
1114     /**
1115      * Generate an invocation to a Call structure
1116      * @see CompilerConstants
1117      *
1118      * @param call the call object
1119      *
1120      * @return the method emitter
1121      */
1122     MethodEmitter invoke(final Call call) {
1123         return call.invoke(this);
1124     }
1125 
1126     private MethodEmitter invoke(final int opcode, final String className, final String methodName, final String methodDescriptor, final boolean hasReceiver) {
1127         final Type returnType = fixParamStack(methodDescriptor);
1128 
1129         if (hasReceiver) {
1130             popType(Type.OBJECT);
1131         }
1132 
1133         if (opcode == INVOKEINTERFACE) {
1134             method.visitMethodInsn(opcode, className, methodName, methodDescriptor, true);
1135         } else {
1136             method.visitMethodInsn(opcode, className, methodName, methodDescriptor, false);
1137         }
1138 
1139         if (returnType != null) {
1140             pushType(returnType);
1141         }
1142 
1143         return this;
1144     }
1145 
1146     /**
1147      * Pop receiver from stack, perform an invoke special
1148      *
1149      * @param className        class name
1150      * @param methodName       method name
1151      * @param methodDescriptor descriptor
1152      *
1153      * @return the method emitter
1154      */
1155     MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
1156         debug("invokespecial", className, ".", methodName, methodDescriptor);
1157         return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
1158     }
1159 
1160     /**
1161      * Pop receiver from stack, perform an invoke virtual, push return value if any
1162      *
1163      * @param className        class name
1164      * @param methodName       method name
1165      * @param methodDescriptor descriptor
1166      *
1167      * @return the method emitter
1168      */
1169     MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
1170         debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
1171         return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
1172     }
1173 
1174     /**
1175      * Perform an invoke static and push the return value if any
1176      *
1177      * @param className        class name
1178      * @param methodName       method name
1179      * @param methodDescriptor descriptor
1180      *
1181      * @return the method emitter
1182      */
1183     MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
1184         debug("invokestatic", className, ".", methodName, methodDescriptor);
1185         invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
1186         return this;
1187     }
1188 
1189     /**
1190      * Perform an invoke static and replace the return type if we know better, e.g. Global.allocate
1191      * that allocates an array should return an ObjectArray type as a NativeArray counts as that
1192      *
1193      * @param className        class name
1194      * @param methodName       method name
1195      * @param methodDescriptor descriptor
1196      * @param returnType       return type override
1197      *
1198      * @return the method emitter
1199      */
1200     MethodEmitter invokeStatic(final String className, final String methodName, final String methodDescriptor, final Type returnType) {
1201         invokestatic(className, methodName, methodDescriptor);
1202         popType();
1203         pushType(returnType);
1204         return this;
1205     }
1206 
1207     /**
1208      * Pop receiver from stack, perform an invoke interface and push return value if any
1209      *
1210      * @param className        class name
1211      * @param methodName       method name
1212      * @param methodDescriptor descriptor
1213      *
1214      * @return the method emitter
1215      */
1216     MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
1217         debug("invokeinterface", className, ".", methodName, methodDescriptor);
1218         return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
1219     }
1220 
1221     static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
1222         final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
1223         for (int i = 0; i < table.length; i++) {
1224             internalLabels[i] = table[i].getLabel();
1225         }
1226         return internalLabels;
1227     }
1228 
1229     /**
1230      * Generate a lookup switch, popping the switch value from the stack
1231      *
1232      * @param defaultLabel default label
1233      * @param values       case values for the table
1234      * @param table        default label
1235      */
1236     void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
1237         debug("lookupswitch", peekType());
1238         popType(Type.INT);
1239         method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
1240     }
1241 
1242     /**
1243      * Generate a table switch
1244      * @param lo            low value
1245      * @param hi            high value
1246      * @param defaultLabel  default label
1247      * @param table         label table
1248      */
1249     void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
1250         debug("tableswitch", peekType());
1251         popType(Type.INT);
1252         method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
1253     }
1254 
1255     /**
1256      * Abstraction for performing a conditional jump of any type
1257      *
1258      * @see MethodEmitter.Condition
1259      *
1260      * @param cond      the condition to test
1261      * @param trueLabel the destination label is condition is true
1262      */
1263     void conditionalJump(final Condition cond, final Label trueLabel) {
1264         conditionalJump(cond, cond != Condition.GT && cond != Condition.GE, trueLabel);
1265     }
1266 
1267     /**
1268      * Abstraction for performing a conditional jump of any type,
1269      * including a dcmpg/dcmpl semantic for doubles.
1270      *
1271      * @param cond      the condition to test
1272      * @param isCmpG    is this a dcmpg for numbers, false if it's a dcmpl
1273      * @param trueLabel the destination label if condition is true
1274      */
1275     void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
1276         if (peekType().isCategory2()) {
1277             debug("[ld]cmp isCmpG=", isCmpG);
1278             pushType(get2n().cmp(method, isCmpG));
1279             jump(Condition.toUnary(cond), trueLabel, 1);
1280         } else {
1281             debug("if", cond);
1282             jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
1283         }
1284     }
1285 
1286     MethodEmitter registerReturn() {
1287         setHasReturn();
1288         return this;
1289     }
1290 
1291     void setHasReturn() {
1292         this.hasReturn = true;
1293     }
1294 
1295     /**
1296      * Perform a non void return, popping the type from the stack
1297      *
1298      * @param type the type for the return
1299      */
1300     void _return(final Type type) {
1301         debug("return", type);
1302         assert stack.size() == 1 : "Only return value on stack allowed at return point - depth=" + stack.size() + " stack = " + stack;
1303         final Type stackType = peekType();
1304         if (!Type.areEquivalent(type, stackType)) {
1305             convert(type);
1306         }
1307         popType(type)._return(method);
1308         stack = null;
1309     }
1310 
1311     /**
1312      * Perform a return using the stack top value as the guide for the type
1313      */
1314     void _return() {
1315         _return(peekType());
1316     }
1317 
1318     /**
1319      * Perform a void return.
1320      */
1321     void returnVoid() {
1322         debug("return [void]");
1323         assert stack.isEmpty() : stack;
1324         method.visitInsn(RETURN);
1325         stack = null;
1326     }
1327 
1328     /**
1329      * Goto, possibly when splitting is taking place. If
1330      * a splitNode exists, we need to handle the case that the
1331      * jump target is another method
1332      *
1333      * @param label destination label
1334      */
1335     void splitAwareGoto(final LexicalContext lc, final Label label) {
1336         _goto(label);
1337     }
1338 
1339     /**
1340      * Perform a comparison of two number types that are popped from the stack
1341      *
1342      * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
1343      *
1344      * @return the method emitter
1345      */
1346     MethodEmitter cmp(final boolean isCmpG) {
1347         pushType(get2n().cmp(method, isCmpG));
1348         return this;
1349     }
1350 
1351     /**
1352      * Helper function for jumps, conditional or not
1353      * @param opcode  opcode for jump
1354      * @param label   destination
1355      * @param n       elements on stack to compare, 0-2
1356      */
1357     private void jump(final int opcode, final Label label, final int n) {
1358         for (int i = 0; i < n; i++) {
1359             assert peekType().isInteger() || peekType().isBoolean() || peekType().isObject() : "expecting integer type or object for jump, but found " + peekType();
1360             popType();
1361         }
1362         mergeStackTo(label);
1363         method.visitJumpInsn(opcode, label.getLabel());
1364     }
1365 
1366     /**
1367      * Generate an if_acmpeq
1368      *
1369      * @param label label to true case
1370      */
1371     void if_acmpeq(final Label label) {
1372         debug("if_acmpeq", label);
1373         jump(IF_ACMPEQ, label, 2);
1374     }
1375 
1376     /**
1377      * Generate an if_acmpne
1378      *
1379      * @param label label to true case
1380      */
1381     void if_acmpne(final Label label) {
1382         debug("if_acmpne", label);
1383         jump(IF_ACMPNE, label, 2);
1384     }
1385 
1386     /**
1387      * Generate an ifnull
1388      *
1389      * @param label label to true case
1390      */
1391     void ifnull(final Label label) {
1392         debug("ifnull", label);
1393         jump(IFNULL, label, 1);
1394     }
1395 
1396     /**
1397      * Generate an ifnonnull
1398      *
1399      * @param label label to true case
1400      */
1401     void ifnonnull(final Label label) {
1402         debug("ifnonnull", label);
1403         jump(IFNONNULL, label, 1);
1404     }
1405 
1406     /**
1407      * Generate an ifeq
1408      *
1409      * @param label label to true case
1410      */
1411     void ifeq(final Label label) {
1412         debug("ifeq ", label);
1413         jump(IFEQ, label, 1);
1414     }
1415 
1416     /**
1417      * Generate an if_icmpeq
1418      *
1419      * @param label label to true case
1420      */
1421     void if_icmpeq(final Label label) {
1422         debug("if_icmpeq", label);
1423         jump(IF_ICMPEQ, label, 2);
1424     }
1425 
1426     /**
1427      * Generate an if_ne
1428      *
1429      * @param label label to true case
1430      */
1431     void ifne(final Label label) {
1432         debug("ifne", label);
1433         jump(IFNE, label, 1);
1434     }
1435 
1436     /**
1437      * Generate an if_icmpne
1438      *
1439      * @param label label to true case
1440      */
1441     void if_icmpne(final Label label) {
1442         debug("if_icmpne", label);
1443         jump(IF_ICMPNE, label, 2);
1444     }
1445 
1446     /**
1447      * Generate an iflt
1448      *
1449      * @param label label to true case
1450      */
1451     void iflt(final Label label) {
1452         debug("iflt", label);
1453         jump(IFLT, label, 1);
1454     }
1455 
1456     /**
1457      * Generate an ifle
1458      *
1459      * @param label label to true case
1460      */
1461     void ifle(final Label label) {
1462         debug("ifle", label);
1463         jump(IFLE, label, 1);
1464     }
1465 
1466     /**
1467      * Generate an ifgt
1468      *
1469      * @param label label to true case
1470      */
1471     void ifgt(final Label label) {
1472         debug("ifgt", label);
1473         jump(IFGT, label, 1);
1474     }
1475 
1476     /**
1477      * Generate an ifge
1478      *
1479      * @param label label to true case
1480      */
1481     void ifge(final Label label) {
1482         debug("ifge", label);
1483         jump(IFGE, label, 1);
1484     }
1485 
1486     /**
1487      * Unconditional jump to a label
1488      *
1489      * @param label destination label
1490      */
1491     void _goto(final Label label) {
1492         //debug("goto", label);
1493         jump(GOTO, label, 0);
1494         stack = null; //whoever reaches the point after us provides the stack, because we don't
1495     }
1496 
1497     /**
1498      * Examine two stacks and make sure they are of the same size and their
1499      * contents are equivalent to each other
1500      * @param s0 first stack
1501      * @param s1 second stack
1502      *
1503      * @return true if stacks are equivalent, false otherwise
1504      */
1505     /**
1506      * A join in control flow - helper function that makes sure all entry stacks
1507      * discovered for the join point so far are equivalent
1508      *
1509      * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
1510      * we have never been here before. Then we are expected to carry a stack with us.
1511      *
1512      * @param label label
1513      */
1514     private void mergeStackTo(final Label label) {
1515         //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
1516         //see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
1517         //by Lower removing everything after an unconditionally executed terminating statement OR a break
1518         //or continue in a block. Previously code left over after breaks and continues was still there
1519         //and caused bytecode to be generated - which crashed on stack not being there, as the merge
1520         //was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
1521         //ATHROW sequences instead of no code being generated at all. This should now be fixed.
1522         assert stack != null : label + " entered with no stack. deadcode that remains?";
1523 
1524         final Label.Stack labelStack = label.getStack();
1525         if (labelStack == null) {
1526             label.setStack(stack.copy());
1527             return;
1528         }
1529         assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
1530     }
1531 
1532     /**
1533      * Register a new label, enter it here.
1534      *
1535      * @param label the label
1536      */
1537     void label(final Label label) {
1538         /*
1539          * If stack == null, this means that we came here not through a fallthrough.
1540          * E.g. a label after an athrow. Then we create a new stack if one doesn't exist
1541          * for this location already.
1542          */
1543         if (stack == null) {
1544             stack = label.getStack();
1545             if (stack == null) {
1546                 newStack();
1547             }
1548         }
1549         debug_label(label);
1550 
1551         mergeStackTo(label); //we have to merge our stack to whatever is in the label
1552 
1553         method.visitLabel(label.getLabel());
1554     }
1555 
1556     /**
1557      * Pop element from stack, convert to given type
1558      *
1559      * @param to type to convert to
1560      *
1561      * @return the method emitter
1562      */
1563     MethodEmitter convert(final Type to) {
1564         final Type type = peekType().convert(method, to);
1565         if (type != null) {
1566             if (!peekType().isEquivalentTo(to)) {
1567                 debug("convert", peekType(), "->", to);
1568             }
1569             popType();
1570             pushType(type);
1571         }
1572         return this;
1573     }
1574 
1575     /**
1576      * Helper function - expect two types that are equivalent
1577      *
1578      * @return common type
1579      */
1580     private Type get2() {
1581         final Type p0 = popType();
1582         final Type p1 = popType();
1583         assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1584         return p0;
1585     }
1586 
1587     /**
1588      * Helper function - expect two types that are integer types and equivalent
1589      *
1590      * @return common type
1591      */
1592     private BitwiseType get2i() {
1593         final BitwiseType p0 = popInteger();
1594         final BitwiseType p1 = popInteger();
1595         assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1596         return p0;
1597     }
1598 
1599     /**
1600      * Helper function - expect two types that are numbers and equivalent
1601      *
1602      * @return common type
1603      */
1604     private NumericType get2n() {
1605         final NumericType p0 = popNumeric();
1606         final NumericType p1 = popNumeric();
1607         assert p0.isEquivalentTo(p1) : "expecting equivalent types on stack but got " + p0 + " and " + p1;
1608         return p0;
1609     }
1610 
1611     /**
1612      * Pop two numbers, perform addition and push result
1613      *
1614      * @return the method emitter
1615      */
1616     MethodEmitter add() {
1617         debug("add");
1618         pushType(get2().add(method));
1619         return this;
1620     }
1621 
1622     /**
1623      * Pop two numbers, perform subtraction and push result
1624      *
1625      * @return the method emitter
1626      */
1627     MethodEmitter sub() {
1628         debug("sub");
1629         pushType(get2n().sub(method));
1630         return this;
1631     }
1632 
1633     /**
1634      * Pop two numbers, perform multiplication and push result
1635      *
1636      * @return the method emitter
1637      */
1638     MethodEmitter mul() {
1639         debug("mul ");
1640         pushType(get2n().mul(method));
1641         return this;
1642     }
1643 
1644     /**
1645      * Pop two numbers, perform division and push result
1646      *
1647      * @return the method emitter
1648      */
1649     MethodEmitter div() {
1650         debug("div");
1651         pushType(get2n().div(method));
1652         return this;
1653     }
1654 
1655     /**
1656      * Pop two numbers, calculate remainder and push result
1657      *
1658      * @return the method emitter
1659      */
1660     MethodEmitter rem() {
1661         debug("rem");
1662         pushType(get2n().rem(method));
1663         return this;
1664     }
1665 
1666     /**
1667      * Retrieve the top <tt>count</tt> types on the stack without modifying it.
1668      *
1669      * @param count number of types to return
1670      * @return array of Types
1671      */
1672     protected Type[] getTypesFromStack(final int count) {
1673         final Type[] types = new Type[count];
1674         int pos = 0;
1675         for (int i = count - 1; i >= 0; i--) {
1676             types[i] = stack.peek(pos++);
1677         }
1678 
1679         return types;
1680     }
1681 
1682     /**
1683      * Helper function to generate a function signature based on stack contents
1684      * and argument count and return type
1685      *
1686      * @param returnType return type
1687      * @param argCount   argument count
1688      *
1689      * @return function signature for stack contents
1690      */
1691     private String getDynamicSignature(final Type returnType, final int argCount) {
1692         final Type[]         paramTypes = new Type[argCount];
1693 
1694         int pos = 0;
1695         for (int i = argCount - 1; i >= 0; i--) {
1696             paramTypes[i] = stack.peek(pos++);
1697         }
1698         final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
1699         for (int i = 0; i < argCount; i++) {
1700             popType(paramTypes[argCount - i - 1]);
1701         }
1702 
1703         return descriptor;
1704     }
1705 
1706     /**
1707      * Generate a dynamic new
1708      *
1709      * @param argCount  number of arguments
1710      * @param flags     callsite flags
1711      *
1712      * @return the method emitter
1713      */
1714     MethodEmitter dynamicNew(final int argCount, final int flags) {
1715         debug("dynamic_new", "argcount=", argCount);
1716         final String signature = getDynamicSignature(Type.OBJECT, argCount);
1717         method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
1718         pushType(Type.OBJECT); //TODO fix result type
1719         return this;
1720     }
1721 
1722     /**
1723      * Generate a dynamic call
1724      *
1725      * @param returnType return type
1726      * @param argCount   number of arguments
1727      * @param flags      callsite flags
1728      *
1729      * @return the method emitter
1730      */
1731     MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
1732         debug("dynamic_call", "args=", argCount, "returnType=", returnType);
1733         final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
1734         debug("   signature", signature);
1735         method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
1736         pushType(returnType);
1737 
1738         return this;
1739     }
1740 
1741     /**
1742      * Generate a dynamic call for a runtime node
1743      *
1744      * @param name       tag for the invoke dynamic for this runtime node
1745      * @param returnType return type
1746      * @param request    RuntimeNode request
1747      *
1748      * @return the method emitter
1749      */
1750     MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
1751         debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
1752         final String signature = getDynamicSignature(returnType, request.getArity());
1753         debug("   signature", signature);
1754         method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
1755         pushType(returnType);
1756 
1757         return this;
1758     }
1759 
1760     /**
1761      * Generate dynamic getter. Pop scope from stack. Push result
1762      *
1763      * @param valueType type of the value to set
1764      * @param name      name of property
1765      * @param flags     call site flags
1766      * @param isMethod  should it prefer retrieving methods
1767      *
1768      * @return the method emitter
1769      */
1770     MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
1771         debug("dynamic_get", name, valueType);
1772 
1773         Type type = valueType;
1774         if (type.isObject() || type.isBoolean()) {
1775             type = Type.OBJECT; //promote e.g strings to object generic setter
1776         }
1777 
1778         popType(Type.SCOPE);
1779         method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
1780                 NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
1781 
1782         pushType(type);
1783 
1784         convert(valueType); //most probably a nop
1785 
1786         return this;
1787     }
1788 
1789     /**
1790      * Generate dynamic setter. Pop receiver and property from stack.
1791      *
1792      * @param valueType the type of the value to set
1793      * @param name      name of property
1794      * @param flags     call site flags
1795      */
1796      void dynamicSet(final String name, final int flags) {
1797         debug("dynamic_set", name, peekType());
1798 
1799         Type type = peekType();
1800         if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
1801             type = Type.OBJECT;
1802             convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
1803         }
1804         popType(type);
1805         popType(Type.SCOPE);
1806 
1807         method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
1808     }
1809 
1810      /**
1811      * Dynamic getter for indexed structures. Pop index and receiver from stack,
1812      * generate appropriate signatures based on types
1813      *
1814      * @param result result type for getter
1815      * @param flags call site flags for getter
1816      * @param isMethod should it prefer retrieving methods
1817      *
1818      * @return the method emitter
1819      */
1820     MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
1821         debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
1822 
1823         Type resultType = result;
1824         if (result.isBoolean()) {
1825             resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
1826         }
1827 
1828         Type index = peekType();
1829         if (index.isObject() || index.isBoolean()) {
1830             index = Type.OBJECT; //e.g. string->object
1831             convert(Type.OBJECT);
1832         }
1833         popType();
1834 
1835         popType(Type.OBJECT);
1836 
1837         final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
1838 
1839         method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod",
1840                 signature, LINKERBOOTSTRAP, flags);
1841         pushType(resultType);
1842 
1843         if (result.isBoolean()) {
1844             convert(Type.BOOLEAN);
1845         }
1846 
1847         return this;
1848     }
1849 
1850     /**
1851      * Dynamic setter for indexed structures. Pop value, index and receiver from
1852      * stack, generate appropriate signature based on types
1853      *
1854      * @param flags call site flags for setter
1855      */
1856     void dynamicSetIndex(final int flags) {
1857         debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
1858 
1859         Type value = peekType();
1860         if (value.isObject() || value.isBoolean()) {
1861             value = Type.OBJECT; //e.g. STRING->OBJECT - one descriptor for all object types
1862             convert(Type.OBJECT);
1863         }
1864         popType();
1865 
1866         Type index = peekType();
1867         if (index.isObject() || index.isBoolean()) {
1868             index = Type.OBJECT; //e.g. string->object
1869             convert(Type.OBJECT);
1870         }
1871         popType(index);
1872 
1873         final Type receiver = popType(Type.OBJECT);
1874         assert receiver.isObject();
1875 
1876         method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags);
1877     }
1878 
1879     /**
1880      * Load a key value in the proper form.
1881      *
1882      * @param key
1883      */
1884     //TODO move this and break it apart
1885     MethodEmitter loadKey(final Object key) {
1886         if (key instanceof IdentNode) {
1887             method.visitLdcInsn(((IdentNode) key).getName());
1888         } else if (key instanceof LiteralNode) {
1889             method.visitLdcInsn(((LiteralNode<?>)key).getString());
1890         } else {
1891             method.visitLdcInsn(JSType.toString(key));
1892         }
1893         pushType(Type.OBJECT); //STRING
1894         return this;
1895     }
1896 
1897      @SuppressWarnings("fallthrough")
1898      private static Type fieldType(final String desc) {
1899          switch (desc) {
1900          case "Z":
1901          case "B":
1902          case "C":
1903          case "S":
1904          case "I":
1905              return Type.INT;
1906          case "F":
1907              assert false;
1908          case "D":
1909              return Type.NUMBER;
1910          case "J":
1911              return Type.LONG;
1912          default:
1913              assert desc.startsWith("[") || desc.startsWith("L") : desc + " is not an object type";
1914              switch (desc.charAt(0)) {
1915              case 'L':
1916                  return Type.OBJECT;
1917              case '[':
1918                  return Type.typeFor(Array.newInstance(fieldType(desc.substring(1)).getTypeClass(), 0).getClass());
1919              default:
1920                  assert false;
1921              }
1922              return Type.OBJECT;
1923          }
1924      }
1925 
1926      /**
1927       * Generate get for a field access
1928       *
1929       * @param fa the field access
1930       *
1931       * @return the method emitter
1932       */
1933     MethodEmitter getField(final FieldAccess fa) {
1934         return fa.get(this);
1935     }
1936 
1937      /**
1938       * Generate set for a field access
1939       *
1940       * @param fa the field access
1941       */
1942     void putField(final FieldAccess fa) {
1943         fa.put(this);
1944     }
1945 
1946     /**
1947      * Get the value of a non-static field, pop the receiver from the stack,
1948      * push value to the stack
1949      *
1950      * @param className        class
1951      * @param fieldName        field name
1952      * @param fieldDescriptor  field descriptor
1953      *
1954      * @return the method emitter
1955      */
1956     MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
1957         debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
1958         final Type receiver = popType();
1959         assert receiver.isObject();
1960         method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
1961         pushType(fieldType(fieldDescriptor));
1962         return this;
1963     }
1964 
1965     /**
1966      * Get the value of a static field, push it to the stack
1967      *
1968      * @param className        class
1969      * @param fieldName        field name
1970      * @param fieldDescriptor  field descriptor
1971      *
1972      * @return the method emitter
1973      */
1974     MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
1975         debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
1976         method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
1977         pushType(fieldType(fieldDescriptor));
1978         return this;
1979     }
1980 
1981     /**
1982      * Pop value and field from stack and write to a non-static field
1983      *
1984      * @param className       class
1985      * @param fieldName       field name
1986      * @param fieldDescriptor field descriptor
1987      */
1988     void putField(final String className, final String fieldName, final String fieldDescriptor) {
1989         debug("putfield", "receiver=", peekType(1), "value=", peekType());
1990         popType(fieldType(fieldDescriptor));
1991         popType(Type.OBJECT);
1992         method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
1993     }
1994 
1995     /**
1996      * Pop value from stack and write to a static field
1997      *
1998      * @param className       class
1999      * @param fieldName       field name
2000      * @param fieldDescriptor field descriptor
2001      */
2002     void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
2003         debug("putfield", "value=", peekType());
2004         popType(fieldType(fieldDescriptor));
2005         method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
2006     }
2007 
2008     /**
2009      * Register line number at a label
2010      *
2011      * @param line  line number
2012      * @param label label
2013      */
2014     void lineNumber(final int line) {
2015         if (env._debug_lines) {
2016             debug_label("[LINE]", line);
2017             final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
2018             method.visitLabel(l);
2019             method.visitLineNumber(line, l);
2020         }
2021     }
2022 
2023     /*
2024      * Debugging below
2025      */
2026 
2027     private final FieldAccess ERR_STREAM       = staticField(System.class, "err", PrintStream.class);
2028     private final Call        PRINT            = virtualCallNoLookup(PrintStream.class, "print", void.class, Object.class);
2029     private final Call        PRINTLN          = virtualCallNoLookup(PrintStream.class, "println", void.class, Object.class);
2030     private final Call        PRINT_STACKTRACE = virtualCallNoLookup(Throwable.class, "printStackTrace", void.class);
2031 
2032     /**
2033      * Emit a System.err.print statement of whatever is on top of the bytecode stack
2034      */
2035      void print() {
2036          getField(ERR_STREAM);
2037          swap();
2038          convert(Type.OBJECT);
2039          invoke(PRINT);
2040      }
2041 
2042     /**
2043      * Emit a System.err.println statement of whatever is on top of the bytecode stack
2044      */
2045      void println() {
2046          getField(ERR_STREAM);
2047          swap();
2048          convert(Type.OBJECT);
2049          invoke(PRINTLN);
2050      }
2051 
2052      /**
2053       * Emit a System.err.print statement
2054       * @param string string to print
2055       */
2056      void print(final String string) {
2057          getField(ERR_STREAM);
2058          load(string);
2059          invoke(PRINT);
2060      }
2061 
2062      /**
2063       * Emit a System.err.println statement
2064       * @param string string to print
2065       */
2066      void println(final String string) {
2067          getField(ERR_STREAM);
2068          load(string);
2069          invoke(PRINTLN);
2070      }
2071 
2072      /**
2073       * Print a stacktrace to S
2074       */
2075      void stacktrace() {
2076          _new(Throwable.class);
2077          dup();
2078          invoke(constructorNoLookup(Throwable.class));
2079          invoke(PRINT_STACKTRACE);
2080      }
2081 
2082     private static int linePrefix = 0;
2083 
2084     /**
2085      * Debug function that outputs generated bytecode and stack contents
2086      *
2087      * @param args debug information to print
2088      */
2089     private void debug(final Object... args) {
2090         if (DEBUG) {
2091             debug(30, args);
2092         }
2093     }
2094 
2095     /**
2096      * Debug function that outputs generated bytecode and stack contents
2097      * for a label - indentation is currently the only thing that differs
2098      *
2099      * @param args debug information to print
2100      */
2101     private void debug_label(final Object... args) {
2102         if (DEBUG) {
2103             debug(22, args);
2104         }
2105     }
2106 
2107     private void debug(final int padConstant, final Object... args) {
2108         if (DEBUG) {
2109             final StringBuilder sb = new StringBuilder();
2110             int pad;
2111 
2112             sb.append('#');
2113             sb.append(++linePrefix);
2114 
2115             pad = 5 - sb.length();
2116             while (pad > 0) {
2117                 sb.append(' ');
2118                 pad--;
2119             }
2120 
2121             if (stack != null && !stack.isEmpty()) {
2122                 sb.append("{");
2123                 sb.append(stack.size());
2124                 sb.append(":");
2125                 for (int pos = 0; pos < stack.size(); pos++) {
2126                     final Type t = stack.peek(pos);
2127 
2128                     if (t == Type.SCOPE) {
2129                         sb.append("scope");
2130                     } else if (t == Type.THIS) {
2131                         sb.append("this");
2132                     } else if (t.isObject()) {
2133                         String desc = t.getDescriptor();
2134                         int i;
2135                         for (i = 0; desc.charAt(i) == '[' && i < desc.length(); i++) {
2136                             sb.append('[');
2137                         }
2138                         desc = desc.substring(i);
2139                         final int slash = desc.lastIndexOf('/');
2140                         if (slash != -1) {
2141                             desc = desc.substring(slash + 1, desc.length() - 1);
2142                         }
2143                         if ("Object".equals(desc)) {
2144                             sb.append('O');
2145                         } else {
2146                             sb.append(desc);
2147                         }
2148                     } else {
2149                         sb.append(t.getDescriptor());
2150                     }
2151 
2152                     if (pos + 1 < stack.size()) {
2153                         sb.append(' ');
2154                     }
2155                 }
2156                 sb.append('}');
2157                 sb.append(' ');
2158             }
2159 
2160             pad = padConstant - sb.length();
2161             while (pad > 0) {
2162                 sb.append(' ');
2163                 pad--;
2164             }
2165 
2166             for (final Object arg : args) {
2167                 sb.append(arg);
2168                 sb.append(' ');
2169             }
2170 
2171             if (env != null) { //early bootstrap code doesn't have inited context yet
2172                 LOG.info(sb);
2173                 if (DEBUG_TRACE_LINE == linePrefix) {
2174                     new Throwable().printStackTrace(LOG.getOutputStream());
2175                 }
2176             }
2177         }
2178     }
2179 
2180     /**
2181      * Set the current function node being emitted
2182      * @param functionNode the function node
2183      */
2184     void setFunctionNode(final FunctionNode functionNode) {
2185         this.functionNode = functionNode;
2186     }
2187 
2188     boolean hasReturn() {
2189         return hasReturn;
2190     }
2191 
2192     List<Label> getExternalTargets() {
2193         return null;
2194     }
2195 
2196 }