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