1 package serp.bytecode;
2
3 import java.io.*;
4 import java.util.*;
5
6 import serp.bytecode.lowlevel.*;
7 import serp.bytecode.visitor.*;
8 import serp.util.*;
9
10 /***
11 * A local variable or local variable type.
12 *
13 * @author Abe White
14 * @author Sakir Murat Cengiz
15 */
16 public abstract class Local implements BCEntity, InstructionPtr {
17 private LocalTable _owner = null;
18 private InstructionPtrStrategy _target = new InstructionPtrStrategy(this);
19 private Instruction _end = null;
20 private int _length = 0;
21 private int _nameIndex = 0;
22 private int _descriptorIndex = 0;
23 private int _index = 0;
24
25 Local(LocalTable owner) {
26 _owner = owner;
27 }
28
29 /***
30 * The owning table.
31 */
32 public LocalTable getTable() {
33 return _owner;
34 }
35
36 void invalidate() {
37 _owner = null;
38 }
39
40
41
42
43
44 /***
45 * Get the local variable index of the current frame for this local.
46 */
47 public int getLocal() {
48 return _index;
49 }
50
51 /***
52 * Set the local variable index of the current frame for this local.
53 */
54 public void setLocal(int index) {
55 _index = index;
56 }
57
58 /***
59 * Return the parameter that this local corresponds to, or -1 if none.
60 */
61 public int getParam() {
62 return getCode().getParamsIndex(getLocal());
63 }
64
65 /***
66 * Set the method parameter that this local corresponds to.
67 */
68 public void setParam(int param) {
69 setLocal(_owner.getCode().getLocalsIndex(param));
70 }
71
72
73
74
75
76 /***
77 * Return the index into the code byte array at which this local starts.
78 */
79 public int getStartPc() {
80 return _target.getByteIndex();
81 }
82
83 /***
84 * Return the instruction marking the beginning of this local.
85 */
86 public Instruction getStart() {
87 return _target.getTargetInstruction();
88 }
89
90 /***
91 * Set the index into the code byte array at which this local starts.
92 */
93 public void setStartPc(int startPc) {
94 _target.setByteIndex(startPc);
95 }
96
97 /***
98 * Set the {@link Instruction} marking the beginning this local.
99 * 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
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
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
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 }