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 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 }