001 package serp.bytecode; 002 003 import java.io.*; 004 import java.util.*; 005 006 import serp.bytecode.lowlevel.*; 007 import serp.bytecode.visitor.*; 008 import serp.util.*; 009 010 /** 011 * A local variable or local variable type. 012 * 013 * @author Abe White 014 * @author Sakir Murat Cengiz 015 */ 016 public 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 return (end != null) ? (Instruction) end.prev 115 : getCode().getLastInstruction(); 116 } 117 118 /** 119 * Get the number of bytes for which this local has a value in 120 * the code byte array. 121 */ 122 public int getLength() { 123 if (_end != null) 124 return _end.getByteIndex() + _end.getLength() 125 - _target.getByteIndex(); 126 return _length; 127 } 128 129 /** 130 * Set the last {@link Instruction} for which this local is in scope. 131 * The instruction must already be a part of the method. 132 * WARNING: if this instruction is deleted, the results are undefined. 133 */ 134 public void setEnd(Instruction end) { 135 if (end.getCode() != getCode()) 136 throw new IllegalArgumentException("Instruction pointers and " 137 + "targets must be part of the same code block."); 138 _end = end; 139 _length = -1; 140 } 141 142 /** 143 * Set the number of bytes for which this local has a value in 144 * the code byte array. 145 */ 146 public void setLength(int length) { 147 if (length < 0) 148 throw new IllegalArgumentException(String.valueOf(length)); 149 _length = length; 150 _end = null; 151 } 152 153 public void updateTargets() { 154 _target.updateTargets(); 155 _end = getEnd(); 156 } 157 158 public void replaceTarget(Instruction oldTarget, Instruction newTarget) { 159 _target.replaceTarget(oldTarget, newTarget); 160 if (getEnd() == oldTarget) 161 setEnd(newTarget); 162 } 163 164 ///////////////////////// 165 // Name, Type operations 166 ///////////////////////// 167 168 /** 169 * Return the {@link ConstantPool} index of the {@link UTF8Entry} that 170 * describes the name of this local. Defaults to 0. 171 */ 172 public int getNameIndex() { 173 return _nameIndex; 174 } 175 176 /** 177 * Set the {@link ConstantPool} index of the {@link UTF8Entry} that 178 * describes the name of this local. 179 */ 180 public void setNameIndex(int nameIndex) { 181 _nameIndex = nameIndex; 182 } 183 184 /** 185 * Return the name of this local, or null if unset. 186 */ 187 public String getName() { 188 if (getNameIndex() == 0) 189 return null; 190 return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue(); 191 } 192 193 /** 194 * Set the name of this inner local. 195 */ 196 public void setName(String name) { 197 if (name == null) 198 setNameIndex(0); 199 else 200 setNameIndex(getPool().findUTF8Entry(name, true)); 201 } 202 203 /** 204 * Return the {@link ConstantPool} index of the {@link UTF8Entry} that 205 * describes this local. Defaults to 0. 206 */ 207 public int getTypeIndex() { 208 return _descriptorIndex; 209 } 210 211 /** 212 * Set the {@link ConstantPool} index of the {@link UTF8Entry} that 213 * describes this local. 214 */ 215 public void setTypeIndex(int index) { 216 _descriptorIndex = index; 217 } 218 219 /** 220 * Return the full name of the local's type, or null if unset. 221 */ 222 public String getTypeName() { 223 if (getTypeIndex() == 0) 224 return null; 225 UTF8Entry entry = (UTF8Entry) getPool().getEntry(getTypeIndex()); 226 return getProject().getNameCache().getExternalForm(entry.getValue(), 227 false); 228 } 229 230 /** 231 * Set the type of this local. 232 */ 233 public void setType(String type) { 234 if (type == null) 235 setTypeIndex(0); 236 else { 237 type = getProject().getNameCache().getInternalForm(type, true); 238 setTypeIndex(getPool().findUTF8Entry(type, true)); 239 } 240 } 241 242 /////////////////////////// 243 // BCEntity implementation 244 /////////////////////////// 245 246 public Project getProject() { 247 return _owner.getProject(); 248 } 249 250 public ConstantPool getPool() { 251 return _owner.getPool(); 252 } 253 254 public ClassLoader getClassLoader() { 255 return _owner.getClassLoader(); 256 } 257 258 public boolean isValid() { 259 return _owner != null; 260 } 261 262 ////////////////// 263 // I/O operations 264 ////////////////// 265 266 void read(DataInput in) throws IOException { 267 setStartPc(in.readUnsignedShort()); 268 setLength(in.readUnsignedShort()); 269 setNameIndex(in.readUnsignedShort()); 270 setTypeIndex(in.readUnsignedShort()); 271 setLocal(in.readUnsignedShort()); 272 } 273 274 void write(DataOutput out) throws IOException { 275 out.writeShort(getStartPc()); 276 out.writeShort(getLength()); 277 out.writeShort(getNameIndex()); 278 out.writeShort(getTypeIndex()); 279 out.writeShort(getLocal()); 280 } 281 282 public Code getCode() { 283 return _owner.getCode(); 284 } 285 }