• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ByteVector()25     public ByteVector() {
26         buffer = new byte[64];
27         size = 0;
28     }
29 
clone()30     public Object clone() throws CloneNotSupportedException {
31         ByteVector bv = (ByteVector)super.clone();
32         bv.buffer = (byte[])buffer.clone();
33         return bv;
34     }
35 
getSize()36     public final int getSize() { return size; }
37 
copy()38     public final byte[] copy() {
39         byte[] b = new byte[size];
40         System.arraycopy(buffer, 0, b, 0, size);
41         return b;
42     }
43 
read(int offset)44     public int read(int offset) {
45         if (offset < 0 || size <= offset)
46             throw new ArrayIndexOutOfBoundsException(offset);
47 
48         return buffer[offset];
49     }
50 
write(int offset, int value)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 
add(int code)58     public void add(int code) {
59         addGap(1);
60         buffer[size - 1] = (byte)code;
61     }
62 
add(int b1, int b2)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 
add(int b1, int b2, int b3, int b4)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 
addGap(int length)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      */
Bytecode(ConstPool cp, int stacksize, int localvars)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      */
Bytecode(ConstPool cp)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      */
clone()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      */
getConstPool()178     public ConstPool getConstPool() { return constPool; }
179 
180     /**
181      * Returns <code>exception_table</code>.
182      */
getExceptionTable()183     public ExceptionTable getExceptionTable() { return tryblocks; }
184 
185     /**
186      * Converts to a <code>CodeAttribute</code>.
187      */
toCodeAttribute()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      */
length()196     public int length() {
197         return getSize();
198     }
199 
200     /**
201      * Returns the produced bytecode sequence.
202      */
get()203     public byte[] get() {
204         return copy();
205     }
206 
207     /**
208      * Gets <code>max_stack</code>.
209      */
getMaxStack()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      */
setMaxStack(int size)226     public void setMaxStack(int size) {
227         maxStack = size;
228     }
229 
230     /**
231      * Gets <code>max_locals</code>.
232      */
getMaxLocals()233     public int getMaxLocals() { return maxLocals; }
234 
235     /**
236      * Sets <code>max_locals</code>.
237      */
setMaxLocals(int size)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      */
setMaxLocals(boolean isStatic, CtClass[] params, int locals)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      */
incMaxLocals(int diff)279     public void incMaxLocals(int diff) {
280         maxLocals += diff;
281     }
282 
283     /**
284      * Adds a new entry of <code>exception_table</code>.
285      */
addExceptionHandler(int start, int end, int handler, CtClass type)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      */
addExceptionHandler(int start, int end, int handler, String type)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      */
addExceptionHandler(int start, int end, int handler, int type)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      */
currentPc()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      */
read(int offset)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      */
read16bit(int offset)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      */
read32bit(int offset)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      */
write(int offset, int value)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      */
write16bit(int offset, int value)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      */
write32bit(int offset, int value)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      */
add(int code)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      */
add32bit(int value)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      */
addGap(int length)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      */
addOpcode(int code)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      */
growStack(int diff)423     public void growStack(int diff) {
424         setStackDepth(stackDepth + diff);
425     }
426 
427     /**
428      * Returns the current stack depth.
429      */
getStackDepth()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      */
setStackDepth(int depth)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      */
addIndex(int index)449     public void addIndex(int index) {
450         add(index >> 8, index);
451     }
452 
453     /**
454      * Appends ALOAD or (WIDE) ALOAD_&lt;n&gt;
455      *
456      * @param n         an index into the local variable array.
457      */
addAload(int n)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_&lt;n&gt;
474      *
475      * @param n         an index into the local variable array.
476      */
addAstore(int n)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_&lt;n&gt;
493      *
494      * @param n         the pushed integer constant.
495      */
addIconst(int n)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      */
addConstZero(CtClass type)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_&lt;n&gt;
537      *
538      * @param n         an index into the local variable array.
539      */
addIload(int n)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_&lt;n&gt;
556      *
557      * @param n         an index into the local variable array.
558      */
addIstore(int n)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_&lt;n&gt;
575      *
576      * @param n         the pushed long integer constant.
577      */
addLconst(long n)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_&lt;n&gt;
587      *
588      * @param n         an index into the local variable array.
589      */
addLload(int n)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_&lt;n&gt;
606      *
607      * @param n         an index into the local variable array.
608      */
addLstore(int n)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_&lt;n&gt;
625      *
626      * @param d         the pushed double constant.
627      */
addDconst(double d)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_&lt;n&gt;
637      *
638      * @param n         an index into the local variable array.
639      */
addDload(int n)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_&lt;n&gt;
656      *
657      * @param n         an index into the local variable array.
658      */
addDstore(int n)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_&lt;n&gt;
675      *
676      * @param f         the pushed float constant.
677      */
addFconst(float f)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_&lt;n&gt;
687      *
688      * @param n         an index into the local variable array.
689      */
addFload(int n)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_&lt;n&gt;
706      *
707      * @param n         an index into the local variable array.
708      */
addFstore(int n)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      */
addLoad(int n, CtClass type)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      */
addStore(int n, CtClass type)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      */
addLoadParameters(CtClass[] params, int offset)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      */
addCheckcast(CtClass c)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      */
addCheckcast(String classname)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      */
addInstanceof(String classname)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      */
addGetfield(CtClass c, String name, String type)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      */
addGetfield(String c, String name, String type)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      */
addGetstatic(CtClass c, String name, String type)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      */
addGetstatic(String c, String name, String type)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      */
addInvokespecial(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)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      */
addInvokespecial(CtClass clazz, String name, String desc)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      */
addInvokespecial(String clazz, String name, String desc)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      */
addInvokespecial(int clazz, String name, String desc)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      */
addInvokestatic(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)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      */
addInvokestatic(CtClass clazz, String name, String desc)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      */
addInvokestatic(String classname, String name, String desc)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      */
addInvokestatic(int clazz, String name, String desc)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      */
addInvokevirtual(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes)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      */
addInvokevirtual(CtClass clazz, String name, String desc)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      */
addInvokevirtual(String classname, String name, String desc)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      */
addInvokevirtual(int clazz, String name, String desc)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      */
addInvokeinterface(CtClass clazz, String name, CtClass returnType, CtClass[] paramTypes, int count)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      */
addInvokeinterface(CtClass clazz, String name, String desc, int count)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      */
addInvokeinterface(String classname, String name, String desc, int count)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      */
addInvokeinterface(int clazz, String name, String desc, int count)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      */
addLdc(String s)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      */
addLdc(int i)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      */
addLdc2w(long l)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      */
addLdc2w(double d)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      */
addNew(CtClass clazz)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      */
addNew(String classname)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      */
addAnewarray(String classname)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      */
addAnewarray(CtClass clazz, int length)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      */
addNewarray(int atype, int length)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      */
addMultiNewarray(CtClass clazz, int[] dimensions)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      */
addMultiNewarray(CtClass clazz, int dim)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      */
addMultiNewarray(String desc, int dim)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      */
addPutfield(CtClass c, String name, String desc)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      */
addPutfield(String classname, String name, String desc)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 
addPutfield0(CtClass target, String classname, String name, String desc)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      */
addPutstatic(CtClass c, String name, String desc)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      */
addPutstatic(String classname, String fieldName, String desc)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 
addPutstatic0(CtClass target, String classname, String fieldName, String desc)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      */
addReturn(CtClass type)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      */
addRet(int var)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      */
addPrintln(String message)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