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