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      */
LocalVariableAttribute(ConstPool cp)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      */
LocalVariableAttribute(ConstPool cp, String name)55     public LocalVariableAttribute(ConstPool cp, String name) {
56         super(cp, name, new byte[2]);
57         ByteArray.write16bit(0, info, 0);
58     }
59 
LocalVariableAttribute(ConstPool cp, int n, DataInputStream in)60     LocalVariableAttribute(ConstPool cp, int n, DataInputStream in)
61         throws IOException
62     {
63         super(cp, n, in);
64     }
65 
LocalVariableAttribute(ConstPool cp, String name, byte[] i)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      */
addEntry(int startPc, int length, int nameIndex, int descriptorIndex, int index)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 
renameClass(String oldname, String newname)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 
renameEntry(String desc, String oldname, String newname)109     String renameEntry(String desc, String oldname, String newname) {
110         return Descriptor.rename(desc, oldname, newname);
111     }
112 
renameClass(Map classnames)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 
renameEntry(String desc, Map classnames)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      */
shiftIndex(int lessThan, int delta)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      */
tableLength()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      */
startPc(int i)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      */
codeLength(int i)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      */
shiftPc(int where, int gapLength, boolean exclusive)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      */
nameIndex(int i)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      */
variableName(int i)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      */
descriptorIndex(int i)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      */
signatureIndex(int i)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      */
descriptor(int i)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      */
signature(int i)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      */
index(int i)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      */
copy(ConstPool newCp, Map classnames)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.
makeThisAttr(ConstPool cp, byte[] dest)330     LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) {
331         return new LocalVariableAttribute(cp, tag, dest);
332     }
333 }
334