1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later, 9 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.bytecode; 18 19 import javassist.CtClass; 20 import javassist.CtPrimitiveType; 21 22 class ByteVector implements Cloneable { 23 private byte[] buffer; 24 private int size; 25 ByteVector()26 public ByteVector() { 27 buffer = new byte[64]; 28 size = 0; 29 } 30 31 @Override clone()32 public Object clone() throws CloneNotSupportedException { 33 ByteVector bv = (ByteVector)super.clone(); 34 bv.buffer = (byte[])buffer.clone(); 35 return bv; 36 } 37 getSize()38 public final int getSize() { return size; } 39 copy()40 public final byte[] copy() { 41 byte[] b = new byte[size]; 42 System.arraycopy(buffer, 0, b, 0, size); 43 return b; 44 } 45 read(int offset)46 public int read(int offset) { 47 if (offset < 0 || size <= offset) 48 throw new ArrayIndexOutOfBoundsException(offset); 49 50 return buffer[offset]; 51 } 52 write(int offset, int value)53 public void write(int offset, int value) { 54 if (offset < 0 || size <= offset) 55 throw new ArrayIndexOutOfBoundsException(offset); 56 57 buffer[offset] = (byte)value; 58 } 59 add(int code)60 public void add(int code) { 61 addGap(1); 62 buffer[size - 1] = (byte)code; 63 } 64 add(int b1, int b2)65 public void add(int b1, int b2) { 66 addGap(2); 67 buffer[size - 2] = (byte)b1; 68 buffer[size - 1] = (byte)b2; 69 } 70 add(int b1, int b2, int b3, int b4)71 public void add(int b1, int b2, int b3, int b4) { 72 addGap(4); 73 buffer[size - 4] = (byte)b1; 74 buffer[size - 3] = (byte)b2; 75 buffer[size - 2] = (byte)b3; 76 buffer[size - 1] = (byte)b4; 77 } 78 addGap(int length)79 public void addGap(int length) { 80 if (size + length > buffer.length) { 81 int newSize = size << 1; 82 if (newSize < size + length) 83 newSize = size + length; 84 85 byte[] newBuf = new byte[newSize]; 86 System.arraycopy(buffer, 0, newBuf, 0, size); 87 buffer = newBuf; 88 } 89 90 size += length; 91 } 92 } 93 94 /** 95 * A utility class for producing a bytecode sequence. 96 * 97 * <p>A <code>Bytecode</code> object is an unbounded array 98 * containing bytecode. For example, 99 * 100 * <pre> 101 * ConstPool cp = ...; // constant pool table 102 * Bytecode b = new Bytecode(cp, 1, 0); 103 * b.addIconst(3); 104 * b.addReturn(CtClass.intType); 105 * CodeAttribute ca = b.toCodeAttribute();</pre> 106 * 107 * <p>This program produces a Code attribute including a bytecode 108 * sequence: 109 * 110 * <pre> 111 * iconst_3 112 * ireturn</pre> 113 * 114 * @see ConstPool 115 * @see CodeAttribute 116 */ 117 public class Bytecode extends ByteVector implements Cloneable, Opcode { 118 /** 119 * Represents the <code>CtClass</code> file using the 120 * constant pool table given to this <code>Bytecode</code> object. 121 */ 122 public static final CtClass THIS = ConstPool.THIS; 123 124 ConstPool constPool; 125 int maxStack, maxLocals; 126 ExceptionTable tryblocks; 127 private int stackDepth; 128 129 /** 130 * Constructs a <code>Bytecode</code> object with an empty bytecode 131 * sequence. 132 * 133 * <p>The parameters <code>stacksize</code> and <code>localvars</code> 134 * specify initial values 135 * of <code>max_stack</code> and <code>max_locals</code>. 136 * They can be changed later. 137 * 138 * @param cp constant pool table. 139 * @param stacksize <code>max_stack</code>. 140 * @param localvars <code>max_locals</code>. 141 */ Bytecode(ConstPool cp, int stacksize, int localvars)142 public Bytecode(ConstPool cp, int stacksize, int localvars) { 143 constPool = cp; 144 maxStack = stacksize; 145 maxLocals = localvars; 146 tryblocks = new ExceptionTable(cp); 147 stackDepth = 0; 148 } 149 150 /** 151 * Constructs a <code>Bytecode</code> object with an empty bytecode 152 * sequence. The initial values of <code>max_stack</code> and 153 * <code>max_locals</code> are zero. 154 * 155 * @param cp constant pool table. 156 * @see Bytecode#setMaxStack(int) 157 * @see Bytecode#setMaxLocals(int) 158 */ Bytecode(ConstPool cp)159 public Bytecode(ConstPool cp) { 160 this(cp, 0, 0); 161 } 162 163 /** 164 * Creates and returns a copy of this object. 165 * The constant pool object is shared between this object 166 * and the cloned object. 167 */ 168 @Override clone()169 public Object clone() { 170 try { 171 Bytecode bc = (Bytecode)super.clone(); 172 bc.tryblocks = (ExceptionTable)tryblocks.clone(); 173 return bc; 174 } 175 catch (CloneNotSupportedException cnse) { 176 throw new RuntimeException(cnse); 177 } 178 } 179 180 /** 181 * Gets a constant pool table. 182 */ getConstPool()183 public ConstPool getConstPool() { return constPool; } 184 185 /** 186 * Returns <code>exception_table</code>. 187 */ getExceptionTable()188 public ExceptionTable getExceptionTable() { return tryblocks; } 189 190 /** 191 * Converts to a <code>CodeAttribute</code>. 192 */ toCodeAttribute()193 public CodeAttribute toCodeAttribute() { 194 return new CodeAttribute(constPool, maxStack, maxLocals, 195 get(), tryblocks); 196 } 197 198 /** 199 * Returns the length of the bytecode sequence. 200 */ length()201 public int length() { 202 return getSize(); 203 } 204 205 /** 206 * Returns the produced bytecode sequence. 207 */ get()208 public byte[] get() { 209 return copy(); 210 } 211 212 /** 213 * Gets <code>max_stack</code>. 214 */ getMaxStack()215 public int getMaxStack() { return maxStack; } 216 217 /** 218 * Sets <code>max_stack</code>. 219 * 220 * <p>This value may be automatically updated when an instruction 221 * is appended. A <code>Bytecode</code> object maintains the current 222 * stack depth whenever an instruction is added 223 * by <code>addOpcode()</code>. For example, if DUP is appended, 224 * the current stack depth is increased by one. If the new stack 225 * depth is more than <code>max_stack</code>, then it is assigned 226 * to <code>max_stack</code>. However, if branch instructions are 227 * appended, the current stack depth may not be correctly maintained. 228 * 229 * @see #addOpcode(int) 230 */ setMaxStack(int size)231 public void setMaxStack(int size) { 232 maxStack = size; 233 } 234 235 /** 236 * Gets <code>max_locals</code>. 237 */ getMaxLocals()238 public int getMaxLocals() { return maxLocals; } 239 240 /** 241 * Sets <code>max_locals</code>. 242 */ setMaxLocals(int size)243 public void setMaxLocals(int size) { 244 maxLocals = size; 245 } 246 247 /** 248 * Sets <code>max_locals</code>. 249 * 250 * <p>This computes the number of local variables 251 * used to pass method parameters and sets <code>max_locals</code> 252 * to that number plus <code>locals</code>. 253 * 254 * @param isStatic true if <code>params</code> must be 255 * interpreted as parameters to a static method. 256 * @param params parameter types. 257 * @param locals the number of local variables excluding 258 * ones used to pass parameters. 259 */ setMaxLocals(boolean isStatic, CtClass[] params, int locals)260 public void setMaxLocals(boolean isStatic, CtClass[] params, 261 int locals) { 262 if (!isStatic) 263 ++locals; 264 265 if (params != null) { 266 CtClass doubleType = CtClass.doubleType; 267 CtClass longType = CtClass.longType; 268 int n = params.length; 269 for (int i = 0; i < n; ++i) { 270 CtClass type = params[i]; 271 if (type == doubleType || type == longType) 272 locals += 2; 273 else 274 ++locals; 275 } 276 } 277 278 maxLocals = locals; 279 } 280 281 /** 282 * Increments <code>max_locals</code>. 283 */ incMaxLocals(int diff)284 public void incMaxLocals(int diff) { 285 maxLocals += diff; 286 } 287 288 /** 289 * Adds a new entry of <code>exception_table</code>. 290 */ addExceptionHandler(int start, int end, int handler, CtClass type)291 public void addExceptionHandler(int start, int end, 292 int handler, CtClass type) { 293 addExceptionHandler(start, end, handler, 294 constPool.addClassInfo(type)); 295 } 296 297 /** 298 * Adds a new entry of <code>exception_table</code>. 299 * 300 * @param type the fully-qualified name of a throwable class. 301 */ addExceptionHandler(int start, int end, int handler, String type)302 public void addExceptionHandler(int start, int end, 303 int handler, String type) { 304 addExceptionHandler(start, end, handler, 305 constPool.addClassInfo(type)); 306 } 307 308 /** 309 * Adds a new entry of <code>exception_table</code>. 310 */ addExceptionHandler(int start, int end, int handler, int type)311 public void addExceptionHandler(int start, int end, 312 int handler, int type) { 313 tryblocks.add(start, end, handler, type); 314 } 315 316 /** 317 * Returns the length of bytecode sequence 318 * that have been added so far. 319 */ currentPc()320 public int currentPc() { 321 return getSize(); 322 } 323 324 /** 325 * Reads a signed 8bit value at the offset from the beginning of the 326 * bytecode sequence. 327 * 328 * @throws ArrayIndexOutOfBoundsException if offset is invalid. 329 */ 330 @Override read(int offset)331 public int read(int offset) { 332 return super.read(offset); 333 } 334 335 /** 336 * Reads a signed 16bit value at the offset from the beginning of the 337 * bytecode sequence. 338 */ read16bit(int offset)339 public int read16bit(int offset) { 340 int v1 = read(offset); 341 int v2 = read(offset + 1); 342 return (v1 << 8) + (v2 & 0xff); 343 } 344 345 /** 346 * Reads a signed 32bit value at the offset from the beginning of the 347 * bytecode sequence. 348 */ read32bit(int offset)349 public int read32bit(int offset) { 350 int v1 = read16bit(offset); 351 int v2 = read16bit(offset + 2); 352 return (v1 << 16) + (v2 & 0xffff); 353 } 354 355 /** 356 * Writes an 8bit value at the offset from the beginning of the 357 * bytecode sequence. 358 * 359 * @throws ArrayIndexOutOfBoundsException if offset is invalid. 360 */ 361 @Override write(int offset, int value)362 public void write(int offset, int value) { 363 super.write(offset, value); 364 } 365 366 /** 367 * Writes an 16bit value at the offset from the beginning of the 368 * bytecode sequence. 369 */ write16bit(int offset, int value)370 public void write16bit(int offset, int value) { 371 write(offset, value >> 8); 372 write(offset + 1, value); 373 } 374 375 /** 376 * Writes an 32bit value at the offset from the beginning of the 377 * bytecode sequence. 378 */ write32bit(int offset, int value)379 public void write32bit(int offset, int value) { 380 write16bit(offset, value >> 16); 381 write16bit(offset + 2, value); 382 } 383 384 /** 385 * Appends an 8bit value to the end of the bytecode sequence. 386 */ 387 @Override add(int code)388 public void add(int code) { 389 super.add(code); 390 } 391 392 /** 393 * Appends a 32bit value to the end of the bytecode sequence. 394 */ add32bit(int value)395 public void add32bit(int value) { 396 add(value >> 24, value >> 16, value >> 8, value); 397 } 398 399 /** 400 * Appends the length-byte gap to the end of the bytecode sequence. 401 * 402 * @param length the gap length in byte. 403 */ 404 @Override addGap(int length)405 public void addGap(int length) { 406 super.addGap(length); 407 } 408 409 /** 410 * Appends an 8bit opcode to the end of the bytecode sequence. 411 * The current stack depth is updated. 412 * <code>max_stack</code> is updated if the current stack depth 413 * is the deepest so far. 414 * 415 * <p>Note: some instructions such as INVOKEVIRTUAL does not 416 * update the current stack depth since the increment depends 417 * on the method signature. 418 * <code>growStack()</code> must be explicitly called. 419 */ addOpcode(int code)420 public void addOpcode(int code) { 421 add(code); 422 growStack(STACK_GROW[code]); 423 } 424 425 /** 426 * Increases the current stack depth. 427 * It also updates <code>max_stack</code> if the current stack depth 428 * is the deepest so far. 429 * 430 * @param diff the number added to the current stack depth. 431 */ growStack(int diff)432 public void growStack(int diff) { 433 setStackDepth(stackDepth + diff); 434 } 435 436 /** 437 * Returns the current stack depth. 438 */ getStackDepth()439 public int getStackDepth() { return stackDepth; } 440 441 /** 442 * Sets the current stack depth. 443 * It also updates <code>max_stack</code> if the current stack depth 444 * is the deepest so far. 445 * 446 * @param depth new value. 447 */ setStackDepth(int depth)448 public void setStackDepth(int depth) { 449 stackDepth = depth; 450 if (stackDepth > maxStack) 451 maxStack = stackDepth; 452 } 453 454 /** 455 * Appends a 16bit value to the end of the bytecode sequence. 456 * It never changes the current stack depth. 457 */ addIndex(int index)458 public void addIndex(int index) { 459 add(index >> 8, index); 460 } 461 462 /** 463 * Appends ALOAD or (WIDE) ALOAD_<n> 464 * 465 * @param n an index into the local variable array. 466 */ addAload(int n)467 public void addAload(int n) { 468 if (n < 4) 469 addOpcode(42 + n); // aload_<n> 470 else if (n < 0x100) { 471 addOpcode(ALOAD); // aload 472 add(n); 473 } 474 else { 475 addOpcode(WIDE); 476 addOpcode(ALOAD); 477 addIndex(n); 478 } 479 } 480 481 /** 482 * Appends ASTORE or (WIDE) ASTORE_<n> 483 * 484 * @param n an index into the local variable array. 485 */ addAstore(int n)486 public void addAstore(int n) { 487 if (n < 4) 488 addOpcode(75 + n); // astore_<n> 489 else if (n < 0x100) { 490 addOpcode(ASTORE); // astore 491 add(n); 492 } 493 else { 494 addOpcode(WIDE); 495 addOpcode(ASTORE); 496 addIndex(n); 497 } 498 } 499 500 /** 501 * Appends ICONST or ICONST_<n> 502 * 503 * @param n the pushed integer constant. 504 */ addIconst(int n)505 public void addIconst(int n) { 506 if (n < 6 && -2 < n) 507 addOpcode(3 + n); // iconst_<i> -1..5 508 else if (n <= 127 && -128 <= n) { 509 addOpcode(16); // bipush 510 add(n); 511 } 512 else if (n <= 32767 && -32768 <= n) { 513 addOpcode(17); // sipush 514 add(n >> 8); 515 add(n); 516 } 517 else 518 addLdc(constPool.addIntegerInfo(n)); 519 } 520 521 /** 522 * Appends an instruction for pushing zero or null on the stack. 523 * If the type is void, this method does not append any instruction. 524 * 525 * @param type the type of the zero value (or null). 526 */ addConstZero(CtClass type)527 public void addConstZero(CtClass type) { 528 if (type.isPrimitive()) { 529 if (type == CtClass.longType) 530 addOpcode(LCONST_0); 531 else if (type == CtClass.floatType) 532 addOpcode(FCONST_0); 533 else if (type == CtClass.doubleType) 534 addOpcode(DCONST_0); 535 else if (type == CtClass.voidType) 536 throw new RuntimeException("void type?"); 537 else 538 addOpcode(ICONST_0); 539 } 540 else 541 addOpcode(ACONST_NULL); 542 } 543 544 /** 545 * Appends ILOAD or (WIDE) ILOAD_<n> 546 * 547 * @param n an index into the local variable array. 548 */ addIload(int n)549 public void addIload(int n) { 550 if (n < 4) 551 addOpcode(26 + n); // iload_<n> 552 else if (n < 0x100) { 553 addOpcode(ILOAD); // iload 554 add(n); 555 } 556 else { 557 addOpcode(WIDE); 558 addOpcode(ILOAD); 559 addIndex(n); 560 } 561 } 562 563 /** 564 * Appends ISTORE or (WIDE) ISTORE_<n> 565 * 566 * @param n an index into the local variable array. 567 */ addIstore(int n)568 public void addIstore(int n) { 569 if (n < 4) 570 addOpcode(59 + n); // istore_<n> 571 else if (n < 0x100) { 572 addOpcode(ISTORE); // istore 573 add(n); 574 } 575 else { 576 addOpcode(WIDE); 577 addOpcode(ISTORE); 578 addIndex(n); 579 } 580 } 581 582 /** 583 * Appends LCONST or LCONST_<n> 584 * 585 * @param n the pushed long integer constant. 586 */ addLconst(long n)587 public void addLconst(long n) { 588 if (n == 0 || n == 1) 589 addOpcode(9 + (int)n); // lconst_<n> 590 else 591 addLdc2w(n); 592 } 593 594 /** 595 * Appends LLOAD or (WIDE) LLOAD_<n> 596 * 597 * @param n an index into the local variable array. 598 */ addLload(int n)599 public void addLload(int n) { 600 if (n < 4) 601 addOpcode(30 + n); // lload_<n> 602 else if (n < 0x100) { 603 addOpcode(LLOAD); // lload 604 add(n); 605 } 606 else { 607 addOpcode(WIDE); 608 addOpcode(LLOAD); 609 addIndex(n); 610 } 611 } 612 613 /** 614 * Appends LSTORE or LSTORE_<n> 615 * 616 * @param n an index into the local variable array. 617 */ addLstore(int n)618 public void addLstore(int n) { 619 if (n < 4) 620 addOpcode(63 + n); // lstore_<n> 621 else if (n < 0x100) { 622 addOpcode(LSTORE); // lstore 623 add(n); 624 } 625 else { 626 addOpcode(WIDE); 627 addOpcode(LSTORE); 628 addIndex(n); 629 } 630 } 631 632 /** 633 * Appends DCONST or DCONST_<n> 634 * 635 * @param d the pushed double constant. 636 */ addDconst(double d)637 public void addDconst(double d) { 638 if (d == 0.0 || d == 1.0) 639 addOpcode(14 + (int)d); // dconst_<n> 640 else 641 addLdc2w(d); 642 } 643 644 /** 645 * Appends DLOAD or (WIDE) DLOAD_<n> 646 * 647 * @param n an index into the local variable array. 648 */ addDload(int n)649 public void addDload(int n) { 650 if (n < 4) 651 addOpcode(38 + n); // dload_<n> 652 else if (n < 0x100) { 653 addOpcode(DLOAD); // dload 654 add(n); 655 } 656 else { 657 addOpcode(WIDE); 658 addOpcode(DLOAD); 659 addIndex(n); 660 } 661 } 662 663 /** 664 * Appends DSTORE or (WIDE) DSTORE_<n> 665 * 666 * @param n an index into the local variable array. 667 */ addDstore(int n)668 public void addDstore(int n) { 669 if (n < 4) 670 addOpcode(71 + n); // dstore_<n> 671 else if (n < 0x100) { 672 addOpcode(DSTORE); // dstore 673 add(n); 674 } 675 else { 676 addOpcode(WIDE); 677 addOpcode(DSTORE); 678 addIndex(n); 679 } 680 } 681 682 /** 683 * Appends FCONST or FCONST_<n> 684 * 685 * @param f the pushed float constant. 686 */ addFconst(float f)687 public void addFconst(float f) { 688 if (f == 0.0f || f == 1.0f || f == 2.0f) 689 addOpcode(11 + (int)f); // fconst_<n> 690 else 691 addLdc(constPool.addFloatInfo(f)); 692 } 693 694 /** 695 * Appends FLOAD or (WIDE) FLOAD_<n> 696 * 697 * @param n an index into the local variable array. 698 */ addFload(int n)699 public void addFload(int n) { 700 if (n < 4) 701 addOpcode(34 + n); // fload_<n> 702 else if (n < 0x100) { 703 addOpcode(FLOAD); // fload 704 add(n); 705 } 706 else { 707 addOpcode(WIDE); 708 addOpcode(FLOAD); 709 addIndex(n); 710 } 711 } 712 713 /** 714 * Appends FSTORE or FSTORE_<n> 715 * 716 * @param n an index into the local variable array. 717 */ addFstore(int n)718 public void addFstore(int n) { 719 if (n < 4) 720 addOpcode(67 + n); // fstore_<n> 721 else if (n < 0x100) { 722 addOpcode(FSTORE); // fstore 723 add(n); 724 } 725 else { 726 addOpcode(WIDE); 727 addOpcode(FSTORE); 728 addIndex(n); 729 } 730 } 731 732 /** 733 * Appends an instruction for loading a value from the 734 * local variable at the index <code>n</code>. 735 * 736 * @param n the index. 737 * @param type the type of the loaded value. 738 * @return the size of the value (1 or 2 word). 739 */ addLoad(int n, CtClass type)740 public int addLoad(int n, CtClass type) { 741 if (type.isPrimitive()) { 742 if (type == CtClass.booleanType || type == CtClass.charType 743 || type == CtClass.byteType || type == CtClass.shortType 744 || type == CtClass.intType) 745 addIload(n); 746 else if (type == CtClass.longType) { 747 addLload(n); 748 return 2; 749 } 750 else if(type == CtClass.floatType) 751 addFload(n); 752 else if(type == CtClass.doubleType) { 753 addDload(n); 754 return 2; 755 } 756 else 757 throw new RuntimeException("void type?"); 758 } 759 else 760 addAload(n); 761 762 return 1; 763 } 764 765 /** 766 * Appends an instruction for storing a value into the 767 * local variable at the index <code>n</code>. 768 * 769 * @param n the index. 770 * @param type the type of the stored value. 771 * @return 2 if the type is long or double. Otherwise 1. 772 */ addStore(int n, CtClass type)773 public int addStore(int n, CtClass type) { 774 if (type.isPrimitive()) { 775 if (type == CtClass.booleanType || type == CtClass.charType 776 || type == CtClass.byteType || type == CtClass.shortType 777 || type == CtClass.intType) 778 addIstore(n); 779 else if (type == CtClass.longType) { 780 addLstore(n); 781 return 2; 782 } 783 else if (type == CtClass.floatType) 784 addFstore(n); 785 else if (type == CtClass.doubleType) { 786 addDstore(n); 787 return 2; 788 } 789 else 790 throw new RuntimeException("void type?"); 791 } 792 else 793 addAstore(n); 794 795 return 1; 796 } 797 798 /** 799 * Appends instructions for loading all the parameters onto the 800 * operand stack. 801 * 802 * @param offset the index of the first parameter. It is 0 803 * if the method is static. Otherwise, it is 1. 804 */ addLoadParameters(CtClass[] params, int offset)805 public int addLoadParameters(CtClass[] params, int offset) { 806 int stacksize = 0; 807 if (params != null) { 808 int n = params.length; 809 for (int i = 0; i < n; ++i) 810 stacksize += addLoad(stacksize + offset, params[i]); 811 } 812 813 return stacksize; 814 } 815 816 /** 817 * Appends CHECKCAST. 818 * 819 * @param c the type. 820 */ addCheckcast(CtClass c)821 public void addCheckcast(CtClass c) { 822 addOpcode(CHECKCAST); 823 addIndex(constPool.addClassInfo(c)); 824 } 825 826 /** 827 * Appends CHECKCAST. 828 * 829 * @param classname a fully-qualified class name. 830 */ addCheckcast(String classname)831 public void addCheckcast(String classname) { 832 addOpcode(CHECKCAST); 833 addIndex(constPool.addClassInfo(classname)); 834 } 835 836 /** 837 * Appends INSTANCEOF. 838 * 839 * @param classname the class name. 840 */ addInstanceof(String classname)841 public void addInstanceof(String classname) { 842 addOpcode(INSTANCEOF); 843 addIndex(constPool.addClassInfo(classname)); 844 } 845 846 /** 847 * Appends GETFIELD. 848 * 849 * @param c the class. 850 * @param name the field name. 851 * @param type the descriptor of the field type. 852 * 853 * @see Descriptor#of(CtClass) 854 */ addGetfield(CtClass c, String name, String type)855 public void addGetfield(CtClass c, String name, String type) { 856 add(GETFIELD); 857 int ci = constPool.addClassInfo(c); 858 addIndex(constPool.addFieldrefInfo(ci, name, type)); 859 growStack(Descriptor.dataSize(type) - 1); 860 } 861 862 /** 863 * Appends GETFIELD. 864 * 865 * @param c the fully-qualified class name. 866 * @param name the field name. 867 * @param type the descriptor of the field type. 868 * 869 * @see Descriptor#of(CtClass) 870 */ addGetfield(String c, String name, String type)871 public void addGetfield(String c, String name, String type) { 872 add(GETFIELD); 873 int ci = constPool.addClassInfo(c); 874 addIndex(constPool.addFieldrefInfo(ci, name, type)); 875 growStack(Descriptor.dataSize(type) - 1); 876 } 877 878 /** 879 * Appends GETSTATIC. 880 * 881 * @param c the class 882 * @param name the field name 883 * @param type the descriptor of the field type. 884 * 885 * @see Descriptor#of(CtClass) 886 */ addGetstatic(CtClass c, String name, String type)887 public void addGetstatic(CtClass c, String name, String type) { 888 add(GETSTATIC); 889 int ci = constPool.addClassInfo(c); 890 addIndex(constPool.addFieldrefInfo(ci, name, type)); 891 growStack(Descriptor.dataSize(type)); 892 } 893 894 /** 895 * Appends GETSTATIC. 896 * 897 * @param c the fully-qualified class name 898 * @param name the field name 899 * @param type the descriptor of the field type. 900 * 901 * @see Descriptor#of(CtClass) 902 */ addGetstatic(String c, String name, String type)903 public void addGetstatic(String c, String name, String type) { 904 add(GETSTATIC); 905 int ci = constPool.addClassInfo(c); 906 addIndex(constPool.addFieldrefInfo(ci, name, type)); 907 growStack(Descriptor.dataSize(type)); 908 } 909 910 /** 911 * Appends INVOKESPECIAL. 912 * 913 * @param clazz the target class. 914 * @param name the method name. 915 * @param returnType the return type. 916 * @param paramTypes the parameter types. 917 */ addInvokespecial(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)918 public void addInvokespecial(CtClass clazz, String name, 919 CtClass returnType, CtClass[] paramTypes) { 920 String desc = Descriptor.ofMethod(returnType, paramTypes); 921 addInvokespecial(clazz, name, desc); 922 } 923 924 /** 925 * Appends INVOKESPECIAL. 926 * 927 * @param clazz the target class. 928 * @param name the method name 929 * @param desc the descriptor of the method signature. 930 * 931 * @see Descriptor#ofMethod(CtClass,CtClass[]) 932 * @see Descriptor#ofConstructor(CtClass[]) 933 */ addInvokespecial(CtClass clazz, String name, String desc)934 public void addInvokespecial(CtClass clazz, String name, String desc) { 935 boolean isInterface = clazz == null ? false : clazz.isInterface(); 936 addInvokespecial(isInterface, 937 constPool.addClassInfo(clazz), name, desc); 938 } 939 940 /** 941 * Appends INVOKESPECIAL. The invoked method must not be a default 942 * method declared in an interface. 943 * 944 * @param clazz the fully-qualified class name. 945 * @param name the method name 946 * @param desc the descriptor of the method signature. 947 * 948 * @see Descriptor#ofMethod(CtClass,CtClass[]) 949 * @see Descriptor#ofConstructor(CtClass[]) 950 */ addInvokespecial(String clazz, String name, String desc)951 public void addInvokespecial(String clazz, String name, String desc) { 952 addInvokespecial(false, constPool.addClassInfo(clazz), name, desc); 953 } 954 955 /** 956 * Appends INVOKESPECIAL. The invoked method must not be a default 957 * method declared in an interface. 958 * 959 * @param clazz the index of <code>CONSTANT_Class_info</code> 960 * structure. 961 * @param name the method name 962 * @param desc the descriptor of the method signature. 963 * 964 * @see Descriptor#ofMethod(CtClass,CtClass[]) 965 * @see Descriptor#ofConstructor(CtClass[]) 966 */ addInvokespecial(int clazz, String name, String desc)967 public void addInvokespecial(int clazz, String name, String desc) { 968 addInvokespecial(false, clazz, name, desc); 969 } 970 971 /** 972 * Appends INVOKESPECIAL. 973 * 974 * @param isInterface true if the invoked method is a default method 975 * declared in an interface. 976 * @param clazz the index of <code>CONSTANT_Class_info</code> 977 * structure. 978 * @param name the method name 979 * @param desc the descriptor of the method signature. 980 * 981 * @see Descriptor#ofMethod(CtClass,CtClass[]) 982 * @see Descriptor#ofConstructor(CtClass[]) 983 */ addInvokespecial(boolean isInterface, int clazz, String name, String desc)984 public void addInvokespecial(boolean isInterface, int clazz, String name, String desc) { 985 int index; 986 if (isInterface) 987 index = constPool.addInterfaceMethodrefInfo(clazz, name, desc); 988 else 989 index = constPool.addMethodrefInfo(clazz, name, desc); 990 991 addInvokespecial(index, desc); 992 } 993 994 /** 995 * Appends INVOKESPECIAL. 996 * 997 * @param index the index of <code>CONSTANT_Methodref_info</code> 998 * or <code>CONSTANT_InterfaceMethodref_info</code> 999 * @param desc the descriptor of the method signature. 1000 * 1001 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1002 * @see Descriptor#ofConstructor(CtClass[]) 1003 */ addInvokespecial(int index, String desc)1004 public void addInvokespecial(int index, String desc) { 1005 add(INVOKESPECIAL); 1006 addIndex(index); 1007 growStack(Descriptor.dataSize(desc) - 1); 1008 } 1009 1010 /** 1011 * Appends INVOKESTATIC. 1012 * 1013 * @param clazz the target class. 1014 * @param name the method name 1015 * @param returnType the return type. 1016 * @param paramTypes the parameter types. 1017 */ addInvokestatic(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)1018 public void addInvokestatic(CtClass clazz, String name, 1019 CtClass returnType, CtClass[] paramTypes) { 1020 String desc = Descriptor.ofMethod(returnType, paramTypes); 1021 addInvokestatic(clazz, name, desc); 1022 } 1023 1024 /** 1025 * Appends INVOKESTATIC. 1026 * 1027 * @param clazz the target class. 1028 * @param name the method name 1029 * @param desc the descriptor of the method signature. 1030 * 1031 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1032 */ addInvokestatic(CtClass clazz, String name, String desc)1033 public void addInvokestatic(CtClass clazz, String name, String desc) { 1034 boolean isInterface; 1035 if (clazz == THIS) 1036 isInterface = false; 1037 else 1038 isInterface = clazz.isInterface(); 1039 1040 addInvokestatic(constPool.addClassInfo(clazz), name, desc, isInterface); 1041 } 1042 1043 /** 1044 * Appends INVOKESTATIC. 1045 * 1046 * @param classname the fully-qualified class name. 1047 * It must not be an interface-type name. 1048 * @param name the method name 1049 * @param desc the descriptor of the method signature. 1050 * 1051 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1052 */ addInvokestatic(String classname, String name, String desc)1053 public void addInvokestatic(String classname, String name, String desc) { 1054 addInvokestatic(constPool.addClassInfo(classname), name, desc); 1055 } 1056 1057 /** 1058 * Appends INVOKESTATIC. 1059 * 1060 * @param clazz the index of <code>CONSTANT_Class_info</code> 1061 * structure. It must not be an interface type. 1062 * @param name the method name 1063 * @param desc the descriptor of the method signature. 1064 * 1065 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1066 */ addInvokestatic(int clazz, String name, String desc)1067 public void addInvokestatic(int clazz, String name, String desc) { 1068 addInvokestatic(clazz, name, desc, false); 1069 } 1070 addInvokestatic(int clazz, String name, String desc, boolean isInterface)1071 private void addInvokestatic(int clazz, String name, String desc, 1072 boolean isInterface) { 1073 add(INVOKESTATIC); 1074 int index; 1075 if (isInterface) 1076 index = constPool.addInterfaceMethodrefInfo(clazz, name, desc); 1077 else 1078 index = constPool.addMethodrefInfo(clazz, name, desc); 1079 1080 addIndex(index); 1081 growStack(Descriptor.dataSize(desc)); 1082 } 1083 1084 /** 1085 * Appends INVOKEVIRTUAL. 1086 * 1087 * <p>The specified method must not be an inherited method. 1088 * It must be directly declared in the class specified 1089 * in <code>clazz</code>. 1090 * 1091 * @param clazz the target class. 1092 * @param name the method name 1093 * @param returnType the return type. 1094 * @param paramTypes the parameter types. 1095 */ addInvokevirtual(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)1096 public void addInvokevirtual(CtClass clazz, String name, 1097 CtClass returnType, CtClass[] paramTypes) { 1098 String desc = Descriptor.ofMethod(returnType, paramTypes); 1099 addInvokevirtual(clazz, name, desc); 1100 } 1101 1102 /** 1103 * Appends INVOKEVIRTUAL. 1104 * 1105 * <p>The specified method must not be an inherited method. 1106 * It must be directly declared in the class specified 1107 * in <code>clazz</code>. 1108 * 1109 * @param clazz the target class. 1110 * @param name the method name 1111 * @param desc the descriptor of the method signature. 1112 * 1113 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1114 */ addInvokevirtual(CtClass clazz, String name, String desc)1115 public void addInvokevirtual(CtClass clazz, String name, String desc) { 1116 addInvokevirtual(constPool.addClassInfo(clazz), name, desc); 1117 } 1118 1119 /** 1120 * Appends INVOKEVIRTUAL. 1121 * 1122 * <p>The specified method must not be an inherited method. 1123 * It must be directly declared in the class specified 1124 * in <code>classname</code>. 1125 * 1126 * @param classname the fully-qualified class name. 1127 * @param name the method name 1128 * @param desc the descriptor of the method signature. 1129 * 1130 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1131 */ addInvokevirtual(String classname, String name, String desc)1132 public void addInvokevirtual(String classname, String name, String desc) { 1133 addInvokevirtual(constPool.addClassInfo(classname), name, desc); 1134 } 1135 1136 /** 1137 * Appends INVOKEVIRTUAL. 1138 * 1139 * <p>The specified method must not be an inherited method. 1140 * It must be directly declared in the class specified 1141 * by <code>clazz</code>. 1142 * 1143 * @param clazz the index of <code>CONSTANT_Class_info</code> 1144 * structure. 1145 * @param name the method name 1146 * @param desc the descriptor of the method signature. 1147 * 1148 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1149 */ addInvokevirtual(int clazz, String name, String desc)1150 public void addInvokevirtual(int clazz, String name, String desc) { 1151 add(INVOKEVIRTUAL); 1152 addIndex(constPool.addMethodrefInfo(clazz, name, desc)); 1153 growStack(Descriptor.dataSize(desc) - 1); 1154 } 1155 1156 /** 1157 * Appends INVOKEINTERFACE. 1158 * 1159 * @param clazz the target class. 1160 * @param name the method name 1161 * @param returnType the return type. 1162 * @param paramTypes the parameter types. 1163 * @param count the count operand of the instruction. 1164 */ addInvokeinterface(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes, int count)1165 public void addInvokeinterface(CtClass clazz, String name, 1166 CtClass returnType, CtClass[] paramTypes, 1167 int count) { 1168 String desc = Descriptor.ofMethod(returnType, paramTypes); 1169 addInvokeinterface(clazz, name, desc, count); 1170 } 1171 1172 /** 1173 * Appends INVOKEINTERFACE. 1174 * 1175 * @param clazz the target class. 1176 * @param name the method name 1177 * @param desc the descriptor of the method signature. 1178 * @param count the count operand of the instruction. 1179 * 1180 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1181 */ addInvokeinterface(CtClass clazz, String name, String desc, int count)1182 public void addInvokeinterface(CtClass clazz, String name, 1183 String desc, int count) { 1184 addInvokeinterface(constPool.addClassInfo(clazz), name, desc, 1185 count); 1186 } 1187 1188 /** 1189 * Appends INVOKEINTERFACE. 1190 * 1191 * @param classname the fully-qualified class name. 1192 * @param name the method name 1193 * @param desc the descriptor of the method signature. 1194 * @param count the count operand of the instruction. 1195 * 1196 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1197 */ addInvokeinterface(String classname, String name, String desc, int count)1198 public void addInvokeinterface(String classname, String name, 1199 String desc, int count) { 1200 addInvokeinterface(constPool.addClassInfo(classname), name, desc, 1201 count); 1202 } 1203 1204 /** 1205 * Appends INVOKEINTERFACE. 1206 * 1207 * @param clazz the index of <code>CONSTANT_Class_info</code> 1208 * structure. 1209 * @param name the method name 1210 * @param desc the descriptor of the method signature. 1211 * @param count the count operand of the instruction. 1212 * 1213 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1214 */ addInvokeinterface(int clazz, String name, String desc, int count)1215 public void addInvokeinterface(int clazz, String name, 1216 String desc, int count) { 1217 add(INVOKEINTERFACE); 1218 addIndex(constPool.addInterfaceMethodrefInfo(clazz, name, desc)); 1219 add(count); 1220 add(0); 1221 growStack(Descriptor.dataSize(desc) - 1); 1222 } 1223 1224 /** 1225 * Appends INVOKEDYNAMIC. 1226 * 1227 * @param bootstrap an index into the <code>bootstrap_methods</code> array 1228 * of the bootstrap method table. 1229 * @param name the method name. 1230 * @param desc the method descriptor. 1231 * @see Descriptor#ofMethod(CtClass,CtClass[]) 1232 * @since 3.17 1233 */ addInvokedynamic(int bootstrap, String name, String desc)1234 public void addInvokedynamic(int bootstrap, String name, String desc) { 1235 int nt = constPool.addNameAndTypeInfo(name, desc); 1236 int dyn = constPool.addInvokeDynamicInfo(bootstrap, nt); 1237 add(INVOKEDYNAMIC); 1238 addIndex(dyn); 1239 add(0, 0); 1240 growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic 1241 } 1242 1243 /** 1244 * Appends LDC or LDC_W. The pushed item is a <code>String</code> 1245 * object. 1246 * 1247 * @param s the character string pushed by LDC or LDC_W. 1248 */ addLdc(String s)1249 public void addLdc(String s) { 1250 addLdc(constPool.addStringInfo(s)); 1251 } 1252 1253 /** 1254 * Appends LDC or LDC_W. 1255 * 1256 * @param i index into the constant pool. 1257 */ addLdc(int i)1258 public void addLdc(int i) { 1259 if (i > 0xFF) { 1260 addOpcode(LDC_W); 1261 addIndex(i); 1262 } 1263 else { 1264 addOpcode(LDC); 1265 add(i); 1266 } 1267 } 1268 1269 /** 1270 * Appends LDC2_W. The pushed item is a long value. 1271 */ addLdc2w(long l)1272 public void addLdc2w(long l) { 1273 addOpcode(LDC2_W); 1274 addIndex(constPool.addLongInfo(l)); 1275 } 1276 1277 /** 1278 * Appends LDC2_W. The pushed item is a double value. 1279 */ addLdc2w(double d)1280 public void addLdc2w(double d) { 1281 addOpcode(LDC2_W); 1282 addIndex(constPool.addDoubleInfo(d)); 1283 } 1284 1285 /** 1286 * Appends NEW. 1287 * 1288 * @param clazz the class of the created instance. 1289 */ addNew(CtClass clazz)1290 public void addNew(CtClass clazz) { 1291 addOpcode(NEW); 1292 addIndex(constPool.addClassInfo(clazz)); 1293 } 1294 1295 /** 1296 * Appends NEW. 1297 * 1298 * @param classname the fully-qualified class name. 1299 */ addNew(String classname)1300 public void addNew(String classname) { 1301 addOpcode(NEW); 1302 addIndex(constPool.addClassInfo(classname)); 1303 } 1304 1305 /** 1306 * Appends ANEWARRAY. 1307 * 1308 * @param classname the qualified class name of the element type. 1309 */ addAnewarray(String classname)1310 public void addAnewarray(String classname) { 1311 addOpcode(ANEWARRAY); 1312 addIndex(constPool.addClassInfo(classname)); 1313 } 1314 1315 /** 1316 * Appends ICONST and ANEWARRAY. 1317 * 1318 * @param clazz the elememnt type. 1319 * @param length the array length. 1320 */ addAnewarray(CtClass clazz, int length)1321 public void addAnewarray(CtClass clazz, int length) { 1322 addIconst(length); 1323 addOpcode(ANEWARRAY); 1324 addIndex(constPool.addClassInfo(clazz)); 1325 } 1326 1327 /** 1328 * Appends NEWARRAY for primitive types. 1329 * 1330 * @param atype <code>T_BOOLEAN</code>, <code>T_CHAR</code>, ... 1331 * @see Opcode 1332 */ addNewarray(int atype, int length)1333 public void addNewarray(int atype, int length) { 1334 addIconst(length); 1335 addOpcode(NEWARRAY); 1336 add(atype); 1337 } 1338 1339 /** 1340 * Appends MULTINEWARRAY. 1341 * 1342 * @param clazz the array type. 1343 * @param dimensions the sizes of all dimensions. 1344 * @return the length of <code>dimensions</code>. 1345 */ addMultiNewarray(CtClass clazz, int[] dimensions)1346 public int addMultiNewarray(CtClass clazz, int[] dimensions) { 1347 int len = dimensions.length; 1348 for (int i = 0; i < len; ++i) 1349 addIconst(dimensions[i]); 1350 1351 growStack(len); 1352 return addMultiNewarray(clazz, len); 1353 } 1354 1355 /** 1356 * Appends MULTINEWARRAY. The size of every dimension must have been 1357 * already pushed on the stack. 1358 * 1359 * @param clazz the array type. 1360 * @param dim the number of the dimensions. 1361 * @return the value of <code>dim</code>. 1362 */ addMultiNewarray(CtClass clazz, int dim)1363 public int addMultiNewarray(CtClass clazz, int dim) { 1364 add(MULTIANEWARRAY); 1365 addIndex(constPool.addClassInfo(clazz)); 1366 add(dim); 1367 growStack(1 - dim); 1368 return dim; 1369 } 1370 1371 /** 1372 * Appends MULTINEWARRAY. 1373 * 1374 * @param desc the type descriptor of the created array. 1375 * @param dim dimensions. 1376 * @return the value of <code>dim</code>. 1377 */ addMultiNewarray(String desc, int dim)1378 public int addMultiNewarray(String desc, int dim) { 1379 add(MULTIANEWARRAY); 1380 addIndex(constPool.addClassInfo(desc)); 1381 add(dim); 1382 growStack(1 - dim); 1383 return dim; 1384 } 1385 1386 /** 1387 * Appends PUTFIELD. 1388 * 1389 * @param c the target class. 1390 * @param name the field name. 1391 * @param desc the descriptor of the field type. 1392 */ addPutfield(CtClass c, String name, String desc)1393 public void addPutfield(CtClass c, String name, String desc) { 1394 addPutfield0(c, null, name, desc); 1395 } 1396 1397 /** 1398 * Appends PUTFIELD. 1399 * 1400 * @param classname the fully-qualified name of the target class. 1401 * @param name the field name. 1402 * @param desc the descriptor of the field type. 1403 */ addPutfield(String classname, String name, String desc)1404 public void addPutfield(String classname, String name, String desc) { 1405 // if classnaem is null, the target class is THIS. 1406 addPutfield0(null, classname, name, desc); 1407 } 1408 addPutfield0(CtClass target, String classname, String name, String desc)1409 private void addPutfield0(CtClass target, String classname, 1410 String name, String desc) { 1411 add(PUTFIELD); 1412 // target is null if it represents THIS. 1413 int ci = classname == null ? constPool.addClassInfo(target) 1414 : constPool.addClassInfo(classname); 1415 addIndex(constPool.addFieldrefInfo(ci, name, desc)); 1416 growStack(-1 - Descriptor.dataSize(desc)); 1417 } 1418 1419 /** 1420 * Appends PUTSTATIC. 1421 * 1422 * @param c the target class. 1423 * @param name the field name. 1424 * @param desc the descriptor of the field type. 1425 */ addPutstatic(CtClass c, String name, String desc)1426 public void addPutstatic(CtClass c, String name, String desc) { 1427 addPutstatic0(c, null, name, desc); 1428 } 1429 1430 /** 1431 * Appends PUTSTATIC. 1432 * 1433 * @param classname the fully-qualified name of the target class. 1434 * @param fieldName the field name. 1435 * @param desc the descriptor of the field type. 1436 */ addPutstatic(String classname, String fieldName, String desc)1437 public void addPutstatic(String classname, String fieldName, String desc) { 1438 // if classname is null, the target class is THIS. 1439 addPutstatic0(null, classname, fieldName, desc); 1440 } 1441 addPutstatic0(CtClass target, String classname, String fieldName, String desc)1442 private void addPutstatic0(CtClass target, String classname, 1443 String fieldName, String desc) { 1444 add(PUTSTATIC); 1445 // target is null if it represents THIS. 1446 int ci = classname == null ? constPool.addClassInfo(target) 1447 : constPool.addClassInfo(classname); 1448 addIndex(constPool.addFieldrefInfo(ci, fieldName, desc)); 1449 growStack(-Descriptor.dataSize(desc)); 1450 } 1451 1452 /** 1453 * Appends ARETURN, IRETURN, .., or RETURN. 1454 * 1455 * @param type the return type. 1456 */ addReturn(CtClass type)1457 public void addReturn(CtClass type) { 1458 if (type == null) 1459 addOpcode(RETURN); 1460 else if (type.isPrimitive()) { 1461 CtPrimitiveType ptype = (CtPrimitiveType)type; 1462 addOpcode(ptype.getReturnOp()); 1463 } 1464 else 1465 addOpcode(ARETURN); 1466 } 1467 1468 /** 1469 * Appends RET. 1470 * 1471 * @param var local variable 1472 */ addRet(int var)1473 public void addRet(int var) { 1474 if (var < 0x100) { 1475 addOpcode(RET); 1476 add(var); 1477 } 1478 else { 1479 addOpcode(WIDE); 1480 addOpcode(RET); 1481 addIndex(var); 1482 } 1483 } 1484 1485 /** 1486 * Appends instructions for executing 1487 * <code>java.lang.System.println(<i>message</i>)</code>. 1488 * 1489 * @param message printed message. 1490 */ addPrintln(String message)1491 public void addPrintln(String message) { 1492 addGetstatic("java.lang.System", "err", "Ljava/io/PrintStream;"); 1493 addLdc(message); 1494 addInvokevirtual("java.io.PrintStream", 1495 "println", "(Ljava/lang/String;)V"); 1496 } 1497 } 1498