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