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