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