1 /* 2 * Copyright (c) 1999, 2025, 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 com.sun.tools.javac.jvm; 27 28 import com.sun.tools.javac.code.*; 29 import com.sun.tools.javac.code.Symbol.*; 30 import com.sun.tools.javac.resources.CompilerProperties.Errors; 31 import com.sun.tools.javac.util.*; 32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 33 34 import java.util.function.ToIntBiFunction; 35 36 import static com.sun.tools.javac.code.TypeTag.BOT; 37 import static com.sun.tools.javac.code.TypeTag.DOUBLE; 38 import static com.sun.tools.javac.code.TypeTag.INT; 39 import static com.sun.tools.javac.code.TypeTag.LONG; 40 import static com.sun.tools.javac.jvm.ByteCodes.*; 41 import static com.sun.tools.javac.jvm.UninitializedType.*; 42 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableEntry; 43 import java.util.Arrays; 44 import java.util.Map; 45 import java.util.HashMap; 46 import java.util.Set; 47 48 /** An internal structure that corresponds to the code attribute of 49 * methods in a classfile. The class also provides some utility operations to 50 * generate bytecode instructions. 51 * 52 * <p><b>This is NOT part of any supported API. 53 * If you write code that depends on this, you do so at your own risk. 54 * This code and its internal interfaces are subject to change or 55 * deletion without notice.</b> 56 */ 57 public class Code { 58 59 public final boolean debugCode; 60 public final boolean needStackMap; 61 62 public enum StackMapFormat { 63 NONE, 64 CLDC { 65 Name getAttributeName(Names names) { 66 return names.StackMap; 67 } 68 }, 69 JSR202 { 70 Name getAttributeName(Names names) { 71 return names.StackMapTable; 72 } 73 }; 74 Name getAttributeName(Names names) { 75 return names.empty; 76 } 77 } 78 79 final Types types; 80 final Symtab syms; 81 final PoolWriter poolWriter; 82 83 /*---------- classfile fields: --------------- */ 84 85 /** The maximum stack size. 86 */ 87 public int max_stack = 0; 88 89 /** The maximum number of local variable slots. 90 */ 91 public int max_locals = 0; 92 93 /** The code buffer. 94 */ 95 public byte[] code = new byte[64]; 96 97 /** the current code pointer. 98 */ 99 public int cp = 0; 100 101 /** Check the code against VM spec limits; if 102 * problems report them and return true. 103 */ 104 public boolean checkLimits(DiagnosticPosition pos, Log log) { 105 if (cp > ClassFile.MAX_CODE) { 106 log.error(pos, Errors.LimitCode); 107 return true; 108 } 109 if (max_locals > ClassFile.MAX_LOCALS) { 110 log.error(pos, Errors.LimitLocals); 111 return true; 112 } 113 if (max_stack > ClassFile.MAX_STACK) { 114 log.error(pos, Errors.LimitStack); 115 return true; 116 } 117 return false; 118 } 119 120 /** A buffer for expression catch data. Each enter is a vector 121 * of four unsigned shorts. 122 */ 123 ListBuffer<char[]> catchInfo = new ListBuffer<>(); 124 125 /** A buffer for line number information. Each entry is a vector 126 * of two unsigned shorts. 127 */ 128 List<char[]> lineInfo = List.nil(); // handled in stack fashion 129 130 /** The CharacterRangeTable 131 */ 132 public CRTable crt; 133 134 /*---------- internal fields: --------------- */ 135 136 /** Are we generating code with jumps ≥ 32K? 137 */ 138 public boolean fatcode; 139 140 /** Code generation enabled? 141 */ 142 private boolean alive = true; 143 144 /** The current machine state (registers and stack). 145 */ 146 State state; 147 148 /** Is it forbidden to compactify code, because something is 149 * pointing to current location? 150 */ 151 private boolean fixedPc = false; 152 153 /** The next available register. 154 */ 155 public int nextreg = 0; 156 157 /** A chain for jumps to be resolved before the next opcode is emitted. 158 * We do this lazily to avoid jumps to jumps. 159 */ 160 Chain pendingJumps = null; 161 162 /** The position of the currently statement, if we are at the 163 * start of this statement, NOPOS otherwise. 164 * We need this to emit line numbers lazily, which we need to do 165 * because of jump-to-jump optimization. 166 */ 167 int pendingStatPos = Position.NOPOS; 168 169 /** Set true when a stackMap is needed at the current PC. */ 170 boolean pendingStackMap = false; 171 172 /** The stack map format to be generated. */ 173 StackMapFormat stackMap; 174 175 /** Switch: emit variable debug info. 176 */ 177 boolean varDebugInfo; 178 179 /** Switch: emit line number info. 180 */ 181 boolean lineDebugInfo; 182 183 /** Emit line number info if map supplied 184 */ 185 Position.LineMap lineMap; 186 187 final MethodSymbol meth; 188 189 private int letExprStackPos = 0; 190 191 private Map<Integer, Set<VarSymbol>> cpToUnsetFieldsMap = new HashMap<>(); 192 193 public Set<VarSymbol> initialUnsetFields; 194 195 public Set<VarSymbol> currentUnsetFields; 196 197 boolean generateAssertUnsetFieldsFrame; 198 199 /** Construct a code object, given the settings of the fatcode, 200 * debugging info switches and the CharacterRangeTable. 201 */ 202 public Code(MethodSymbol meth, 203 boolean fatcode, 204 Position.LineMap lineMap, 205 boolean varDebugInfo, 206 StackMapFormat stackMap, 207 boolean debugCode, 208 CRTable crt, 209 Symtab syms, 210 Types types, 211 PoolWriter poolWriter, 212 boolean generateAssertUnsetFieldsFrame) { 213 this.meth = meth; 214 this.fatcode = fatcode; 215 this.lineMap = lineMap; 216 this.lineDebugInfo = lineMap != null; 217 this.varDebugInfo = varDebugInfo; 218 this.crt = crt; 219 this.syms = syms; 220 this.types = types; 221 this.poolWriter = poolWriter; 222 this.debugCode = debugCode; 223 this.stackMap = stackMap; 224 switch (stackMap) { 225 case CLDC: 226 case JSR202: 227 this.needStackMap = true; 228 break; 229 default: 230 this.needStackMap = false; 231 } 232 state = new State(); 233 lvar = new LocalVar[20]; 234 this.generateAssertUnsetFieldsFrame = generateAssertUnsetFieldsFrame; 235 } 236 237 238 /* ************************************************************************** 239 * Typecodes & related stuff 240 ****************************************************************************/ 241 242 /** Given a type, return its type code (used implicitly in the 243 * JVM architecture). 244 */ 245 public static int typecode(Type type) { 246 switch (type.getTag()) { 247 case BYTE: return BYTEcode; 248 case SHORT: return SHORTcode; 249 case CHAR: return CHARcode; 250 case INT: return INTcode; 251 case LONG: return LONGcode; 252 case FLOAT: return FLOATcode; 253 case DOUBLE: return DOUBLEcode; 254 case BOOLEAN: return BYTEcode; 255 case VOID: return VOIDcode; 256 case CLASS: 257 case ARRAY: 258 case METHOD: 259 case BOT: 260 case TYPEVAR: 261 case UNINITIALIZED_THIS: 262 case UNINITIALIZED_OBJECT: 263 return OBJECTcode; 264 default: throw new AssertionError("typecode " + type.getTag()); 265 } 266 } 267 268 /** Collapse type code for subtypes of int to INTcode. 269 */ 270 public static int truncate(int tc) { 271 switch (tc) { 272 case BYTEcode: case SHORTcode: case CHARcode: return INTcode; 273 default: return tc; 274 } 275 } 276 277 /** The width in bytes of objects of the type. 278 */ 279 public static int width(int typecode) { 280 switch (typecode) { 281 case LONGcode: case DOUBLEcode: return 2; 282 case VOIDcode: return 0; 283 default: return 1; 284 } 285 } 286 287 public static int width(Type type) { 288 return type == null ? 1 : width(typecode(type)); 289 } 290 291 /** The total width taken up by a vector of objects. 292 */ 293 public static int width(List<Type> types) { 294 int w = 0; 295 for (List<Type> l = types; l.nonEmpty(); l = l.tail) 296 w = w + width(l.head); 297 return w; 298 } 299 300 /** Given a type, return its code for allocating arrays of that type. 301 */ 302 public static int arraycode(Type type) { 303 switch (type.getTag()) { 304 case BYTE: return 8; 305 case BOOLEAN: return 4; 306 case SHORT: return 9; 307 case CHAR: return 5; 308 case INT: return 10; 309 case LONG: return 11; 310 case FLOAT: return 6; 311 case DOUBLE: return 7; 312 case CLASS: return 0; 313 case ARRAY: return 1; 314 default: throw new AssertionError("arraycode " + type); 315 } 316 } 317 318 319 /* ************************************************************************** 320 * Emit code 321 ****************************************************************************/ 322 323 /** The current output code pointer. 324 */ 325 public int curCP() { 326 /* 327 * This method has side-effects because calling it can indirectly provoke 328 * extra code generation, like goto instructions, depending on the context 329 * where it's called. 330 * Use with care or even better avoid using it. 331 */ 332 if (pendingJumps != null) { 333 resolvePending(); 334 } 335 if (pendingStatPos != Position.NOPOS) { 336 markStatBegin(); 337 } 338 fixedPc = true; 339 return cp; 340 } 341 342 /** Emit a byte of code. 343 */ 344 private void emit1(int od) { 345 if (!alive) return; 346 code = ArrayUtils.ensureCapacity(code, cp); 347 code[cp++] = (byte)od; 348 } 349 350 /** Emit two bytes of code. 351 */ 352 private void emit2(int od) { 353 if (!alive) return; 354 if (cp + 2 > code.length) { 355 emit1(od >> 8); 356 emit1(od); 357 } else { 358 code[cp++] = (byte)(od >> 8); 359 code[cp++] = (byte)od; 360 } 361 } 362 363 /** Emit four bytes of code. 364 */ 365 public void emit4(int od) { 366 if (!alive) return; 367 if (cp + 4 > code.length) { 368 emit1(od >> 24); 369 emit1(od >> 16); 370 emit1(od >> 8); 371 emit1(od); 372 } else { 373 code[cp++] = (byte)(od >> 24); 374 code[cp++] = (byte)(od >> 16); 375 code[cp++] = (byte)(od >> 8); 376 code[cp++] = (byte)od; 377 } 378 } 379 380 /** Emit an opcode. 381 */ 382 private void emitop(int op) { 383 if (pendingJumps != null) resolvePending(); 384 if (alive) { 385 if (pendingStatPos != Position.NOPOS) 386 markStatBegin(); 387 if (pendingStackMap) { 388 pendingStackMap = false; 389 emitStackMap(); 390 } 391 if (debugCode) 392 System.err.println("emit@" + cp + " stack=" + 393 state.stacksize + ": " + 394 mnem(op)); 395 emit1(op); 396 } 397 } 398 399 void postop() { 400 Assert.check(alive || isStatementStart()); 401 } 402 403 /** Emit a ldc (or ldc_w) instruction, taking into account operand size 404 */ 405 public void emitLdc(LoadableConstant constant) { 406 int od = poolWriter.putConstant(constant); 407 Type constantType = types.constantType(constant); 408 if (constantType.hasTag(LONG) || constantType.hasTag(DOUBLE)) { 409 emitop2(ldc2w, od, constant); 410 } else if (od <= 255) { 411 emitop1(ldc1, od, constant); 412 } else { 413 emitop2(ldc2, od, constant); 414 } 415 } 416 417 /** Emit a multinewarray instruction. 418 */ 419 public void emitMultianewarray(int ndims, int type, Type arrayType) { 420 emitop(multianewarray); 421 if (!alive) return; 422 emit2(type); 423 emit1(ndims); 424 state.pop(ndims); 425 state.push(arrayType); 426 } 427 428 /** Emit newarray. 429 */ 430 public void emitNewarray(int elemcode, Type arrayType) { 431 emitop(newarray); 432 if (!alive) return; 433 emit1(elemcode); 434 state.pop(1); // count 435 state.push(arrayType); 436 } 437 438 /** Emit anewarray. 439 */ 440 public void emitAnewarray(int od, Type arrayType) { 441 emitop(anewarray); 442 if (!alive) return; 443 emit2(od); 444 state.pop(1); 445 state.push(arrayType); 446 } 447 448 /** Emit an invokeinterface instruction. 449 */ 450 public void emitInvokeinterface(Symbol member, Type mtype) { 451 int argsize = width(mtype.getParameterTypes()); 452 emitop(invokeinterface); 453 if (!alive) return; 454 emit2(poolWriter.putMember(member)); 455 emit1(argsize + 1); 456 emit1(0); 457 state.pop(argsize + 1); 458 state.push(mtype.getReturnType()); 459 } 460 461 /** Emit an invokespecial instruction. 462 */ 463 public void emitInvokespecial(Symbol member, Type mtype) { 464 int argsize = width(mtype.getParameterTypes()); 465 emitop(invokespecial); 466 if (!alive) return; 467 emit2(poolWriter.putMember(member)); 468 state.pop(argsize); 469 if (member.isConstructor()) 470 state.markInitialized((UninitializedType)state.peek()); 471 state.pop(1); 472 state.push(mtype.getReturnType()); 473 } 474 475 /** Emit an invokestatic instruction. 476 */ 477 public void emitInvokestatic(Symbol member, Type mtype) { 478 int argsize = width(mtype.getParameterTypes()); 479 emitop(invokestatic); 480 if (!alive) return; 481 emit2(poolWriter.putMember(member)); 482 state.pop(argsize); 483 state.push(mtype.getReturnType()); 484 } 485 486 /** Emit an invokevirtual instruction. 487 */ 488 public void emitInvokevirtual(Symbol member, Type mtype) { 489 int argsize = width(mtype.getParameterTypes()); 490 emitop(invokevirtual); 491 if (!alive) return; 492 emit2(poolWriter.putMember(member)); 493 state.pop(argsize + 1); 494 state.push(mtype.getReturnType()); 495 } 496 497 /** Emit an invokedynamic instruction. 498 */ 499 public void emitInvokedynamic(DynamicMethodSymbol dynMember, Type mtype) { 500 int argsize = width(mtype.getParameterTypes()); 501 emitop(invokedynamic); 502 if (!alive) return; 503 emit2(poolWriter.putDynamic(dynMember)); 504 emit2(0); 505 state.pop(argsize); 506 state.push(mtype.getReturnType()); 507 } 508 509 /** Emit an opcode with no operand field. 510 */ 511 public void emitop0(int op) { 512 emitop(op); 513 if (!alive) return; 514 switch (op) { 515 case aaload: { 516 state.pop(1);// index 517 Type a = state.stack[state.stacksize-1]; 518 Assert.check(!a.hasTag(BOT)); // null type as is cannot be indexed. 519 state.pop(1); 520 state.push(types.erasure(types.elemtype(a))); } 521 break; 522 case goto_: 523 markDead(); 524 break; 525 case nop: 526 case ineg: 527 case lneg: 528 case fneg: 529 case dneg: 530 break; 531 case aconst_null: 532 state.push(syms.botType); 533 break; 534 case iconst_m1: 535 case iconst_0: 536 case iconst_1: 537 case iconst_2: 538 case iconst_3: 539 case iconst_4: 540 case iconst_5: 541 case iload_0: 542 case iload_1: 543 case iload_2: 544 case iload_3: 545 state.push(syms.intType); 546 break; 547 case lconst_0: 548 case lconst_1: 549 case lload_0: 550 case lload_1: 551 case lload_2: 552 case lload_3: 553 state.push(syms.longType); 554 break; 555 case fconst_0: 556 case fconst_1: 557 case fconst_2: 558 case fload_0: 559 case fload_1: 560 case fload_2: 561 case fload_3: 562 state.push(syms.floatType); 563 break; 564 case dconst_0: 565 case dconst_1: 566 case dload_0: 567 case dload_1: 568 case dload_2: 569 case dload_3: 570 state.push(syms.doubleType); 571 break; 572 case aload_0: 573 state.push(lvar[0].sym.type); 574 break; 575 case aload_1: 576 state.push(lvar[1].sym.type); 577 break; 578 case aload_2: 579 state.push(lvar[2].sym.type); 580 break; 581 case aload_3: 582 state.push(lvar[3].sym.type); 583 break; 584 case iaload: 585 case baload: 586 case caload: 587 case saload: 588 state.pop(2); 589 state.push(syms.intType); 590 break; 591 case laload: 592 state.pop(2); 593 state.push(syms.longType); 594 break; 595 case faload: 596 state.pop(2); 597 state.push(syms.floatType); 598 break; 599 case daload: 600 state.pop(2); 601 state.push(syms.doubleType); 602 break; 603 case istore_0: 604 case istore_1: 605 case istore_2: 606 case istore_3: 607 case fstore_0: 608 case fstore_1: 609 case fstore_2: 610 case fstore_3: 611 case astore_0: 612 case astore_1: 613 case astore_2: 614 case astore_3: 615 case pop: 616 case lshr: 617 case lshl: 618 case lushr: 619 state.pop(1); 620 break; 621 case areturn: 622 case ireturn: 623 case freturn: 624 Assert.check(state.nlocks == 0); 625 state.pop(1); 626 markDead(); 627 break; 628 case athrow: 629 state.pop(state.stacksize); 630 markDead(); 631 break; 632 case lstore_0: 633 case lstore_1: 634 case lstore_2: 635 case lstore_3: 636 case dstore_0: 637 case dstore_1: 638 case dstore_2: 639 case dstore_3: 640 case pop2: 641 state.pop(2); 642 break; 643 case lreturn: 644 case dreturn: 645 Assert.check(state.nlocks == 0); 646 state.pop(2); 647 markDead(); 648 break; 649 case dup: 650 state.push(state.stack[state.stacksize-1]); 651 break; 652 case return_: 653 Assert.check(state.nlocks == 0); 654 markDead(); 655 break; 656 case arraylength: 657 state.pop(1); 658 state.push(syms.intType); 659 break; 660 case isub: 661 case iadd: 662 case imul: 663 case idiv: 664 case imod: 665 case ishl: 666 case ishr: 667 case iushr: 668 case iand: 669 case ior: 670 case ixor: 671 state.pop(1); 672 // state.pop(1); 673 // state.push(syms.intType); 674 break; 675 case aastore: 676 state.pop(3); 677 break; 678 case land: 679 case lor: 680 case lxor: 681 case lmod: 682 case ldiv: 683 case lmul: 684 case lsub: 685 case ladd: 686 state.pop(2); 687 break; 688 case lcmp: 689 state.pop(4); 690 state.push(syms.intType); 691 break; 692 case l2i: 693 state.pop(2); 694 state.push(syms.intType); 695 break; 696 case i2l: 697 state.pop(1); 698 state.push(syms.longType); 699 break; 700 case i2f: 701 state.pop(1); 702 state.push(syms.floatType); 703 break; 704 case i2d: 705 state.pop(1); 706 state.push(syms.doubleType); 707 break; 708 case l2f: 709 state.pop(2); 710 state.push(syms.floatType); 711 break; 712 case l2d: 713 state.pop(2); 714 state.push(syms.doubleType); 715 break; 716 case f2i: 717 state.pop(1); 718 state.push(syms.intType); 719 break; 720 case f2l: 721 state.pop(1); 722 state.push(syms.longType); 723 break; 724 case f2d: 725 state.pop(1); 726 state.push(syms.doubleType); 727 break; 728 case d2i: 729 state.pop(2); 730 state.push(syms.intType); 731 break; 732 case d2l: 733 state.pop(2); 734 state.push(syms.longType); 735 break; 736 case d2f: 737 state.pop(2); 738 state.push(syms.floatType); 739 break; 740 case tableswitch: 741 case lookupswitch: 742 state.pop(1); 743 // the caller is responsible for patching up the state 744 break; 745 case dup_x1: { 746 Type val1 = state.pop1(); 747 Type val2 = state.pop1(); 748 state.push(val1); 749 state.push(val2); 750 state.push(val1); 751 break; 752 } 753 case bastore: 754 state.pop(3); 755 break; 756 case int2byte: 757 case int2char: 758 case int2short: 759 break; 760 case fmul: 761 case fadd: 762 case fsub: 763 case fdiv: 764 case fmod: 765 state.pop(1); 766 break; 767 case castore: 768 case iastore: 769 case fastore: 770 case sastore: 771 state.pop(3); 772 break; 773 case lastore: 774 case dastore: 775 state.pop(4); 776 break; 777 case dup2: 778 if (state.stack[state.stacksize-1] != null) { 779 Type value1 = state.pop1(); 780 Type value2 = state.pop1(); 781 state.push(value2); 782 state.push(value1); 783 state.push(value2); 784 state.push(value1); 785 } else { 786 Type value = state.pop2(); 787 state.push(value); 788 state.push(value); 789 } 790 break; 791 case dup2_x1: 792 if (state.stack[state.stacksize-1] != null) { 793 Type value1 = state.pop1(); 794 Type value2 = state.pop1(); 795 Type value3 = state.pop1(); 796 state.push(value2); 797 state.push(value1); 798 state.push(value3); 799 state.push(value2); 800 state.push(value1); 801 } else { 802 Type value1 = state.pop2(); 803 Type value2 = state.pop1(); 804 state.push(value1); 805 state.push(value2); 806 state.push(value1); 807 } 808 break; 809 case dup2_x2: 810 if (state.stack[state.stacksize-1] != null) { 811 Type value1 = state.pop1(); 812 Type value2 = state.pop1(); 813 if (state.stack[state.stacksize-1] != null) { 814 // form 1 815 Type value3 = state.pop1(); 816 Type value4 = state.pop1(); 817 state.push(value2); 818 state.push(value1); 819 state.push(value4); 820 state.push(value3); 821 state.push(value2); 822 state.push(value1); 823 } else { 824 // form 3 825 Type value3 = state.pop2(); 826 state.push(value2); 827 state.push(value1); 828 state.push(value3); 829 state.push(value2); 830 state.push(value1); 831 } 832 } else { 833 Type value1 = state.pop2(); 834 if (state.stack[state.stacksize-1] != null) { 835 // form 2 836 Type value2 = state.pop1(); 837 Type value3 = state.pop1(); 838 state.push(value1); 839 state.push(value3); 840 state.push(value2); 841 state.push(value1); 842 } else { 843 // form 4 844 Type value2 = state.pop2(); 845 state.push(value1); 846 state.push(value2); 847 state.push(value1); 848 } 849 } 850 break; 851 case dup_x2: { 852 Type value1 = state.pop1(); 853 if (state.stack[state.stacksize-1] != null) { 854 // form 1 855 Type value2 = state.pop1(); 856 Type value3 = state.pop1(); 857 state.push(value1); 858 state.push(value3); 859 state.push(value2); 860 state.push(value1); 861 } else { 862 // form 2 863 Type value2 = state.pop2(); 864 state.push(value1); 865 state.push(value2); 866 state.push(value1); 867 } 868 } 869 break; 870 case fcmpl: 871 case fcmpg: 872 state.pop(2); 873 state.push(syms.intType); 874 break; 875 case dcmpl: 876 case dcmpg: 877 state.pop(4); 878 state.push(syms.intType); 879 break; 880 case swap: { 881 Type value1 = state.pop1(); 882 Type value2 = state.pop1(); 883 state.push(value1); 884 state.push(value2); 885 break; 886 } 887 case dadd: 888 case dsub: 889 case dmul: 890 case ddiv: 891 case dmod: 892 state.pop(2); 893 break; 894 case ret: 895 markDead(); 896 break; 897 case wide: 898 // must be handled by the caller. 899 return; 900 case monitorenter: 901 case monitorexit: 902 state.pop(1); 903 break; 904 905 default: 906 throw new AssertionError(mnem(op)); 907 } 908 postop(); 909 } 910 911 /** Emit an opcode with a one-byte operand field. 912 */ 913 public void emitop1(int op, int od) { 914 emitop1(op, od, null); 915 } 916 917 public void emitop1(int op, int od, PoolConstant data) { 918 emitop(op); 919 if (!alive) return; 920 emit1(od); 921 switch (op) { 922 case bipush: 923 state.push(syms.intType); 924 break; 925 case ldc1: 926 state.push(types.constantType((LoadableConstant)data)); 927 break; 928 default: 929 throw new AssertionError(mnem(op)); 930 } 931 postop(); 932 } 933 934 /** Emit an opcode with a one-byte operand field; 935 * widen if field does not fit in a byte. 936 */ 937 public void emitop1w(int op, int od) { 938 if (od > 0xFF) { 939 emitop(wide); 940 emitop(op); 941 emit2(od); 942 } else { 943 emitop(op); 944 emit1(od); 945 } 946 if (!alive) return; 947 switch (op) { 948 case iload: 949 state.push(syms.intType); 950 break; 951 case lload: 952 state.push(syms.longType); 953 break; 954 case fload: 955 state.push(syms.floatType); 956 break; 957 case dload: 958 state.push(syms.doubleType); 959 break; 960 case aload: 961 state.push(lvar[od].sym.type); 962 break; 963 case lstore: 964 case dstore: 965 state.pop(2); 966 break; 967 case istore: 968 case fstore: 969 case astore: 970 state.pop(1); 971 break; 972 case ret: 973 markDead(); 974 break; 975 default: 976 throw new AssertionError(mnem(op)); 977 } 978 postop(); 979 } 980 981 /** Emit an opcode with two one-byte operand fields; 982 * widen if either field does not fit in a byte. 983 */ 984 public void emitop1w(int op, int od1, int od2) { 985 if (od1 > 0xFF || od2 < -128 || od2 > 127) { 986 emitop(wide); 987 emitop(op); 988 emit2(od1); 989 emit2(od2); 990 } else { 991 emitop(op); 992 emit1(od1); 993 emit1(od2); 994 } 995 if (!alive) return; 996 switch (op) { 997 case iinc: 998 break; 999 default: 1000 throw new AssertionError(mnem(op)); 1001 } 1002 } 1003 1004 /** Emit an opcode with a two-byte operand field. 1005 */ 1006 public <P extends PoolConstant> void emitop2(int op, P constant, ToIntBiFunction<PoolWriter, P> poolFunc) { 1007 int od = poolFunc.applyAsInt(poolWriter, constant); 1008 emitop2(op, od, constant); 1009 } 1010 1011 public void emitop2(int op, int od) { 1012 emitop2(op, od, null); 1013 } 1014 1015 public void emitop2(int op, int od, PoolConstant data) { 1016 emitop(op); 1017 if (!alive) return; 1018 emit2(od); 1019 switch (op) { 1020 case getstatic: 1021 state.push(((Symbol)data).erasure(types)); 1022 break; 1023 case putstatic: 1024 state.pop(((Symbol)data).erasure(types)); 1025 break; 1026 case new_: { 1027 Type t = (Type)data; 1028 state.push(uninitializedObject(t.tsym.erasure(types), cp-3)); 1029 break; 1030 } 1031 case sipush: 1032 state.push(syms.intType); 1033 break; 1034 case if_acmp_null: 1035 case if_acmp_nonnull: 1036 case ifeq: 1037 case ifne: 1038 case iflt: 1039 case ifge: 1040 case ifgt: 1041 case ifle: 1042 state.pop(1); 1043 break; 1044 case if_icmpeq: 1045 case if_icmpne: 1046 case if_icmplt: 1047 case if_icmpge: 1048 case if_icmpgt: 1049 case if_icmple: 1050 case if_acmpeq: 1051 case if_acmpne: 1052 state.pop(2); 1053 break; 1054 case goto_: 1055 markDead(); 1056 break; 1057 case putfield: 1058 state.pop(((Symbol)data).erasure(types)); 1059 state.pop(1); // object ref 1060 break; 1061 case getfield: 1062 state.pop(1); // object ref 1063 state.push(((Symbol)data).erasure(types)); 1064 break; 1065 case checkcast: { 1066 state.pop(1); // object ref 1067 Type t = types.erasure((Type)data); 1068 state.push(t); 1069 break; } 1070 case ldc2: 1071 case ldc2w: 1072 state.push(types.constantType((LoadableConstant)data)); 1073 break; 1074 case instanceof_: 1075 state.pop(1); 1076 state.push(syms.intType); 1077 break; 1078 case jsr: 1079 break; 1080 default: 1081 throw new AssertionError(mnem(op)); 1082 } 1083 // postop(); 1084 } 1085 /** Emit an opcode with a four-byte operand field. 1086 */ 1087 public void emitop4(int op, int od) { 1088 emitop(op); 1089 if (!alive) return; 1090 emit4(od); 1091 switch (op) { 1092 case goto_w: 1093 markDead(); 1094 break; 1095 case jsr_w: 1096 break; 1097 default: 1098 throw new AssertionError(mnem(op)); 1099 } 1100 // postop(); 1101 } 1102 1103 /** Align code pointer to next `incr' boundary. 1104 */ 1105 public void align(int incr) { 1106 if (alive) 1107 while (cp % incr != 0) emitop0(nop); 1108 } 1109 1110 /** Place a byte into code at address pc. 1111 * Pre: {@literal pc + 1 <= cp }. 1112 */ 1113 private void put1(int pc, int op) { 1114 code[pc] = (byte)op; 1115 } 1116 1117 /** Place two bytes into code at address pc. 1118 * Pre: {@literal pc + 2 <= cp }. 1119 */ 1120 private void put2(int pc, int od) { 1121 // pre: pc + 2 <= cp 1122 put1(pc, od >> 8); 1123 put1(pc+1, od); 1124 } 1125 1126 /** Place four bytes into code at address pc. 1127 * Pre: {@literal pc + 4 <= cp }. 1128 */ 1129 public void put4(int pc, int od) { 1130 // pre: pc + 4 <= cp 1131 put1(pc , od >> 24); 1132 put1(pc+1, od >> 16); 1133 put1(pc+2, od >> 8); 1134 put1(pc+3, od); 1135 } 1136 1137 /** Return code byte at position pc as an unsigned int. 1138 */ 1139 private int get1(int pc) { 1140 return code[pc] & 0xFF; 1141 } 1142 1143 /** Return two code bytes at position pc as an unsigned int. 1144 */ 1145 private int get2(int pc) { 1146 return (get1(pc) << 8) | get1(pc+1); 1147 } 1148 1149 /** Return four code bytes at position pc as an int. 1150 */ 1151 public int get4(int pc) { 1152 // pre: pc + 4 <= cp 1153 return 1154 (get1(pc) << 24) | 1155 (get1(pc+1) << 16) | 1156 (get1(pc+2) << 8) | 1157 (get1(pc+3)); 1158 } 1159 1160 /** Is code generation currently enabled? 1161 */ 1162 public boolean isAlive() { 1163 return alive || pendingJumps != null; 1164 } 1165 1166 /** Switch code generation on/off. 1167 */ 1168 public void markDead() { 1169 alive = false; 1170 } 1171 1172 /** Declare an entry point; return current code pointer 1173 */ 1174 public int entryPoint() { 1175 int pc = curCP(); 1176 alive = true; 1177 pendingStackMap = needStackMap; 1178 return pc; 1179 } 1180 1181 /** Declare an entry point with initial state; 1182 * return current code pointer 1183 */ 1184 public int entryPoint(State state) { 1185 int pc = curCP(); 1186 alive = true; 1187 State newState = state.dup(); 1188 setDefined(newState.defined); 1189 this.state = newState; 1190 Assert.check(state.stacksize <= max_stack); 1191 if (debugCode) System.err.println("entry point " + state); 1192 pendingStackMap = needStackMap; 1193 return pc; 1194 } 1195 1196 /** Declare an entry point with initial state plus a pushed value; 1197 * return current code pointer 1198 */ 1199 public int entryPoint(State state, Type pushed) { 1200 int pc = curCP(); 1201 alive = true; 1202 State newState = state.dup(); 1203 setDefined(newState.defined); 1204 this.state = newState; 1205 Assert.check(state.stacksize <= max_stack); 1206 this.state.push(pushed); 1207 if (debugCode) System.err.println("entry point " + state); 1208 pendingStackMap = needStackMap; 1209 return pc; 1210 } 1211 1212 public int setLetExprStackPos(int pos) { 1213 int res = letExprStackPos; 1214 letExprStackPos = pos; 1215 return res; 1216 } 1217 1218 public boolean isStatementStart() { 1219 return !alive || state.stacksize == letExprStackPos; 1220 } 1221 1222 /* ************************************************************************ 1223 * Stack map generation 1224 *************************************************************************/ 1225 1226 /** An entry in the stack map. */ 1227 static class StackMapFrame { 1228 int pc; 1229 Type[] locals; 1230 Type[] stack; 1231 Set<VarSymbol> unsetFields; 1232 } 1233 1234 /** A buffer of cldc stack map entries. */ 1235 StackMapFrame[] stackMapBuffer = null; 1236 1237 /** A buffer of compressed StackMapTable entries. */ 1238 StackMapTableEntry[] stackMapTableBuffer = null; 1239 int stackMapBufferSize = 0; 1240 1241 /** The last PC at which we generated a stack map. */ 1242 int lastStackMapPC = -1; 1243 1244 /** The last stack map frame in StackMapTable. */ 1245 StackMapFrame lastFrame = null; 1246 1247 /** The stack map frame before the last one. */ 1248 StackMapFrame frameBeforeLast = null; 1249 1250 /** Emit a stack map entry. */ 1251 public void emitStackMap() { 1252 int pc = curCP(); 1253 if (!needStackMap) return; 1254 1255 1256 1257 switch (stackMap) { 1258 case CLDC: 1259 emitCLDCStackMap(pc, getLocalsSize()); 1260 break; 1261 case JSR202: 1262 emitStackMapFrame(pc, getLocalsSize()); 1263 break; 1264 default: 1265 throw new AssertionError("Should have chosen a stackmap format"); 1266 } 1267 // DEBUG code follows 1268 if (debugCode) state.dump(pc); 1269 } 1270 1271 private int getLocalsSize() { 1272 int nextLocal = 0; 1273 for (int i=max_locals-1; i>=0; i--) { 1274 if (state.defined.isMember(i) && lvar[i] != null) { 1275 nextLocal = i + width(lvar[i].sym.erasure(types)); 1276 break; 1277 } 1278 } 1279 return nextLocal; 1280 } 1281 1282 /** Emit a CLDC stack map frame. */ 1283 void emitCLDCStackMap(int pc, int localsSize) { 1284 if (lastStackMapPC == pc) { 1285 // drop existing stackmap at this offset 1286 stackMapBuffer[--stackMapBufferSize] = null; 1287 } 1288 lastStackMapPC = pc; 1289 1290 if (stackMapBuffer == null) { 1291 stackMapBuffer = new StackMapFrame[20]; 1292 } else { 1293 stackMapBuffer = ArrayUtils.ensureCapacity(stackMapBuffer, stackMapBufferSize); 1294 } 1295 StackMapFrame frame = 1296 stackMapBuffer[stackMapBufferSize++] = new StackMapFrame(); 1297 frame.pc = pc; 1298 1299 frame.locals = new Type[localsSize]; 1300 for (int i=0; i<localsSize; i++) { 1301 if (state.defined.isMember(i) && lvar[i] != null) { 1302 Type vtype = lvar[i].sym.type; 1303 if (!(vtype instanceof UninitializedType)) 1304 vtype = types.erasure(vtype); 1305 frame.locals[i] = vtype; 1306 } 1307 } 1308 frame.stack = new Type[state.stacksize]; 1309 for (int i=0; i<state.stacksize; i++) 1310 frame.stack[i] = state.stack[i]; 1311 } 1312 1313 void emitStackMapFrame(int pc, int localsSize) { 1314 if (lastFrame == null) { 1315 // first frame 1316 lastFrame = getInitialFrame(); 1317 } else if (lastFrame.pc == pc) { 1318 // drop existing stackmap at this offset 1319 stackMapTableBuffer[--stackMapBufferSize] = null; 1320 lastFrame = frameBeforeLast; 1321 frameBeforeLast = null; 1322 } 1323 1324 StackMapFrame frame = new StackMapFrame(); 1325 frame.pc = pc; 1326 1327 int localCount = 0; 1328 Type[] locals = new Type[localsSize]; 1329 for (int i=0; i<localsSize; i++, localCount++) { 1330 if (state.defined.isMember(i) && lvar[i] != null) { 1331 Type vtype = lvar[i].sym.type; 1332 if (!(vtype instanceof UninitializedType)) 1333 vtype = types.erasure(vtype); 1334 locals[i] = vtype; 1335 if (width(vtype) > 1) i++; 1336 } 1337 } 1338 frame.locals = new Type[localCount]; 1339 for (int i=0, j=0; i<localsSize; i++, j++) { 1340 Assert.check(j < localCount); 1341 frame.locals[j] = locals[i]; 1342 if (width(locals[i]) > 1) i++; 1343 } 1344 1345 int stackCount = 0; 1346 for (int i=0; i<state.stacksize; i++) { 1347 if (state.stack[i] != null) { 1348 stackCount++; 1349 } 1350 } 1351 frame.stack = new Type[stackCount]; 1352 stackCount = 0; 1353 for (int i=0; i<state.stacksize; i++) { 1354 if (state.stack[i] != null) { 1355 frame.stack[stackCount++] = types.erasure(state.stack[i]); 1356 } 1357 } 1358 1359 Set<VarSymbol> unsetFieldsAtPC = cpToUnsetFieldsMap.get(pc); 1360 boolean generateAssertUnsetFieldsEntry = unsetFieldsAtPC != null && generateAssertUnsetFieldsFrame && !lastFrame.unsetFields.equals(unsetFieldsAtPC) ; 1361 1362 if (stackMapTableBuffer == null) { 1363 stackMapTableBuffer = new StackMapTableEntry[20]; 1364 } else { 1365 stackMapTableBuffer = ArrayUtils.ensureCapacity( 1366 stackMapTableBuffer, 1367 stackMapBufferSize + (generateAssertUnsetFieldsEntry ? 1 : 0)); 1368 } 1369 1370 if (generateAssertUnsetFieldsEntry) { 1371 stackMapTableBuffer[stackMapBufferSize++] = new StackMapTableEntry.AssertUnsetFields(pc, unsetFieldsAtPC); 1372 frame.unsetFields = unsetFieldsAtPC; 1373 } else { 1374 frame.unsetFields = lastFrame.unsetFields; 1375 } 1376 stackMapTableBuffer[stackMapBufferSize++] = 1377 StackMapTableEntry.getInstance(frame, lastFrame, types, pc); 1378 1379 frameBeforeLast = lastFrame; 1380 lastFrame = frame; 1381 } 1382 1383 public void addUnsetFieldsAtPC(int pc, Set<VarSymbol> unsetFields) { 1384 cpToUnsetFieldsMap.put(pc, unsetFields); 1385 } 1386 1387 StackMapFrame getInitialFrame() { 1388 StackMapFrame frame = new StackMapFrame(); 1389 List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes; 1390 int len = arg_types.length(); 1391 int count = 0; 1392 if (!meth.isStatic()) { 1393 Type thisType = meth.owner.type; 1394 frame.locals = new Type[len+1]; 1395 if (meth.isConstructor() && thisType != syms.objectType) { 1396 frame.locals[count++] = UninitializedType.uninitializedThis(thisType); 1397 } else { 1398 frame.locals[count++] = types.erasure(thisType); 1399 } 1400 } else { 1401 frame.locals = new Type[len]; 1402 } 1403 for (Type arg_type : arg_types) { 1404 frame.locals[count++] = types.erasure(arg_type); 1405 } 1406 frame.pc = -1; 1407 frame.stack = null; 1408 frame.unsetFields = initialUnsetFields; 1409 return frame; 1410 } 1411 1412 1413 /* ************************************************************************ 1414 * Operations having to do with jumps 1415 *************************************************************************/ 1416 1417 /** A chain represents a list of unresolved jumps. Jump locations 1418 * are sorted in decreasing order. 1419 */ 1420 public static class Chain { 1421 1422 /** The position of the jump instruction. 1423 */ 1424 public final int pc; 1425 1426 /** The machine state after the jump instruction. 1427 * Invariant: all elements of a chain list have the same stacksize 1428 * and compatible stack and register contents. 1429 */ 1430 Code.State state; 1431 1432 /** The next jump in the list. 1433 */ 1434 public final Chain next; 1435 1436 /** Construct a chain from its jump position, stacksize, previous 1437 * chain, and machine state. 1438 */ 1439 public Chain(int pc, Chain next, Code.State state) { 1440 this.pc = pc; 1441 this.next = next; 1442 this.state = state; 1443 } 1444 } 1445 1446 /** Negate a branch opcode. 1447 */ 1448 public static int negate(int opcode) { 1449 if (opcode == if_acmp_null) return if_acmp_nonnull; 1450 else if (opcode == if_acmp_nonnull) return if_acmp_null; 1451 else return ((opcode + 1) ^ 1) - 1; 1452 } 1453 1454 /** Emit a jump instruction. 1455 * Return code pointer of instruction to be patched. 1456 */ 1457 public int emitJump(int opcode) { 1458 if (fatcode) { 1459 if (opcode == goto_ || opcode == jsr) { 1460 emitop4(opcode + goto_w - goto_, 0); 1461 } else { 1462 emitop2(negate(opcode), 8); 1463 emitop4(goto_w, 0); 1464 alive = true; 1465 pendingStackMap = needStackMap; 1466 } 1467 return cp - 5; 1468 } else { 1469 emitop2(opcode, 0); 1470 return cp - 3; 1471 } 1472 } 1473 1474 /** Emit a branch with given opcode; return its chain. 1475 * branch differs from jump in that jsr is treated as no-op. 1476 */ 1477 public Chain branch(int opcode) { 1478 Chain result = null; 1479 if (opcode == goto_) { 1480 result = pendingJumps; 1481 pendingJumps = null; 1482 } 1483 if (opcode != dontgoto && isAlive()) { 1484 result = new Chain(emitJump(opcode), 1485 result, 1486 state.dup()); 1487 if (currentUnsetFields != null) { 1488 addUnsetFieldsAtPC(result.pc, currentUnsetFields); 1489 } 1490 fixedPc = fatcode; 1491 if (opcode == goto_) alive = false; 1492 } 1493 return result; 1494 } 1495 1496 /** Resolve chain to point to given target. 1497 */ 1498 public void resolve(Chain chain, int target) { 1499 boolean changed = false; 1500 State newState = state; 1501 int originalTarget = target; 1502 for (; chain != null; chain = chain.next) { 1503 Assert.check(state != chain.state 1504 && (target > chain.pc || isStatementStart())); 1505 if (target >= cp) { 1506 target = cp; 1507 } else if (get1(target) == goto_) { 1508 if (fatcode) target = target + get4(target + 1); 1509 else target = target + get2(target + 1); 1510 } 1511 if (get1(chain.pc) == goto_ && 1512 chain.pc + 3 == target && target == cp && !fixedPc) { 1513 // If goto the next instruction, the jump is not needed: 1514 // compact the code. 1515 if (varDebugInfo) { 1516 adjustAliveRanges(cp, -3); 1517 } 1518 cp = cp - 3; 1519 target = target - 3; 1520 if (chain.next == null) { 1521 // This is the only jump to the target. Exit the loop 1522 // without setting new state. The code is reachable 1523 // from the instruction before goto_. 1524 alive = true; 1525 break; 1526 } 1527 } else { 1528 if (fatcode) { 1529 put4(chain.pc + 1, target - chain.pc); 1530 if (cpToUnsetFieldsMap.get(chain.pc) != null) { 1531 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc)); 1532 } 1533 } 1534 else if (target - chain.pc < Short.MIN_VALUE || 1535 target - chain.pc > Short.MAX_VALUE) 1536 fatcode = true; 1537 else { 1538 put2(chain.pc + 1, target - chain.pc); 1539 if (cpToUnsetFieldsMap.get(chain.pc) != null) { 1540 addUnsetFieldsAtPC(originalTarget, cpToUnsetFieldsMap.get(chain.pc)); 1541 } 1542 } 1543 Assert.check(!alive || 1544 chain.state.stacksize == newState.stacksize && 1545 chain.state.nlocks == newState.nlocks); 1546 } 1547 fixedPc = true; 1548 if (cp == target) { 1549 changed = true; 1550 if (debugCode) 1551 System.err.println("resolving chain state=" + chain.state); 1552 if (alive) { 1553 newState = chain.state.join(newState); 1554 } else { 1555 newState = chain.state; 1556 alive = true; 1557 } 1558 } 1559 } 1560 Assert.check(!changed || state != newState); 1561 if (state != newState) { 1562 setDefined(newState.defined); 1563 state = newState; 1564 pendingStackMap = needStackMap; 1565 } 1566 } 1567 1568 /** Resolve chain to point to current code pointer. 1569 */ 1570 public void resolve(Chain chain) { 1571 Assert.check( 1572 !alive || 1573 chain==null || 1574 state.stacksize == chain.state.stacksize && 1575 state.nlocks == chain.state.nlocks); 1576 pendingJumps = mergeChains(chain, pendingJumps); 1577 } 1578 1579 /** Resolve any pending jumps. 1580 */ 1581 public void resolvePending() { 1582 Chain x = pendingJumps; 1583 pendingJumps = null; 1584 resolve(x, cp); 1585 } 1586 1587 /** Merge the jumps in of two chains into one. 1588 */ 1589 public static Chain mergeChains(Chain chain1, Chain chain2) { 1590 // recursive merge sort 1591 if (chain2 == null) return chain1; 1592 if (chain1 == null) return chain2; 1593 Assert.check( 1594 chain1.state.stacksize == chain2.state.stacksize && 1595 chain1.state.nlocks == chain2.state.nlocks); 1596 if (chain1.pc < chain2.pc) 1597 return new Chain( 1598 chain2.pc, 1599 mergeChains(chain1, chain2.next), 1600 chain2.state); 1601 return new Chain( 1602 chain1.pc, 1603 mergeChains(chain1.next, chain2), 1604 chain1.state); 1605 } 1606 1607 1608 /* ************************************************************************** 1609 * Catch clauses 1610 ****************************************************************************/ 1611 1612 /** Add a catch clause to code. 1613 */ 1614 public void addCatch(char startPc, char endPc, 1615 char handlerPc, char catchType) { 1616 catchInfo.append(new char[]{startPc, endPc, handlerPc, catchType}); 1617 } 1618 1619 1620 public void compressCatchTable() { 1621 ListBuffer<char[]> compressedCatchInfo = new ListBuffer<>(); 1622 List<Integer> handlerPcs = List.nil(); 1623 for (char[] catchEntry : catchInfo) { 1624 handlerPcs = handlerPcs.prepend((int)catchEntry[2]); 1625 } 1626 for (char[] catchEntry : catchInfo) { 1627 int startpc = catchEntry[0]; 1628 int endpc = catchEntry[1]; 1629 if (startpc == endpc || 1630 (startpc == (endpc - 1) && 1631 handlerPcs.contains(startpc))) { 1632 continue; 1633 } else { 1634 compressedCatchInfo.append(catchEntry); 1635 } 1636 } 1637 catchInfo = compressedCatchInfo; 1638 } 1639 1640 1641 /* ************************************************************************** 1642 * Line numbers 1643 ****************************************************************************/ 1644 1645 /** Add a line number entry. 1646 */ 1647 public void addLineNumber(char startPc, char lineNumber) { 1648 if (lineDebugInfo) { 1649 if (lineInfo.nonEmpty() && lineInfo.head[0] == startPc) 1650 lineInfo = lineInfo.tail; 1651 if (lineInfo.isEmpty() || lineInfo.head[1] != lineNumber) 1652 lineInfo = lineInfo.prepend(new char[]{startPc, lineNumber}); 1653 } 1654 } 1655 1656 /** Mark beginning of statement. 1657 */ 1658 public void statBegin(int pos) { 1659 if (pos != Position.NOPOS) { 1660 pendingStatPos = pos; 1661 } 1662 } 1663 1664 /** Force stat begin eagerly 1665 */ 1666 public void markStatBegin() { 1667 if (alive && lineDebugInfo) { 1668 int line = lineMap.getLineNumber(pendingStatPos); 1669 char cp1 = (char)cp; 1670 char line1 = (char)line; 1671 if (cp1 == cp && line1 == line) 1672 addLineNumber(cp1, line1); 1673 } 1674 pendingStatPos = Position.NOPOS; 1675 } 1676 1677 1678 /* ************************************************************************** 1679 * Simulated VM machine state 1680 ****************************************************************************/ 1681 1682 class State implements Cloneable { 1683 /** The set of registers containing values. */ 1684 Bits defined; 1685 1686 /** The (types of the) contents of the machine stack. */ 1687 Type[] stack; 1688 1689 /** The first stack position currently unused. */ 1690 int stacksize; 1691 1692 /** The numbers of registers containing locked monitors. */ 1693 int[] locks; 1694 int nlocks; 1695 1696 State() { 1697 defined = new Bits(); 1698 stack = new Type[16]; 1699 } 1700 1701 State dup() { 1702 try { 1703 State state = (State)super.clone(); 1704 state.defined = new Bits(defined); 1705 state.stack = stack.clone(); 1706 if (locks != null) state.locks = locks.clone(); 1707 if (debugCode) { 1708 System.err.println("duping state " + this); 1709 dump(); 1710 } 1711 return state; 1712 } catch (CloneNotSupportedException ex) { 1713 throw new AssertionError(ex); 1714 } 1715 } 1716 1717 void lock(int register) { 1718 if (locks == null) { 1719 locks = new int[20]; 1720 } else { 1721 locks = ArrayUtils.ensureCapacity(locks, nlocks); 1722 } 1723 locks[nlocks] = register; 1724 nlocks++; 1725 } 1726 1727 void unlock(int register) { 1728 nlocks--; 1729 Assert.check(locks[nlocks] == register); 1730 locks[nlocks] = -1; 1731 } 1732 1733 void push(Type t) { 1734 if (debugCode) System.err.println(" pushing " + t); 1735 switch (t.getTag()) { 1736 case VOID: 1737 return; 1738 case BYTE: 1739 case CHAR: 1740 case SHORT: 1741 case BOOLEAN: 1742 t = syms.intType; 1743 break; 1744 default: 1745 break; 1746 } 1747 stack = ArrayUtils.ensureCapacity(stack, stacksize+2); 1748 stack[stacksize++] = t; 1749 switch (width(t)) { 1750 case 1: 1751 break; 1752 case 2: 1753 stack[stacksize++] = null; 1754 break; 1755 default: 1756 throw new AssertionError(t); 1757 } 1758 if (stacksize > max_stack) 1759 max_stack = stacksize; 1760 } 1761 1762 Type pop1() { 1763 if (debugCode) System.err.println(" popping " + 1); 1764 stacksize--; 1765 Type result = stack[stacksize]; 1766 stack[stacksize] = null; 1767 Assert.check(result != null && width(result) == 1); 1768 return result; 1769 } 1770 1771 Type peek() { 1772 return stack[stacksize-1]; 1773 } 1774 1775 Type pop2() { 1776 if (debugCode) System.err.println(" popping " + 2); 1777 stacksize -= 2; 1778 Type result = stack[stacksize]; 1779 stack[stacksize] = null; 1780 Assert.check(stack[stacksize+1] == null 1781 && result != null && width(result) == 2); 1782 return result; 1783 } 1784 1785 void pop(int n) { 1786 if (debugCode) System.err.println(" popping " + n); 1787 while (n > 0) { 1788 stack[--stacksize] = null; 1789 n--; 1790 } 1791 } 1792 1793 void pop(Type t) { 1794 pop(width(t)); 1795 } 1796 1797 /** Force the top of the stack to be treated as this supertype 1798 * of its current type. */ 1799 void forceStackTop(Type t) { 1800 if (!alive) return; 1801 switch (t.getTag()) { 1802 case CLASS: 1803 case ARRAY: 1804 int width = width(t); 1805 Type old = stack[stacksize-width]; 1806 Assert.check(types.isSubtype(types.erasure(old), 1807 types.erasure(t))); 1808 stack[stacksize-width] = t; 1809 break; 1810 default: 1811 } 1812 } 1813 1814 void markInitialized(UninitializedType old) { 1815 Type newtype = old.initializedType(); 1816 for (int i=0; i<stacksize; i++) { 1817 if (stack[i] == old) stack[i] = newtype; 1818 } 1819 for (int i=0; i<lvar.length; i++) { 1820 LocalVar lv = lvar[i]; 1821 if (lv != null && lv.sym.type == old) { 1822 VarSymbol sym = lv.sym; 1823 sym = sym.clone(sym.owner); 1824 sym.type = newtype; 1825 LocalVar newlv = lvar[i] = new LocalVar(sym); 1826 newlv.aliveRanges = lv.aliveRanges; 1827 } 1828 } 1829 } 1830 1831 State join(State other) { 1832 defined.andSet(other.defined); 1833 Assert.check(stacksize == other.stacksize 1834 && nlocks == other.nlocks); 1835 for (int i=0; i<stacksize; ) { 1836 Type t = stack[i]; 1837 Type tother = other.stack[i]; 1838 Type result = 1839 t==tother ? t : 1840 types.isSubtype(t, tother) ? tother : 1841 types.isSubtype(tother, t) ? t : 1842 error(); 1843 int w = width(result); 1844 stack[i] = result; 1845 if (w == 2) Assert.checkNull(stack[i+1]); 1846 i += w; 1847 } 1848 return this; 1849 } 1850 1851 Type error() { 1852 throw new AssertionError("inconsistent stack types at join point"); 1853 } 1854 1855 void dump() { 1856 dump(-1); 1857 } 1858 1859 void dump(int pc) { 1860 System.err.print("stackMap for " + meth.owner + "." + meth); 1861 if (pc == -1) 1862 System.out.println(); 1863 else 1864 System.out.println(" at " + pc); 1865 System.err.println(" stack (from bottom):"); 1866 for (int i=0; i<stacksize; i++) 1867 System.err.println(" " + i + ": " + stack[i]); 1868 1869 int lastLocal = 0; 1870 for (int i=max_locals-1; i>=0; i--) { 1871 if (defined.isMember(i)) { 1872 lastLocal = i; 1873 break; 1874 } 1875 } 1876 if (lastLocal >= 0) 1877 System.err.println(" locals:"); 1878 for (int i=0; i<=lastLocal; i++) { 1879 System.err.print(" " + i + ": "); 1880 if (defined.isMember(i)) { 1881 LocalVar var = lvar[i]; 1882 if (var == null) { 1883 System.err.println("(none)"); 1884 } else if (var.sym == null) 1885 System.err.println("UNKNOWN!"); 1886 else 1887 System.err.println("" + var.sym + " of type " + 1888 var.sym.erasure(types)); 1889 } else { 1890 System.err.println("undefined"); 1891 } 1892 } 1893 if (nlocks != 0) { 1894 System.err.print(" locks:"); 1895 for (int i=0; i<nlocks; i++) { 1896 System.err.print(" " + locks[i]); 1897 } 1898 System.err.println(); 1899 } 1900 } 1901 } 1902 1903 static final Type jsrReturnValue = new JCPrimitiveType(INT, null); 1904 1905 1906 /* ************************************************************************** 1907 * Local variables 1908 ****************************************************************************/ 1909 1910 /** A live range of a local variable. */ 1911 static class LocalVar { 1912 final VarSymbol sym; 1913 final char reg; 1914 1915 class Range { 1916 char start_pc = Character.MAX_VALUE; 1917 char length = Character.MAX_VALUE; 1918 1919 Range() {} 1920 1921 Range(char start) { 1922 this.start_pc = start; 1923 } 1924 1925 Range(char start, char length) { 1926 this.start_pc = start; 1927 this.length = length; 1928 } 1929 1930 boolean closed() { 1931 return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE; 1932 } 1933 1934 @Override 1935 public String toString() { 1936 int currentStartPC = start_pc; 1937 int currentLength = length; 1938 return "startpc = " + currentStartPC + " length " + currentLength; 1939 } 1940 } 1941 1942 java.util.List<Range> aliveRanges = new java.util.ArrayList<>(); 1943 1944 LocalVar(VarSymbol v) { 1945 this.sym = v; 1946 this.reg = (char)v.adr; 1947 } 1948 public LocalVar dup() { 1949 return new LocalVar(sym); 1950 } 1951 1952 Range firstRange() { 1953 return aliveRanges.isEmpty() ? null : aliveRanges.get(0); 1954 } 1955 1956 Range lastRange() { 1957 return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1); 1958 } 1959 1960 void removeLastRange() { 1961 Range lastRange = lastRange(); 1962 if (lastRange != null) { 1963 aliveRanges.remove(lastRange); 1964 } 1965 } 1966 1967 @Override 1968 public String toString() { 1969 if (aliveRanges == null) { 1970 return "empty local var"; 1971 } 1972 StringBuilder sb = new StringBuilder().append(sym) 1973 .append(" in register ").append((int)reg).append(" \n"); 1974 for (Range r : aliveRanges) { 1975 sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc))) 1976 .append(" length=").append(Integer.toString(((int)r.length))) 1977 .append("\n"); 1978 } 1979 return sb.toString(); 1980 } 1981 1982 public void openRange(char start) { 1983 if (!hasOpenRange()) { 1984 aliveRanges.add(new Range(start)); 1985 } 1986 } 1987 1988 public void closeRange(char length) { 1989 if (isLastRangeInitialized() && length > 0) { 1990 Range range = lastRange(); 1991 if (range != null) { 1992 if (range.length == Character.MAX_VALUE) { 1993 range.length = length; 1994 } 1995 } 1996 } else { 1997 removeLastRange(); 1998 } 1999 } 2000 2001 public boolean hasOpenRange() { 2002 if (aliveRanges.isEmpty()) { 2003 return false; 2004 } 2005 return lastRange().length == Character.MAX_VALUE; 2006 } 2007 2008 public boolean isLastRangeInitialized() { 2009 if (aliveRanges.isEmpty()) { 2010 return false; 2011 } 2012 return lastRange().start_pc != Character.MAX_VALUE; 2013 } 2014 2015 public Range getWidestRange() { 2016 if (aliveRanges.isEmpty()) { 2017 return new Range(); 2018 } else { 2019 Range firstRange = firstRange(); 2020 Range lastRange = lastRange(); 2021 char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc)); 2022 return new Range(firstRange.start_pc, length); 2023 } 2024 } 2025 2026 } 2027 2028 /** Local variables, indexed by register. */ 2029 LocalVar[] lvar; 2030 2031 /** Add a new local variable. */ 2032 private void addLocalVar(VarSymbol v) { 2033 int adr = v.adr; 2034 lvar = ArrayUtils.ensureCapacity(lvar, adr+1); 2035 Assert.checkNull(lvar[adr]); 2036 if (pendingJumps != null) { 2037 resolvePending(); 2038 } 2039 lvar[adr] = new LocalVar(v); 2040 state.defined.excl(adr); 2041 } 2042 2043 void adjustAliveRanges(int oldCP, int delta) { 2044 for (LocalVar localVar: lvar) { 2045 if (localVar != null) { 2046 for (LocalVar.Range range: localVar.aliveRanges) { 2047 if (range.closed() && range.start_pc + range.length >= oldCP) { 2048 range.length += (char)delta; 2049 } 2050 } 2051 } 2052 } 2053 } 2054 2055 /** 2056 * Calculates the size of the LocalVariableTable. 2057 */ 2058 public int getLVTSize() { 2059 int result = varBufferSize; 2060 for (int i = 0; i < varBufferSize; i++) { 2061 LocalVar var = varBuffer[i]; 2062 result += var.aliveRanges.size() - 1; 2063 } 2064 return result; 2065 } 2066 2067 /** Set the current variable defined state. */ 2068 public void setDefined(Bits newDefined) { 2069 if (alive && newDefined != state.defined) { 2070 Bits diff = new Bits(state.defined).xorSet(newDefined); 2071 for (int adr = diff.nextBit(0); 2072 adr >= 0; 2073 adr = diff.nextBit(adr+1)) { 2074 if (adr >= nextreg) 2075 state.defined.excl(adr); 2076 else if (state.defined.isMember(adr)) 2077 setUndefined(adr); 2078 else 2079 setDefined(adr); 2080 } 2081 } 2082 } 2083 2084 /** Mark a register as being (possibly) defined. */ 2085 public void setDefined(int adr) { 2086 LocalVar v = lvar[adr]; 2087 if (v == null) { 2088 state.defined.excl(adr); 2089 } else { 2090 state.defined.incl(adr); 2091 if (cp < Character.MAX_VALUE) { 2092 v.openRange((char)cp); 2093 } 2094 } 2095 } 2096 2097 /** Mark a register as being undefined. */ 2098 public void setUndefined(int adr) { 2099 state.defined.excl(adr); 2100 if (adr < lvar.length && 2101 lvar[adr] != null && 2102 lvar[adr].isLastRangeInitialized()) { 2103 LocalVar v = lvar[adr]; 2104 char length = (char)(curCP() - v.lastRange().start_pc); 2105 if (length < Character.MAX_VALUE) { 2106 lvar[adr] = v.dup(); 2107 v.closeRange(length); 2108 putVar(v); 2109 fillLocalVarPosition(v); 2110 } else { 2111 v.removeLastRange(); 2112 } 2113 } 2114 } 2115 2116 /** End the scope of a variable. */ 2117 private void endScope(int adr) { 2118 LocalVar v = lvar[adr]; 2119 if (v != null) { 2120 if (v.isLastRangeInitialized()) { 2121 char length = (char)(curCP() - v.lastRange().start_pc); 2122 if (length < Character.MAX_VALUE) { 2123 v.closeRange(length); 2124 putVar(v); 2125 fillLocalVarPosition(v); 2126 } 2127 } 2128 /** the call to curCP() can implicitly adjust the current cp, if so 2129 * the alive range of local variables may be modified. Thus we need 2130 * all of them. For this reason assigning null to the given address 2131 * should be the last action to do. 2132 */ 2133 lvar[adr] = null; 2134 } 2135 state.defined.excl(adr); 2136 } 2137 2138 private void fillLocalVarPosition(LocalVar lv) { 2139 if (lv == null || lv.sym == null || lv.sym.isExceptionParameter()|| !lv.sym.hasTypeAnnotations()) 2140 return; 2141 LocalVar.Range[] validRanges = lv.aliveRanges.stream().filter(r -> r.closed() && r.length > 0).toArray(s -> new LocalVar.Range[s]); 2142 if (validRanges.length == 0) 2143 return ; 2144 int[] lvarOffset = Arrays.stream(validRanges).mapToInt(r -> r.start_pc).toArray(); 2145 int[] lvarLength = Arrays.stream(validRanges).mapToInt(r -> r.length).toArray(); 2146 int[] lvarIndex = Arrays.stream(validRanges).mapToInt(r -> lv.reg).toArray(); 2147 for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { 2148 TypeAnnotationPosition p = ta.position; 2149 p.lvarOffset = appendArray(p.lvarOffset, lvarOffset); 2150 p.lvarLength = appendArray(p.lvarLength, lvarLength); 2151 p.lvarIndex = appendArray(p.lvarIndex, lvarIndex); 2152 p.isValidOffset = true; 2153 } 2154 } 2155 2156 private int[] appendArray(int[] source, int[] append) { 2157 if (source == null || source.length == 0) return append; 2158 2159 int[] result = new int[source.length + append.length]; 2160 2161 System.arraycopy(source, 0, result, 0, source.length); 2162 System.arraycopy(append, 0, result, source.length, append.length); 2163 return result; 2164 } 2165 2166 // Method to be called after compressCatchTable to 2167 // fill in the exception table index for type 2168 // annotations on exception parameters. 2169 public void fillExceptionParameterPositions() { 2170 for (int i = 0; i < varBufferSize; ++i) { 2171 LocalVar lv = varBuffer[i]; 2172 if (lv == null || lv.sym == null 2173 || !lv.sym.hasTypeAnnotations() 2174 || !lv.sym.isExceptionParameter()) 2175 continue; 2176 2177 for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { 2178 TypeAnnotationPosition p = ta.position; 2179 if (p.hasCatchType()) { 2180 final int idx = findExceptionIndex(p); 2181 if (idx == -1) 2182 Assert.error("Could not find exception index for type annotation " + 2183 ta + " on exception parameter"); 2184 p.setExceptionIndex(idx); 2185 } 2186 } 2187 } 2188 } 2189 2190 private int findExceptionIndex(TypeAnnotationPosition p) { 2191 final int catchType = p.getCatchType(); 2192 final int startPos = p.getStartPos(); 2193 final int len = catchInfo.length(); 2194 List<char[]> iter = catchInfo.toList(); 2195 for (int i = 0; i < len; ++i) { 2196 char[] catchEntry = iter.head; 2197 iter = iter.tail; 2198 int ct = catchEntry[3]; 2199 int sp = catchEntry[0]; 2200 if (catchType == ct && sp == startPos) { 2201 return i; 2202 } 2203 } 2204 return -1; 2205 } 2206 2207 /** Put a live variable range into the buffer to be output to the 2208 * class file. 2209 */ 2210 void putVar(LocalVar var) { 2211 // Keep local variables if 2212 // 1) we need them for debug information 2213 // 2) it is an exception type and it contains type annotations 2214 boolean keepLocalVariables = varDebugInfo || 2215 (var.sym.isExceptionParameter() && var.sym.hasTypeAnnotations()); 2216 if (!keepLocalVariables) return; 2217 //don't keep synthetic vars, unless they are lambda method parameters 2218 boolean ignoredSyntheticVar = (var.sym.flags() & Flags.SYNTHETIC) != 0 && 2219 ((var.sym.owner.flags() & Flags.LAMBDA_METHOD) == 0 || 2220 (var.sym.flags() & Flags.PARAMETER) == 0); 2221 if (ignoredSyntheticVar) return; 2222 //don't include unnamed variables: 2223 if (var.sym.name == var.sym.name.table.names.empty) return ; 2224 if (varBuffer == null) 2225 varBuffer = new LocalVar[20]; 2226 else 2227 varBuffer = ArrayUtils.ensureCapacity(varBuffer, varBufferSize); 2228 varBuffer[varBufferSize++] = var; 2229 } 2230 2231 /** Previously live local variables, to be put into the variable table. */ 2232 LocalVar[] varBuffer; 2233 int varBufferSize; 2234 2235 /** Create a new local variable address and return it. 2236 */ 2237 private int newLocal(int typecode) { 2238 int reg = nextreg; 2239 int w = width(typecode); 2240 nextreg = reg + w; 2241 if (nextreg > max_locals) max_locals = nextreg; 2242 return reg; 2243 } 2244 2245 private int newLocal(Type type) { 2246 return newLocal(typecode(type)); 2247 } 2248 2249 public int newLocal(VarSymbol v) { 2250 int reg = v.adr = newLocal(v.erasure(types)); 2251 addLocalVar(v); 2252 return reg; 2253 } 2254 2255 /** Start a set of fresh registers. 2256 */ 2257 public void newRegSegment() { 2258 nextreg = max_locals; 2259 } 2260 2261 /** End scopes of all variables with registers ≥ first. 2262 */ 2263 public void endScopes(int first) { 2264 int prevNextReg = nextreg; 2265 nextreg = first; 2266 for (int i = nextreg; i < prevNextReg; i++) endScope(i); 2267 } 2268 2269 /* ************************************************************************ 2270 * static tables 2271 *************************************************************************/ 2272 2273 public static String mnem(int opcode) { 2274 return Mneumonics.mnem[opcode]; 2275 } 2276 2277 private static class Mneumonics { 2278 private static final String[] mnem = new String[ByteCodeCount]; 2279 static { 2280 mnem[nop] = "nop"; 2281 mnem[aconst_null] = "aconst_null"; 2282 mnem[iconst_m1] = "iconst_m1"; 2283 mnem[iconst_0] = "iconst_0"; 2284 mnem[iconst_1] = "iconst_1"; 2285 mnem[iconst_2] = "iconst_2"; 2286 mnem[iconst_3] = "iconst_3"; 2287 mnem[iconst_4] = "iconst_4"; 2288 mnem[iconst_5] = "iconst_5"; 2289 mnem[lconst_0] = "lconst_0"; 2290 mnem[lconst_1] = "lconst_1"; 2291 mnem[fconst_0] = "fconst_0"; 2292 mnem[fconst_1] = "fconst_1"; 2293 mnem[fconst_2] = "fconst_2"; 2294 mnem[dconst_0] = "dconst_0"; 2295 mnem[dconst_1] = "dconst_1"; 2296 mnem[bipush] = "bipush"; 2297 mnem[sipush] = "sipush"; 2298 mnem[ldc1] = "ldc1"; 2299 mnem[ldc2] = "ldc2"; 2300 mnem[ldc2w] = "ldc2w"; 2301 mnem[iload] = "iload"; 2302 mnem[lload] = "lload"; 2303 mnem[fload] = "fload"; 2304 mnem[dload] = "dload"; 2305 mnem[aload] = "aload"; 2306 mnem[iload_0] = "iload_0"; 2307 mnem[lload_0] = "lload_0"; 2308 mnem[fload_0] = "fload_0"; 2309 mnem[dload_0] = "dload_0"; 2310 mnem[aload_0] = "aload_0"; 2311 mnem[iload_1] = "iload_1"; 2312 mnem[lload_1] = "lload_1"; 2313 mnem[fload_1] = "fload_1"; 2314 mnem[dload_1] = "dload_1"; 2315 mnem[aload_1] = "aload_1"; 2316 mnem[iload_2] = "iload_2"; 2317 mnem[lload_2] = "lload_2"; 2318 mnem[fload_2] = "fload_2"; 2319 mnem[dload_2] = "dload_2"; 2320 mnem[aload_2] = "aload_2"; 2321 mnem[iload_3] = "iload_3"; 2322 mnem[lload_3] = "lload_3"; 2323 mnem[fload_3] = "fload_3"; 2324 mnem[dload_3] = "dload_3"; 2325 mnem[aload_3] = "aload_3"; 2326 mnem[iaload] = "iaload"; 2327 mnem[laload] = "laload"; 2328 mnem[faload] = "faload"; 2329 mnem[daload] = "daload"; 2330 mnem[aaload] = "aaload"; 2331 mnem[baload] = "baload"; 2332 mnem[caload] = "caload"; 2333 mnem[saload] = "saload"; 2334 mnem[istore] = "istore"; 2335 mnem[lstore] = "lstore"; 2336 mnem[fstore] = "fstore"; 2337 mnem[dstore] = "dstore"; 2338 mnem[astore] = "astore"; 2339 mnem[istore_0] = "istore_0"; 2340 mnem[lstore_0] = "lstore_0"; 2341 mnem[fstore_0] = "fstore_0"; 2342 mnem[dstore_0] = "dstore_0"; 2343 mnem[astore_0] = "astore_0"; 2344 mnem[istore_1] = "istore_1"; 2345 mnem[lstore_1] = "lstore_1"; 2346 mnem[fstore_1] = "fstore_1"; 2347 mnem[dstore_1] = "dstore_1"; 2348 mnem[astore_1] = "astore_1"; 2349 mnem[istore_2] = "istore_2"; 2350 mnem[lstore_2] = "lstore_2"; 2351 mnem[fstore_2] = "fstore_2"; 2352 mnem[dstore_2] = "dstore_2"; 2353 mnem[astore_2] = "astore_2"; 2354 mnem[istore_3] = "istore_3"; 2355 mnem[lstore_3] = "lstore_3"; 2356 mnem[fstore_3] = "fstore_3"; 2357 mnem[dstore_3] = "dstore_3"; 2358 mnem[astore_3] = "astore_3"; 2359 mnem[iastore] = "iastore"; 2360 mnem[lastore] = "lastore"; 2361 mnem[fastore] = "fastore"; 2362 mnem[dastore] = "dastore"; 2363 mnem[aastore] = "aastore"; 2364 mnem[bastore] = "bastore"; 2365 mnem[castore] = "castore"; 2366 mnem[sastore] = "sastore"; 2367 mnem[pop] = "pop"; 2368 mnem[pop2] = "pop2"; 2369 mnem[dup] = "dup"; 2370 mnem[dup_x1] = "dup_x1"; 2371 mnem[dup_x2] = "dup_x2"; 2372 mnem[dup2] = "dup2"; 2373 mnem[dup2_x1] = "dup2_x1"; 2374 mnem[dup2_x2] = "dup2_x2"; 2375 mnem[swap] = "swap"; 2376 mnem[iadd] = "iadd"; 2377 mnem[ladd] = "ladd"; 2378 mnem[fadd] = "fadd"; 2379 mnem[dadd] = "dadd"; 2380 mnem[isub] = "isub"; 2381 mnem[lsub] = "lsub"; 2382 mnem[fsub] = "fsub"; 2383 mnem[dsub] = "dsub"; 2384 mnem[imul] = "imul"; 2385 mnem[lmul] = "lmul"; 2386 mnem[fmul] = "fmul"; 2387 mnem[dmul] = "dmul"; 2388 mnem[idiv] = "idiv"; 2389 mnem[ldiv] = "ldiv"; 2390 mnem[fdiv] = "fdiv"; 2391 mnem[ddiv] = "ddiv"; 2392 mnem[imod] = "imod"; 2393 mnem[lmod] = "lmod"; 2394 mnem[fmod] = "fmod"; 2395 mnem[dmod] = "dmod"; 2396 mnem[ineg] = "ineg"; 2397 mnem[lneg] = "lneg"; 2398 mnem[fneg] = "fneg"; 2399 mnem[dneg] = "dneg"; 2400 mnem[ishl] = "ishl"; 2401 mnem[lshl] = "lshl"; 2402 mnem[ishr] = "ishr"; 2403 mnem[lshr] = "lshr"; 2404 mnem[iushr] = "iushr"; 2405 mnem[lushr] = "lushr"; 2406 mnem[iand] = "iand"; 2407 mnem[land] = "land"; 2408 mnem[ior] = "ior"; 2409 mnem[lor] = "lor"; 2410 mnem[ixor] = "ixor"; 2411 mnem[lxor] = "lxor"; 2412 mnem[iinc] = "iinc"; 2413 mnem[i2l] = "i2l"; 2414 mnem[i2f] = "i2f"; 2415 mnem[i2d] = "i2d"; 2416 mnem[l2i] = "l2i"; 2417 mnem[l2f] = "l2f"; 2418 mnem[l2d] = "l2d"; 2419 mnem[f2i] = "f2i"; 2420 mnem[f2l] = "f2l"; 2421 mnem[f2d] = "f2d"; 2422 mnem[d2i] = "d2i"; 2423 mnem[d2l] = "d2l"; 2424 mnem[d2f] = "d2f"; 2425 mnem[int2byte] = "int2byte"; 2426 mnem[int2char] = "int2char"; 2427 mnem[int2short] = "int2short"; 2428 mnem[lcmp] = "lcmp"; 2429 mnem[fcmpl] = "fcmpl"; 2430 mnem[fcmpg] = "fcmpg"; 2431 mnem[dcmpl] = "dcmpl"; 2432 mnem[dcmpg] = "dcmpg"; 2433 mnem[ifeq] = "ifeq"; 2434 mnem[ifne] = "ifne"; 2435 mnem[iflt] = "iflt"; 2436 mnem[ifge] = "ifge"; 2437 mnem[ifgt] = "ifgt"; 2438 mnem[ifle] = "ifle"; 2439 mnem[if_icmpeq] = "if_icmpeq"; 2440 mnem[if_icmpne] = "if_icmpne"; 2441 mnem[if_icmplt] = "if_icmplt"; 2442 mnem[if_icmpge] = "if_icmpge"; 2443 mnem[if_icmpgt] = "if_icmpgt"; 2444 mnem[if_icmple] = "if_icmple"; 2445 mnem[if_acmpeq] = "if_acmpeq"; 2446 mnem[if_acmpne] = "if_acmpne"; 2447 mnem[goto_] = "goto_"; 2448 mnem[jsr] = "jsr"; 2449 mnem[ret] = "ret"; 2450 mnem[tableswitch] = "tableswitch"; 2451 mnem[lookupswitch] = "lookupswitch"; 2452 mnem[ireturn] = "ireturn"; 2453 mnem[lreturn] = "lreturn"; 2454 mnem[freturn] = "freturn"; 2455 mnem[dreturn] = "dreturn"; 2456 mnem[areturn] = "areturn"; 2457 mnem[return_] = "return_"; 2458 mnem[getstatic] = "getstatic"; 2459 mnem[putstatic] = "putstatic"; 2460 mnem[getfield] = "getfield"; 2461 mnem[putfield] = "putfield"; 2462 mnem[invokevirtual] = "invokevirtual"; 2463 mnem[invokespecial] = "invokespecial"; 2464 mnem[invokestatic] = "invokestatic"; 2465 mnem[invokeinterface] = "invokeinterface"; 2466 mnem[invokedynamic] = "invokedynamic"; 2467 mnem[new_] = "new_"; 2468 mnem[newarray] = "newarray"; 2469 mnem[anewarray] = "anewarray"; 2470 mnem[arraylength] = "arraylength"; 2471 mnem[athrow] = "athrow"; 2472 mnem[checkcast] = "checkcast"; 2473 mnem[instanceof_] = "instanceof_"; 2474 mnem[monitorenter] = "monitorenter"; 2475 mnem[monitorexit] = "monitorexit"; 2476 mnem[wide] = "wide"; 2477 mnem[multianewarray] = "multianewarray"; 2478 mnem[if_acmp_null] = "if_acmp_null"; 2479 mnem[if_acmp_nonnull] = "if_acmp_nonnull"; 2480 mnem[goto_w] = "goto_w"; 2481 mnem[jsr_w] = "jsr_w"; 2482 mnem[breakpoint] = "breakpoint"; 2483 } 2484 } 2485 }