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 java.io.DataInputStream;
     19 import java.io.IOException;
     20 import java.util.Map;
     21 
     22 /**
     23  * <code>LocalVariableTable_attribute</code>.
     24  */
     25 public class LocalVariableAttribute extends AttributeInfo {
     26     /**
     27      * The name of this attribute <code>"LocalVariableTable"</code>.
     28      */
     29     public static final String tag = "LocalVariableTable";
     30 
     31     /**
     32      * The name of the attribute <code>"LocalVariableTypeTable"</code>.
     33      */
     34     public static final String typeTag = "LocalVariableTypeTable";
     35 
     36     /**
     37      * Constructs an empty LocalVariableTable.
     38      */
     39     public LocalVariableAttribute(ConstPool cp) {
     40         super(cp, tag, new byte[2]);
     41         ByteArray.write16bit(0, info, 0);
     42     }
     43 
     44     /**
     45      * Constructs an empty LocalVariableTable.
     46      *
     47      * @param name      the attribute name.
     48      *                  <code>LocalVariableAttribute.tag</code> or
     49      *                  <code>LocalVariableAttribute.typeTag</code>.
     50      * @see #tag
     51      * @see #typeTag
     52      * @since 3.1
     53      * @deprecated
     54      */
     55     public LocalVariableAttribute(ConstPool cp, String name) {
     56         super(cp, name, new byte[2]);
     57         ByteArray.write16bit(0, info, 0);
     58     }
     59 
     60     LocalVariableAttribute(ConstPool cp, int n, DataInputStream in)
     61         throws IOException
     62     {
     63         super(cp, n, in);
     64     }
     65 
     66     LocalVariableAttribute(ConstPool cp, String name, byte[] i) {
     67         super(cp, name, i);
     68     }
     69 
     70     /**
     71      * Appends a new entry to <code>local_variable_table</code>.
     72      *
     73      * @param startPc           <code>start_pc</code>
     74      * @param length            <code>length</code>
     75      * @param nameIndex         <code>name_index</code>
     76      * @param descriptorIndex   <code>descriptor_index</code>
     77      * @param index             <code>index</code>
     78      */
     79     public void addEntry(int startPc, int length, int nameIndex,
     80                          int descriptorIndex, int index) {
     81         int size = info.length;
     82         byte[] newInfo = new byte[size + 10];
     83         ByteArray.write16bit(tableLength() + 1, newInfo, 0);
     84         for (int i = 2; i < size; ++i)
     85             newInfo[i] = info[i];
     86 
     87         ByteArray.write16bit(startPc, newInfo, size);
     88         ByteArray.write16bit(length, newInfo, size + 2);
     89         ByteArray.write16bit(nameIndex, newInfo, size + 4);
     90         ByteArray.write16bit(descriptorIndex, newInfo, size + 6);
     91         ByteArray.write16bit(index, newInfo, size + 8);
     92         info = newInfo;
     93     }
     94 
     95     void renameClass(String oldname, String newname) {
     96         ConstPool cp = getConstPool();
     97         int n = tableLength();
     98         for (int i = 0; i < n; ++i) {
     99             int pos = i * 10 + 2;
    100             int index = ByteArray.readU16bit(info, pos + 6);
    101             if (index != 0) {
    102                 String desc = cp.getUtf8Info(index);
    103                 desc = renameEntry(desc, oldname, newname);
    104                 ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6);
    105             }
    106         }
    107     }
    108 
    109     String renameEntry(String desc, String oldname, String newname) {
    110         return Descriptor.rename(desc, oldname, newname);
    111     }
    112 
    113     void renameClass(Map classnames) {
    114         ConstPool cp = getConstPool();
    115         int n = tableLength();
    116         for (int i = 0; i < n; ++i) {
    117             int pos = i * 10 + 2;
    118             int index = ByteArray.readU16bit(info, pos + 6);
    119             if (index != 0) {
    120                 String desc = cp.getUtf8Info(index);
    121                 desc = renameEntry(desc, classnames);
    122                 ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6);
    123             }
    124         }
    125     }
    126 
    127     String renameEntry(String desc, Map classnames) {
    128         return Descriptor.rename(desc, classnames);
    129     }
    130 
    131     /**
    132      * For each <code>local_variable_table[i].index</code>,
    133      * this method increases <code>index</code> by <code>delta</code>.
    134      *
    135      * @param lessThan      the index does not change if it
    136      *                      is less than this value.
    137      */
    138     public void shiftIndex(int lessThan, int delta) {
    139         int size = info.length;
    140         for (int i = 2; i < size; i += 10){
    141             int org = ByteArray.readU16bit(info, i + 8);
    142             if (org >= lessThan)
    143                 ByteArray.write16bit(org + delta, info, i + 8);
    144         }
    145     }
    146 
    147     /**
    148      * Returns <code>local_variable_table_length</code>.
    149      * This represents the number of entries in the table.
    150      */
    151     public int tableLength() {
    152         return ByteArray.readU16bit(info, 0);
    153     }
    154 
    155     /**
    156      * Returns <code>local_variable_table[i].start_pc</code>.
    157      * This represents the index into the code array from which the local
    158      * variable is effective.
    159      *
    160      * @param i         the i-th entry.
    161      */
    162     public int startPc(int i) {
    163         return ByteArray.readU16bit(info, i * 10 + 2);
    164     }
    165 
    166     /**
    167      * Returns <code>local_variable_table[i].length</code>.
    168      * This represents the length of the code region in which the local
    169      * variable is effective.
    170      *
    171      * @param i         the i-th entry.
    172      */
    173     public int codeLength(int i) {
    174         return ByteArray.readU16bit(info, i * 10 + 4);
    175     }
    176 
    177     /**
    178      * Adjusts start_pc and length if bytecode is inserted in a method body.
    179      */
    180     void shiftPc(int where, int gapLength, boolean exclusive) {
    181         int n = tableLength();
    182         for (int i = 0; i < n; ++i) {
    183             int pos = i * 10 + 2;
    184             int pc = ByteArray.readU16bit(info, pos);
    185             int len = ByteArray.readU16bit(info, pos + 2);
    186 
    187             /* if pc == 0, then the local variable is a method parameter.
    188              */
    189             if (pc > where || (exclusive && pc == where && pc != 0))
    190                 ByteArray.write16bit(pc + gapLength, info, pos);
    191             else if (pc + len > where || (exclusive && pc + len == where))
    192                 ByteArray.write16bit(len + gapLength, info, pos + 2);
    193         }
    194     }
    195 
    196     /**
    197      * Returns the value of <code>local_variable_table[i].name_index</code>.
    198      * This represents the name of the local variable.
    199      *
    200      * @param i         the i-th entry.
    201      */
    202     public int nameIndex(int i) {
    203         return ByteArray.readU16bit(info, i * 10 + 6);
    204     }
    205 
    206     /**
    207      * Returns the name of the local variable
    208      * specified by <code>local_variable_table[i].name_index</code>.
    209      *
    210      * @param i         the i-th entry.
    211      */
    212     public String variableName(int i) {
    213         return getConstPool().getUtf8Info(nameIndex(i));
    214     }
    215 
    216     /**
    217      * Returns the value of
    218      * <code>local_variable_table[i].descriptor_index</code>.
    219      * This represents the type descriptor of the local variable.
    220      * <p>
    221      * If this attribute represents a LocalVariableTypeTable attribute,
    222      * this method returns the value of
    223      * <code>local_variable_type_table[i].signature_index</code>.
    224      * It represents the type of the local variable.
    225      *
    226      * @param i         the i-th entry.
    227      */
    228     public int descriptorIndex(int i) {
    229         return ByteArray.readU16bit(info, i * 10 + 8);
    230     }
    231 
    232     /**
    233      * This method is equivalent to <code>descriptorIndex()</code>.
    234      * If this attribute represents a LocalVariableTypeTable attribute,
    235      * this method should be used instead of <code>descriptorIndex()</code>
    236      * since the method name is more appropriate.
    237      *
    238      * @param i         the i-th entry.
    239      * @see #descriptorIndex(int)
    240      * @see SignatureAttribute#toFieldSignature(String)
    241      */
    242     public int signatureIndex(int i) {
    243         return descriptorIndex(i);
    244     }
    245 
    246     /**
    247      * Returns the type descriptor of the local variable
    248      * specified by <code>local_variable_table[i].descriptor_index</code>.
    249      * <p>
    250      * If this attribute represents a LocalVariableTypeTable attribute,
    251      * this method returns the type signature of the local variable
    252      * specified by <code>local_variable_type_table[i].signature_index</code>.
    253       *
    254      * @param i         the i-th entry.
    255      */
    256     public String descriptor(int i) {
    257         return getConstPool().getUtf8Info(descriptorIndex(i));
    258     }
    259 
    260     /**
    261      * This method is equivalent to <code>descriptor()</code>.
    262      * If this attribute represents a LocalVariableTypeTable attribute,
    263      * this method should be used instead of <code>descriptor()</code>
    264      * since the method name is more appropriate.
    265      *
    266      * <p>To parse the string, call <code>toFieldSignature(String)</code>
    267      * in <code>SignatureAttribute</code>.
    268      *
    269      * @param i         the i-th entry.
    270      * @see #descriptor(int)
    271      * @see SignatureAttribute#toFieldSignature(String)
    272      */
    273     public String signature(int i) {
    274         return descriptor(i);
    275     }
    276 
    277     /**
    278      * Returns <code>local_variable_table[i].index</code>.
    279      * This represents the index of the local variable.
    280      *
    281      * @param i         the i-th entry.
    282      */
    283     public int index(int i) {
    284         return ByteArray.readU16bit(info, i * 10 + 10);
    285     }
    286 
    287     /**
    288      * Makes a copy.
    289      *
    290      * @param newCp     the constant pool table used by the new copy.
    291      * @param classnames        should be null.
    292      */
    293     public AttributeInfo copy(ConstPool newCp, Map classnames) {
    294         byte[] src = get();
    295         byte[] dest = new byte[src.length];
    296         ConstPool cp = getConstPool();
    297         LocalVariableAttribute attr = makeThisAttr(newCp, dest);
    298         int n = ByteArray.readU16bit(src, 0);
    299         ByteArray.write16bit(n, dest, 0);
    300         int j = 2;
    301         for (int i = 0; i < n; ++i) {
    302             int start = ByteArray.readU16bit(src, j);
    303             int len = ByteArray.readU16bit(src, j + 2);
    304             int name = ByteArray.readU16bit(src, j + 4);
    305             int type = ByteArray.readU16bit(src, j + 6);
    306             int index = ByteArray.readU16bit(src, j + 8);
    307 
    308             ByteArray.write16bit(start, dest, j);
    309             ByteArray.write16bit(len, dest, j + 2);
    310             if (name != 0)
    311                 name = cp.copy(name, newCp, null);
    312 
    313             ByteArray.write16bit(name, dest, j + 4);
    314 
    315             if (type != 0)  {
    316                 String sig = cp.getUtf8Info(type);
    317                 sig = Descriptor.rename(sig, classnames);
    318                 type = newCp.addUtf8Info(sig);
    319             }
    320 
    321             ByteArray.write16bit(type, dest, j + 6);
    322             ByteArray.write16bit(index, dest, j + 8);
    323             j += 10;
    324         }
    325 
    326         return attr;
    327     }
    328 
    329     // LocalVariableTypeAttribute overrides this method.
    330     LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) {
    331         return new LocalVariableAttribute(cp, tag, dest);
    332     }
    333 }
    334