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