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