1 /* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.experimental.bytecode; 25 26 import jdk.experimental.bytecode.PoolHelper.StaticArgListBuilder; 27 28 import java.lang.invoke.MethodHandle; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.function.BiFunction; 32 import java.util.function.Consumer; 33 import java.util.function.Function; 34 import java.util.function.ToIntFunction; 35 36 /** 37 * Builder for class file code attributes. A code attribute is defined: 38 * <pre> 39 * {@code 40 * Code_attribute { 41 * u2 attribute_name_index; 42 * u4 attribute_length; 43 * u2 max_stack; 44 * u2 max_locals; 45 * u4 code_length; 46 * u1 code[code_length]; 47 * u2 exception_table_length; 48 * { u2 start_pc; 49 * u2 end_pc; 50 * u2 handler_pc; 51 * u2 catch_type; 52 * } exception_table[exception_table_length]; 53 * u2 attributes_count; 54 * attribute_info attributes[attributes_count]; 55 * } } 56 * </pre> 57 * 58 * @param <S> the type of symbol representation 59 * @param <T> the type of type descriptors representation 60 * @param <E> the type of pool entries 61 * @param <C> the type of this code builder 62 */ 63 public class CodeBuilder<S, T, E, C extends CodeBuilder<S, T, E, C>> extends AttributeBuilder<S, T, E, C> { 64 65 protected GrowableByteBuffer code = new GrowableByteBuffer(); 66 GrowableByteBuffer catchers = new GrowableByteBuffer(); 67 GrowableByteBuffer stackmaps = new GrowableByteBuffer(); 68 MethodBuilder<S, T, E> methodBuilder; 69 int ncatchers; 70 int stacksize = -1; 71 int localsize = -1; 72 int nstackmaps = 0; 73 74 public enum JumpMode { 75 NARROW, 76 WIDE; 77 } 78 79 CodeBuilder(MethodBuilder<S, T, E> methodBuilder) { 80 super(methodBuilder.poolHelper, methodBuilder.typeHelper); 81 this.methodBuilder = methodBuilder; 82 } 83 84 public C getstatic(S owner, CharSequence name, T type) { 85 emitOp(Opcode.GETSTATIC, type); 86 code.writeChar(poolHelper.putFieldRef(owner, name, type)); 87 return thisBuilder(); 88 } 89 90 public C putstatic(S owner, CharSequence name, T type) { 91 emitOp(Opcode.PUTSTATIC, type); 92 code.writeChar(poolHelper.putFieldRef(owner, name, type)); 93 return thisBuilder(); 94 } 95 96 public C getfield(S owner, CharSequence name, T type) { 97 emitOp(Opcode.GETFIELD, type); 98 code.writeChar(poolHelper.putFieldRef(owner, name, type)); 99 return thisBuilder(); 100 } 101 102 public C putfield(S owner, CharSequence name, T type) { 103 emitOp(Opcode.PUTFIELD, type); 104 code.writeChar(poolHelper.putFieldRef(owner, name, type)); 105 return thisBuilder(); 106 } 107 108 public C withfield(S owner, CharSequence name, T type) { 109 emitOp(Opcode.WITHFIELD, type); 110 code.writeChar(poolHelper.putFieldRef(owner, name, type)); 111 return thisBuilder(); 112 } 113 114 public C invokevirtual(S owner, CharSequence name, T type, boolean isInterface) { 115 emitOp(Opcode.INVOKEVIRTUAL, type); 116 code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface)); 117 return thisBuilder(); 118 } 119 120 public C invokespecial(S owner, CharSequence name, T type, boolean isInterface) { 121 emitOp(Opcode.INVOKESPECIAL, type); 122 code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface)); 123 return thisBuilder(); 124 } 125 126 public C invokestatic(S owner, CharSequence name, T type, boolean isInterface) { 127 emitOp(Opcode.INVOKESTATIC, type); 128 code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface)); 129 return thisBuilder(); 130 } 131 132 public C invokeinterface(S owner, CharSequence name, T type) { 133 emitOp(Opcode.INVOKEINTERFACE, type); 134 code.writeChar(poolHelper.putMethodRef(owner, name, type, true)); 135 int nargs = 1; 136 Iterator<T> it = typeHelper.parameterTypes(type); 137 while (it.hasNext()) { 138 nargs += typeHelper.tag(it.next()).width; 139 } 140 code.writeByte(nargs); 141 code.writeByte(0); 142 return thisBuilder(); 143 } 144 145 public C invokedynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) { 146 emitOp(Opcode.INVOKEDYNAMIC, invokedType); 147 code.writeChar(poolHelper.putInvokeDynamic(invokedName, invokedType, bsmClass, bsmName, bsmType, staticArgs)); 148 code.writeChar(0); //padding 149 return thisBuilder(); 150 } 151 152 public C new_(S clazz) { 153 emitOp(Opcode.NEW, clazz); 154 code.writeChar(poolHelper.putClass(clazz)); 155 return thisBuilder(); 156 } 157 158 public C aconst_init(S clazz) { 159 emitOp(Opcode.ACONST_INIT, clazz); 160 code.writeChar(poolHelper.putClass(clazz)); 161 return thisBuilder(); 162 } 163 164 public C newarray(TypeTag tag) { 165 emitOp(Opcode.NEWARRAY, tag); 166 int newarraycode = tag.newarraycode; 167 if (newarraycode == -1) { 168 throw new IllegalStateException("Bad tag " + tag); 169 } 170 code.writeByte(newarraycode); 171 return thisBuilder(); 172 } 173 174 public C anewarray(S array) { 175 emitOp(Opcode.ANEWARRAY, array); 176 int poolIdx = poolHelper.putClass(array); 177 code.writeChar(poolIdx); 178 return thisBuilder(); 179 } 180 181 public C checkcast(S target) { 182 emitOp(Opcode.CHECKCAST); 183 int poolIdx = poolHelper.putClass(target); 184 code.writeChar(poolIdx); 185 return thisBuilder(); 186 } 187 188 public C instanceof_(S target) { 189 emitOp(Opcode.INSTANCEOF); 190 int poolIdx = poolHelper.putClass(target); 191 code.writeChar(poolIdx); 192 return thisBuilder(); 193 } 194 195 public C multianewarray(S array, byte dims) { 196 emitOp(Opcode.MULTIANEWARRAY, new Object[]{array, dims}); 197 code.writeChar(poolHelper.putClass(array)).writeByte(dims); 198 return thisBuilder(); 199 } 200 201 public C ldc(int i) { 202 return ldc(pool -> pool.putInt(i), false); 203 } 204 205 public C ldc(long l) { 206 return ldc(pool -> pool.putLong(l), true); 207 } 208 209 public C ldc(float f) { 210 return ldc(pool -> pool.putFloat(f), false); 211 } 212 213 public C ldc(double d) { 214 return ldc(pool -> pool.putDouble(d), true); 215 } 216 217 public C ldc(String s) { 218 return ldc(pool -> pool.putString(s), false); 219 } 220 221 public C ldc(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) { 222 boolean fat = typeHelper.tag(constType).width() == 2; 223 return ldc(pool -> pool.putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs), fat); 224 } 225 226 public <Z> C ldc(Z z, BiFunction<PoolHelper<S, T, E>, Z, Integer> poolFunc) { 227 return ldc(pool -> poolFunc.apply(pool, z), false); 228 } 229 230 protected C ldc(ToIntFunction<PoolHelper<S, T, E>> indexFunc, boolean fat) { 231 // @@@ This should probably be abstract 232 int index = indexFunc.applyAsInt(poolHelper); 233 return ldc(index, null, fat); 234 } 235 236 protected final C ldc(int index, T type, boolean fat) { 237 if (fat) { 238 emitOp(Opcode.LDC2_W, type); 239 code.writeChar(index); 240 } else if (index > 63) { 241 emitOp(Opcode.LDC_W, type); 242 code.writeChar(index); 243 } else { 244 emitOp(Opcode.LDC, type); 245 code.writeByte(index); 246 } 247 return thisBuilder(); 248 } 249 250 //other non-CP dependent opcodes 251 public C areturn() { 252 return emitOp(Opcode.ARETURN); 253 } 254 255 public C ireturn() { 256 return emitOp(Opcode.IRETURN); 257 } 258 259 public C freturn() { 260 return emitOp(Opcode.FRETURN); 261 } 262 263 public C lreturn() { 264 return emitOp(Opcode.LRETURN); 265 } 266 267 public C dreturn() { 268 return emitOp(Opcode.DRETURN); 269 } 270 271 public C return_() { 272 return emitOp(Opcode.RETURN); 273 } 274 275 protected C emitWideIfNeeded(Opcode opcode, int n) { 276 boolean wide = n > Byte.MAX_VALUE; 277 if (wide) { 278 wide(); 279 } 280 emitOp(opcode, n); 281 if (wide) { 282 code.writeChar(n); 283 } else { 284 code.writeByte(n); 285 } 286 return thisBuilder(); 287 } 288 289 protected C emitWideIfNeeded(Opcode opcode, int n, int v) { 290 boolean wide = n > Byte.MAX_VALUE || v > Byte.MAX_VALUE; 291 if (wide) { 292 wide(); 293 } 294 emitOp(opcode, n); 295 if (wide) { 296 code.writeChar(n).writeChar(v); 297 } else { 298 code.writeByte(n).writeByte(v); 299 } 300 return thisBuilder(); 301 } 302 303 public C aload(int i) { 304 return emitWideIfNeeded(Opcode.ALOAD, i); 305 } 306 307 public C iload(int i) { 308 return emitWideIfNeeded(Opcode.ILOAD, i); 309 } 310 311 public C fload(int i) { 312 return emitWideIfNeeded(Opcode.FLOAD, i); 313 } 314 315 public C lload(int i) { 316 return emitWideIfNeeded(Opcode.LLOAD, i); 317 } 318 319 public C dload(int i) { 320 return emitWideIfNeeded(Opcode.DLOAD, i); 321 } 322 323 public C aload_0() { 324 return emitOp(Opcode.ALOAD_0); 325 } 326 327 public C iload_0() { 328 return emitOp(Opcode.ILOAD_0); 329 } 330 331 public C fload_0() { 332 return emitOp(Opcode.FLOAD_0); 333 } 334 335 public C lload_0() { 336 return emitOp(Opcode.LLOAD_0); 337 } 338 339 public C dload_0() { 340 return emitOp(Opcode.DLOAD_0); 341 } 342 343 public C aload_1() { 344 return emitOp(Opcode.ALOAD_1); 345 } 346 347 public C iload_1() { 348 return emitOp(Opcode.ILOAD_1); 349 } 350 351 public C fload_1() { 352 return emitOp(Opcode.FLOAD_1); 353 } 354 355 public C lload_1() { 356 return emitOp(Opcode.LLOAD_1); 357 } 358 359 public C dload_1() { 360 return emitOp(Opcode.DLOAD_1); 361 } 362 363 public C aload_2() { 364 return emitOp(Opcode.ALOAD_2); 365 } 366 367 public C iload_2() { 368 return emitOp(Opcode.ILOAD_2); 369 } 370 371 public C fload_2() { 372 return emitOp(Opcode.FLOAD_2); 373 } 374 375 public C lload_2() { 376 return emitOp(Opcode.LLOAD_2); 377 } 378 379 public C dload_2() { 380 return emitOp(Opcode.DLOAD_2); 381 } 382 383 public C aload_3() { 384 return emitOp(Opcode.ALOAD_3); 385 } 386 387 public C iload_3() { 388 return emitOp(Opcode.ILOAD_3); 389 } 390 391 public C fload_3() { 392 return emitOp(Opcode.FLOAD_3); 393 } 394 395 public C lload_3() { 396 return emitOp(Opcode.LLOAD_3); 397 } 398 399 public C dload_3() { 400 return emitOp(Opcode.DLOAD_3); 401 } 402 403 public C astore(int i) { 404 return emitWideIfNeeded(Opcode.ASTORE, i); 405 } 406 407 public C istore(int i) { 408 return emitWideIfNeeded(Opcode.ISTORE, i); 409 } 410 411 public C fstore(int i) { 412 return emitWideIfNeeded(Opcode.FSTORE, i); 413 } 414 415 public C lstore(int i) { 416 return emitWideIfNeeded(Opcode.LSTORE, i); 417 } 418 419 public C dstore(int i) { 420 return emitWideIfNeeded(Opcode.DSTORE, i); 421 } 422 423 public C astore_0() { 424 return emitOp(Opcode.ASTORE_0); 425 } 426 427 public C istore_0() { 428 return emitOp(Opcode.ISTORE_0); 429 } 430 431 public C fstore_0() { 432 return emitOp(Opcode.FSTORE_0); 433 } 434 435 public C lstore_0() { 436 return emitOp(Opcode.LSTORE_0); 437 } 438 439 public C dstore_0() { 440 return emitOp(Opcode.DSTORE_0); 441 } 442 443 public C astore_1() { 444 return emitOp(Opcode.ASTORE_1); 445 } 446 447 public C istore_1() { 448 return emitOp(Opcode.ISTORE_1); 449 } 450 451 public C fstore_1() { 452 return emitOp(Opcode.FSTORE_1); 453 } 454 455 public C lstore_1() { 456 return emitOp(Opcode.LSTORE_1); 457 } 458 459 public C dstore_1() { 460 return emitOp(Opcode.DSTORE_1); 461 } 462 463 public C astore_2() { 464 return emitOp(Opcode.ASTORE_2); 465 } 466 467 public C istore_2() { 468 return emitOp(Opcode.ISTORE_2); 469 } 470 471 public C fstore_2() { 472 return emitOp(Opcode.FSTORE_2); 473 } 474 475 public C lstore_2() { 476 return emitOp(Opcode.LSTORE_2); 477 } 478 479 public C dstore_2() { 480 return emitOp(Opcode.DSTORE_2); 481 } 482 483 public C astore_3() { 484 return emitOp(Opcode.ASTORE_3); 485 } 486 487 public C istore_3() { 488 return emitOp(Opcode.ISTORE_3); 489 } 490 491 public C fstore_3() { 492 return emitOp(Opcode.FSTORE_3); 493 } 494 495 public C lstore_3() { 496 return emitOp(Opcode.LSTORE_3); 497 } 498 499 public C dstore_3() { 500 return emitOp(Opcode.DSTORE_3); 501 } 502 503 //... 504 505 public C iaload() { 506 return emitOp(Opcode.IALOAD); 507 } 508 509 public C laload() { 510 return emitOp(Opcode.LALOAD); 511 } 512 513 public C faload() { 514 return emitOp(Opcode.FALOAD); 515 } 516 517 public C daload() { 518 return emitOp(Opcode.DALOAD); 519 } 520 521 public C aaload() { 522 return emitOp(Opcode.AALOAD); 523 } 524 525 public C baload() { 526 return emitOp(Opcode.BALOAD); 527 } 528 529 public C caload() { 530 return emitOp(Opcode.CALOAD); 531 } 532 533 public C saload() { 534 return emitOp(Opcode.SALOAD); 535 } 536 537 public C iastore() { 538 return emitOp(Opcode.IASTORE); 539 } 540 541 public C lastore() { 542 return emitOp(Opcode.LASTORE); 543 } 544 545 public C fastore() { 546 return emitOp(Opcode.FASTORE); 547 } 548 549 public C dastore() { 550 return emitOp(Opcode.DASTORE); 551 } 552 553 public C aastore() { 554 return emitOp(Opcode.AASTORE); 555 } 556 557 public C bastore() { 558 return emitOp(Opcode.BASTORE); 559 } 560 561 public C castore() { 562 return emitOp(Opcode.CASTORE); 563 } 564 565 public C sastore() { 566 return emitOp(Opcode.SASTORE); 567 } 568 569 public C nop() { 570 return emitOp(Opcode.NOP); 571 } 572 573 public C aconst_null() { 574 return emitOp(Opcode.ACONST_NULL); 575 } 576 577 public C iconst_0() { 578 return emitOp(Opcode.ICONST_0); 579 } 580 581 public C iconst_1() { 582 return emitOp(Opcode.ICONST_1); 583 } 584 585 public C iconst_2() { 586 return emitOp(Opcode.ICONST_2); 587 } 588 589 public C iconst_3() { 590 return emitOp(Opcode.ICONST_3); 591 } 592 593 public C iconst_4() { 594 return emitOp(Opcode.ICONST_4); 595 } 596 597 public C iconst_5() { 598 return emitOp(Opcode.ICONST_5); 599 } 600 601 public C iconst_m1() { 602 return emitOp(Opcode.ICONST_M1); 603 } 604 605 public C lconst_0() { 606 return emitOp(Opcode.LCONST_0); 607 } 608 609 public C lconst_1() { 610 return emitOp(Opcode.LCONST_1); 611 } 612 613 public C fconst_0() { 614 return emitOp(Opcode.FCONST_0); 615 } 616 617 public C fconst_1() { 618 return emitOp(Opcode.FCONST_1); 619 } 620 621 public C fconst_2() { 622 return emitOp(Opcode.FCONST_2); 623 } 624 625 public C dconst_0() { 626 return emitOp(Opcode.DCONST_0); 627 } 628 629 public C dconst_1() { 630 return emitOp(Opcode.DCONST_1); 631 } 632 633 public C sipush(int s) { 634 emitOp(Opcode.SIPUSH); 635 code.writeChar(s); 636 return thisBuilder(); 637 } 638 639 public C bipush(int b) { 640 emitOp(Opcode.BIPUSH); 641 code.writeByte(b); 642 return thisBuilder(); 643 } 644 645 public C pop() { 646 return emitOp(Opcode.POP); 647 } 648 649 public C pop2() { 650 return emitOp(Opcode.POP2); 651 } 652 653 public C dup() { 654 return emitOp(Opcode.DUP); 655 } 656 657 public C dup_x1() { 658 return emitOp(Opcode.DUP_X1); 659 } 660 661 public C dup_x2() { 662 return emitOp(Opcode.DUP_X2); 663 } 664 665 public C dup2() { 666 return emitOp(Opcode.DUP2); 667 } 668 669 public C dup2_x1() { 670 return emitOp(Opcode.DUP2_X1); 671 } 672 673 public C dup2_x2() { 674 return emitOp(Opcode.DUP2_X2); 675 } 676 677 public C swap() { 678 return emitOp(Opcode.SWAP); 679 } 680 681 public C iadd() { 682 return emitOp(Opcode.IADD); 683 } 684 685 public C ladd() { 686 return emitOp(Opcode.LADD); 687 } 688 689 public C fadd() { 690 return emitOp(Opcode.FADD); 691 } 692 693 public C dadd() { 694 return emitOp(Opcode.DADD); 695 } 696 697 public C isub() { 698 return emitOp(Opcode.ISUB); 699 } 700 701 public C lsub() { 702 return emitOp(Opcode.LSUB); 703 } 704 705 public C fsub() { 706 return emitOp(Opcode.FSUB); 707 } 708 709 public C dsub() { 710 return emitOp(Opcode.DSUB); 711 } 712 713 public C imul() { 714 return emitOp(Opcode.IMUL); 715 } 716 717 public C lmul() { 718 return emitOp(Opcode.LMUL); 719 } 720 721 public C fmul() { 722 return emitOp(Opcode.FMUL); 723 } 724 725 public C dmul() { 726 return emitOp(Opcode.DMUL); 727 } 728 729 public C idiv() { 730 return emitOp(Opcode.IDIV); 731 } 732 733 public C ldiv() { 734 return emitOp(Opcode.LDIV); 735 } 736 737 public C fdiv() { 738 return emitOp(Opcode.FDIV); 739 } 740 741 public C ddiv() { 742 return emitOp(Opcode.DDIV); 743 } 744 745 public C irem() { 746 return emitOp(Opcode.IREM); 747 } 748 749 public C lrem() { 750 return emitOp(Opcode.LREM); 751 } 752 753 public C frem() { 754 return emitOp(Opcode.FREM); 755 } 756 757 public C drem() { 758 return emitOp(Opcode.DREM); 759 } 760 761 public C ineg() { 762 return emitOp(Opcode.INEG); 763 } 764 765 public C lneg() { 766 return emitOp(Opcode.LNEG); 767 } 768 769 public C fneg() { 770 return emitOp(Opcode.FNEG); 771 } 772 773 public C dneg() { 774 return emitOp(Opcode.DNEG); 775 } 776 777 public C ishl() { 778 return emitOp(Opcode.ISHL); 779 } 780 781 public C lshl() { 782 return emitOp(Opcode.LSHL); 783 } 784 785 public C ishr() { 786 return emitOp(Opcode.ISHR); 787 } 788 789 public C lshr() { 790 return emitOp(Opcode.LSHR); 791 } 792 793 public C iushr() { 794 return emitOp(Opcode.IUSHR); 795 } 796 797 public C lushr() { 798 return emitOp(Opcode.LUSHR); 799 } 800 801 public C iand() { 802 return emitOp(Opcode.IAND); 803 } 804 805 public C land() { 806 return emitOp(Opcode.LAND); 807 } 808 809 public C ior() { 810 return emitOp(Opcode.IOR); 811 } 812 813 public C lor() { 814 return emitOp(Opcode.LOR); 815 } 816 817 public C ixor() { 818 return emitOp(Opcode.IXOR); 819 } 820 821 public C lxor() { 822 return emitOp(Opcode.LXOR); 823 } 824 825 public C iinc(int index, int val) { 826 return emitWideIfNeeded(Opcode.IINC, index, val); 827 } 828 829 public C i2l() { 830 return emitOp(Opcode.I2L); 831 } 832 833 public C i2f() { 834 return emitOp(Opcode.I2F); 835 } 836 837 public C i2d() { 838 return emitOp(Opcode.I2D); 839 } 840 841 public C l2i() { 842 return emitOp(Opcode.L2I); 843 } 844 845 public C l2f() { 846 return emitOp(Opcode.L2F); 847 } 848 849 public C l2d() { 850 return emitOp(Opcode.L2D); 851 } 852 853 public C f2i() { 854 return emitOp(Opcode.F2I); 855 } 856 857 public C f2l() { 858 return emitOp(Opcode.F2L); 859 } 860 861 public C f2d() { 862 return emitOp(Opcode.F2D); 863 } 864 865 public C d2i() { 866 return emitOp(Opcode.D2I); 867 } 868 869 public C d2l() { 870 return emitOp(Opcode.D2L); 871 } 872 873 public C d2f() { 874 return emitOp(Opcode.D2F); 875 } 876 877 public C i2b() { 878 return emitOp(Opcode.I2B); 879 } 880 881 public C i2c() { 882 return emitOp(Opcode.I2C); 883 } 884 885 public C i2s() { 886 return emitOp(Opcode.I2S); 887 } 888 889 public C lcmp() { 890 return emitOp(Opcode.LCMP); 891 } 892 893 public C fcmpl() { 894 return emitOp(Opcode.FCMPL); 895 } 896 897 public C fcmpg() { 898 return emitOp(Opcode.FCMPG); 899 } 900 901 public C dcmpl() { 902 return emitOp(Opcode.DCMPL); 903 } 904 905 public C dcmpg() { 906 return emitOp(Opcode.DCMPG); 907 } 908 909 public C ifeq(short target) { 910 return emitNarrowJumpOp(Opcode.IFEQ, target); 911 } 912 913 public C ifne(short target) { 914 return emitNarrowJumpOp(Opcode.IFNE, target); 915 } 916 917 public C iflt(short target) { 918 return emitNarrowJumpOp(Opcode.IFLT, target); 919 } 920 921 public C ifge(short target) { 922 return emitNarrowJumpOp(Opcode.IFGE, target); 923 } 924 925 public C ifgt(short target) { 926 return emitNarrowJumpOp(Opcode.IFGT, target); 927 } 928 929 public C ifle(short target) { 930 return emitNarrowJumpOp(Opcode.IFLE, target); 931 } 932 933 public C if_icmpeq(short target) { 934 return emitNarrowJumpOp(Opcode.IF_ICMPEQ, target); 935 } 936 937 public C if_icmpne(short target) { 938 return emitNarrowJumpOp(Opcode.IF_ICMPNE, target); 939 } 940 941 public C if_icmplt(short target) { 942 return emitNarrowJumpOp(Opcode.IF_ICMPLT, target); 943 } 944 945 public C if_icmpge(short target) { 946 return emitNarrowJumpOp(Opcode.IF_ICMPGE, target); 947 } 948 949 public C if_icmpgt(short target) { 950 return emitNarrowJumpOp(Opcode.IF_ICMPGT, target); 951 } 952 953 public C if_icmple(short target) { 954 return emitNarrowJumpOp(Opcode.IF_ICMPLE, target); 955 } 956 957 public C if_acmpeq(short target) { 958 return emitNarrowJumpOp(Opcode.IF_ACMPEQ, target); 959 } 960 961 public C if_acmpne(short target) { 962 return emitNarrowJumpOp(Opcode.IF_ACMPNE, target); 963 } 964 965 public C goto_(short target) { 966 return emitNarrowJumpOp(Opcode.GOTO_, target); 967 } 968 969 public C jsr(short target) { 970 return emitNarrowJumpOp(Opcode.JSR, target); 971 } 972 973 public C ret(int index) { 974 return emitWideIfNeeded(Opcode.RET, index); 975 } 976 977 public C tableswitch(int low, int high, int defaultTarget, int... targets) { 978 if (high - low + 1 != targets.length) throw new IllegalStateException("Bad targets length"); 979 emitOp(Opcode.TABLESWITCH); 980 //padding 981 int start = code.offset; 982 if ((start % 4) != 0) { 983 //add padding 984 for (int i = 0; i < 4 - (start % 4); i++) { 985 code.writeByte(0); 986 } 987 } 988 code.writeInt(defaultTarget) 989 .writeInt(low) 990 .writeInt(high); 991 for (int target : targets) { 992 code.writeInt(target); 993 } 994 return thisBuilder(); 995 } 996 997 public C lookupswitch(int defaultTarget, int... npairs) { 998 if (npairs.length % 2 != 0) throw new IllegalStateException("Bad npairs length"); 999 emitOp(Opcode.LOOKUPSWITCH); 1000 //padding 1001 int start = code.offset; 1002 for (int i = 0; i < (4 - (start % 4)); i++) { 1003 code.writeByte(0); 1004 } 1005 code.writeInt(defaultTarget) 1006 .writeInt(npairs.length / 2); 1007 for (int i = 0; i < npairs.length; i += 2) { 1008 code.writeInt(npairs[i]); 1009 code.writeInt(npairs[i + 1]); 1010 } 1011 return thisBuilder(); 1012 } 1013 1014 public C arraylength() { 1015 return emitOp(Opcode.ARRAYLENGTH); 1016 } 1017 1018 public C athrow() { 1019 return emitOp(Opcode.ATHROW); 1020 } 1021 1022 public C monitorenter() { 1023 return emitOp(Opcode.MONITORENTER); 1024 } 1025 1026 public C monitorexit() { 1027 return emitOp(Opcode.MONITOREXIT); 1028 } 1029 1030 public C wide() { 1031 return emitOp(Opcode.WIDE); 1032 } 1033 1034 public C if_null(short offset) { 1035 return emitNarrowJumpOp(Opcode.IF_NULL, offset); 1036 } 1037 1038 public C if_nonnull(short offset) { 1039 return emitNarrowJumpOp(Opcode.IF_NONNULL, offset); 1040 } 1041 1042 public C goto_w(int target) { 1043 return emitWideJumpOp(Opcode.GOTO_W, target); 1044 } 1045 1046 public C jsr_w(int target) { 1047 return emitWideJumpOp(Opcode.JSR_W, target); 1048 } 1049 1050 public C withCatch(S type, int start, int end, int offset) { 1051 catchers.writeChar(start); 1052 catchers.writeChar(end); 1053 catchers.writeChar(offset); 1054 catchers.writeChar(type != null ? poolHelper.putClass(type) : 0); 1055 ncatchers++; 1056 return thisBuilder(); 1057 } 1058 1059 public C withLocalSize(int localsize) { 1060 this.localsize = localsize; 1061 return thisBuilder(); 1062 } 1063 1064 public C withStackSize(int stacksize) { 1065 this.stacksize = stacksize; 1066 return thisBuilder(); 1067 } 1068 1069 protected int localsize() { 1070 return localsize; 1071 } 1072 1073 void build(GrowableByteBuffer buf) { 1074 buf.writeChar(stacksize); //max stack size 1075 buf.writeChar(localsize()); //max locals 1076 buf.writeInt(code.offset); 1077 buf.writeBytes(code); 1078 buf.writeChar(ncatchers); 1079 buf.writeBytes(catchers); 1080 buf.writeChar(nattrs); //attributes 1081 buf.writeBytes(attributes); 1082 } 1083 1084 byte[] build() { 1085 GrowableByteBuffer buf = new GrowableByteBuffer(); 1086 build(buf); 1087 return buf.bytes(); 1088 } 1089 1090 protected C emitNarrowJumpOp(Opcode opcode, short target) { 1091 emitOp(opcode); 1092 emitOffset(code, JumpMode.NARROW, target); 1093 return thisBuilder(); 1094 } 1095 1096 protected C emitWideJumpOp(Opcode opcode, int target) { 1097 emitOp(opcode); 1098 emitOffset(code, JumpMode.WIDE, target); 1099 return thisBuilder(); 1100 } 1101 1102 protected C emitOp(Opcode opcode) { 1103 return emitOp(opcode, null); 1104 } 1105 1106 protected C emitOp(Opcode opcode, Object optPoolValue) { 1107 code.writeByte(opcode.code); 1108 return thisBuilder(); 1109 } 1110 1111 protected void emitOffset(GrowableByteBuffer buf, JumpMode jumpMode, int offset) { 1112 if (jumpMode == JumpMode.NARROW) { 1113 buf.writeChar((short) offset); 1114 } else { 1115 buf.writeInt(offset); 1116 } 1117 } 1118 1119 int offset() { 1120 return code.offset; 1121 } 1122 1123 /*** stackmap support ***/ 1124 1125 /** 1126 * The tags and constants used in compressed stackmap. 1127 */ 1128 static final int SAME_FRAME_SIZE = 64; 1129 static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; 1130 static final int SAME_FRAME_EXTENDED = 251; 1131 static final int FULL_FRAME = 255; 1132 static final int MAX_LOCAL_LENGTH_DIFF = 4; 1133 1134 @SuppressWarnings("unchecked") 1135 private void writeStackMapType(T t) { 1136 if (t == null) { 1137 stackmaps.writeByte(0); 1138 } else { 1139 switch (typeHelper.tag(t)) { 1140 case B: 1141 case C: 1142 case S: 1143 case I: 1144 case Z: 1145 stackmaps.writeByte(1); 1146 break; 1147 case F: 1148 stackmaps.writeByte(2); 1149 break; 1150 case D: 1151 stackmaps.writeByte(3); 1152 break; 1153 case J: 1154 stackmaps.writeByte(4); 1155 break; 1156 case A: 1157 if (t == typeHelper.nullType()) { 1158 stackmaps.writeByte(5); //null 1159 } else { 1160 //TODO: uninit this, top? 1161 stackmaps.writeByte(7); 1162 stackmaps.writeChar(poolHelper.putClass(typeHelper.symbol(t))); 1163 } 1164 break; 1165 default: 1166 throw new IllegalStateException("Bad type"); 1167 } 1168 } 1169 } 1170 1171 public void sameFrame(int offsetDelta) { 1172 int frameType = (offsetDelta < SAME_FRAME_SIZE) ? 1173 offsetDelta : SAME_FRAME_EXTENDED; 1174 stackmaps.writeByte(frameType); 1175 if (frameType == SAME_FRAME_EXTENDED) { 1176 stackmaps.writeChar(offsetDelta); 1177 } 1178 } 1179 1180 public void sameLocals1StackItemFrame(int offsetDelta, T stackItem) { 1181 int frameType = (offsetDelta < SAME_FRAME_SIZE) ? 1182 (SAME_FRAME_SIZE + offsetDelta) : SAME_LOCALS_1_STACK_ITEM_EXTENDED; 1183 stackmaps.writeByte(frameType); 1184 if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 1185 stackmaps.writeChar(offsetDelta); 1186 } 1187 writeStackMapType(stackItem); 1188 } 1189 1190 public void appendFrame(int offsetDelta, int prevLocalsSize, List<T> locals) { 1191 int frameType = SAME_FRAME_EXTENDED + (locals.size() - prevLocalsSize); 1192 stackmaps.writeByte(frameType); 1193 stackmaps.writeChar(offsetDelta); 1194 for (int i = prevLocalsSize; i < locals.size(); i++) { 1195 writeStackMapType(locals.get(i)); 1196 } 1197 } 1198 1199 public void chopFrame(int offsetDelta, int droppedVars) { 1200 int frameType = SAME_FRAME_EXTENDED - droppedVars; 1201 stackmaps.writeByte(frameType); 1202 stackmaps.writeChar(offsetDelta); 1203 } 1204 1205 public void fullFrame(int offsetDelta, List<T> locals, List<T> stackItems) { 1206 stackmaps.writeByte(FULL_FRAME); 1207 stackmaps.writeChar(offsetDelta); 1208 stackmaps.writeChar(locals.size()); 1209 for (T local : locals) { 1210 writeStackMapType(local); 1211 } 1212 1213 stackmaps.writeChar(stackItems.size()); 1214 for (T stackType : stackItems) { 1215 writeStackMapType(stackType); 1216 } 1217 } 1218 }