/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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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_&lt;n&gt; 
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