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