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 }