001package serp.bytecode; 002 003import java.io.*; 004import java.util.*; 005 006import serp.bytecode.lowlevel.*; 007import serp.bytecode.visitor.*; 008import serp.util.*; 009 010/** 011 * A local variable or local variable type. 012 * 013 * @author Abe White 014 * @author Sakir Murat Cengiz 015 */ 016public abstract class Local implements BCEntity, InstructionPtr { 017 private LocalTable _owner = null; 018 private InstructionPtrStrategy _target = new InstructionPtrStrategy(this); 019 private Instruction _end = null; 020 private int _length = 0; 021 private int _nameIndex = 0; 022 private int _descriptorIndex = 0; 023 private int _index = 0; 024 025 Local(LocalTable owner) { 026 _owner = owner; 027 } 028 029 /** 030 * The owning table. 031 */ 032 public LocalTable getTable() { 033 return _owner; 034 } 035 036 void invalidate() { 037 _owner = null; 038 } 039 040 ////////////////////////// 041 // Local index operations 042 ////////////////////////// 043 044 /** 045 * Get the local variable index of the current frame for this local. 046 */ 047 public int getLocal() { 048 return _index; 049 } 050 051 /** 052 * Set the local variable index of the current frame for this local. 053 */ 054 public void setLocal(int index) { 055 _index = index; 056 } 057 058 /** 059 * Return the parameter that this local corresponds to, or -1 if none. 060 */ 061 public int getParam() { 062 return getCode().getParamsIndex(getLocal()); 063 } 064 065 /** 066 * Set the method parameter that this local corresponds to. 067 */ 068 public void setParam(int param) { 069 setLocal(_owner.getCode().getLocalsIndex(param)); 070 } 071 072 //////////////////////////// 073 // Start, Length operations 074 //////////////////////////// 075 076 /** 077 * Return the index into the code byte array at which this local starts. 078 */ 079 public int getStartPc() { 080 return _target.getByteIndex(); 081 } 082 083 /** 084 * Return the instruction marking the beginning of this local. 085 */ 086 public Instruction getStart() { 087 return _target.getTargetInstruction(); 088 } 089 090 /** 091 * Set the index into the code byte array at which this local starts. 092 */ 093 public void setStartPc(int startPc) { 094 _target.setByteIndex(startPc); 095 } 096 097 /** 098 * Set the {@link Instruction} marking the beginning this local. 099 * The instruction must already be a part of the method. 100 * WARNING: if this instruction is deleted, the results are undefined. 101 */ 102 public void setStart(Instruction instruction) { 103 _target.setTargetInstruction(instruction); 104 } 105 106 /** 107 * The last {@link Instruction} for which this local is in scope. 108 */ 109 public Instruction getEnd() { 110 if (_end != null) 111 return _end; 112 int idx = _target.getByteIndex() + _length; 113 Instruction end = getCode().getInstruction(idx); 114 if (end != null && (end.prev instanceof Instruction)) { 115 return (Instruction) end.prev; 116 } 117 return getCode().getLastInstruction(); 118 } 119 120 /** 121 * Get the number of bytes for which this local has a value in 122 * the code byte array. 123 */ 124 public int getLength() { 125 if (_end != null) 126 return _end.getByteIndex() + _end.getLength() 127 - _target.getByteIndex(); 128 return _length; 129 } 130 131 /** 132 * Set the last {@link Instruction} for which this local is in scope. 133 * The instruction must already be a part of the method. 134 * WARNING: if this instruction is deleted, the results are undefined. 135 */ 136 public void setEnd(Instruction end) { 137 if (end.getCode() != getCode()) 138 throw new IllegalArgumentException("Instruction pointers and " 139 + "targets must be part of the same code block."); 140 _end = end; 141 _length = -1; 142 } 143 144 /** 145 * Set the number of bytes for which this local has a value in 146 * the code byte array. 147 */ 148 public void setLength(int length) { 149 if (length < 0) 150 throw new IllegalArgumentException(String.valueOf(length)); 151 _length = length; 152 _end = null; 153 } 154 155 public void updateTargets() { 156 _target.updateTargets(); 157 _end = getEnd(); 158 } 159 160 public void replaceTarget(Instruction oldTarget, Instruction newTarget) { 161 _target.replaceTarget(oldTarget, newTarget); 162 if (getEnd() == oldTarget) 163 setEnd(newTarget); 164 } 165 166 ///////////////////////// 167 // Name, Type operations 168 ///////////////////////// 169 170 /** 171 * Return the {@link ConstantPool} index of the {@link UTF8Entry} that 172 * describes the name of this local. Defaults to 0. 173 */ 174 public int getNameIndex() { 175 return _nameIndex; 176 } 177 178 /** 179 * Set the {@link ConstantPool} index of the {@link UTF8Entry} that 180 * describes the name of this local. 181 */ 182 public void setNameIndex(int nameIndex) { 183 _nameIndex = nameIndex; 184 } 185 186 /** 187 * Return the name of this local, or null if unset. 188 */ 189 public String getName() { 190 if (getNameIndex() == 0) 191 return null; 192 return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue(); 193 } 194 195 /** 196 * Set the name of this inner local. 197 */ 198 public void setName(String name) { 199 if (name == null) 200 setNameIndex(0); 201 else 202 setNameIndex(getPool().findUTF8Entry(name, true)); 203 } 204 205 /** 206 * Return the {@link ConstantPool} index of the {@link UTF8Entry} that 207 * describes this local. Defaults to 0. 208 */ 209 public int getTypeIndex() { 210 return _descriptorIndex; 211 } 212 213 /** 214 * Set the {@link ConstantPool} index of the {@link UTF8Entry} that 215 * describes this local. 216 */ 217 public void setTypeIndex(int index) { 218 _descriptorIndex = index; 219 } 220 221 /** 222 * Return the full name of the local's type, or null if unset. 223 */ 224 public String getTypeName() { 225 if (getTypeIndex() == 0) 226 return null; 227 UTF8Entry entry = (UTF8Entry) getPool().getEntry(getTypeIndex()); 228 return getProject().getNameCache().getExternalForm(entry.getValue(), 229 false); 230 } 231 232 /** 233 * Set the type of this local. 234 */ 235 public void setType(String type) { 236 if (type == null) 237 setTypeIndex(0); 238 else { 239 type = getProject().getNameCache().getInternalForm(type, true); 240 setTypeIndex(getPool().findUTF8Entry(type, true)); 241 } 242 } 243 244 /////////////////////////// 245 // BCEntity implementation 246 /////////////////////////// 247 248 public Project getProject() { 249 return _owner.getProject(); 250 } 251 252 public ConstantPool getPool() { 253 return _owner.getPool(); 254 } 255 256 public ClassLoader getClassLoader() { 257 return _owner.getClassLoader(); 258 } 259 260 public boolean isValid() { 261 return _owner != null; 262 } 263 264 ////////////////// 265 // I/O operations 266 ////////////////// 267 268 void read(DataInput in) throws IOException { 269 setStartPc(in.readUnsignedShort()); 270 setLength(in.readUnsignedShort()); 271 setNameIndex(in.readUnsignedShort()); 272 setTypeIndex(in.readUnsignedShort()); 273 setLocal(in.readUnsignedShort()); 274 } 275 276 void write(DataOutput out) throws IOException { 277 out.writeShort(getStartPc()); 278 out.writeShort(getLength()); 279 out.writeShort(getNameIndex()); 280 out.writeShort(getTypeIndex()); 281 out.writeShort(getLocal()); 282 } 283 284 public Code getCode() { 285 return _owner.getCode(); 286 } 287}