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 * Represents a <code>try {} catch() {}</code> statement in bytecode.
12 *
13 * @author Abe White
14 */
15 public class ExceptionHandler implements InstructionPtr, BCEntity,
16 VisitAcceptor {
17 private int _catchIndex = 0;
18 private Code _owner = null;
19 private InstructionPtrStrategy _tryStart = new InstructionPtrStrategy(this);
20 private InstructionPtrStrategy _tryEnd = new InstructionPtrStrategy(this);
21 private InstructionPtrStrategy _tryHandler = new InstructionPtrStrategy
22 (this);
23
24 ExceptionHandler(Code owner) {
25 _owner = owner;
26 }
27
28 /***
29 * Return the owning code block.
30 */
31 public Code getCode() {
32 return _owner;
33 }
34
35
36
37
38
39 /***
40 * Return the instruction marking the beginning of the try {} block.
41 */
42 public Instruction getTryStart() {
43 return _tryStart.getTargetInstruction();
44 }
45
46 /***
47 * Set the {@link Instruction} marking the beginning of the try block.
48 * The instruction must already be a part of the method.
49 */
50 public void setTryStart(Instruction instruction) {
51 _tryStart.setTargetInstruction(instruction);
52 }
53
54 /***
55 * Return the instruction at the end of the try {} block.
56 */
57 public Instruction getTryEnd() {
58 return _tryEnd.getTargetInstruction();
59 }
60
61 /***
62 * Set the Instruction at the end of the try block. The
63 * Instruction must already be a part of the method.
64 */
65 public void setTryEnd(Instruction instruction) {
66 _tryEnd.setTargetInstruction(instruction);
67 }
68
69
70
71
72
73 /***
74 * Return the instruction marking the beginning of the catch {} block.
75 */
76 public Instruction getHandlerStart() {
77 return _tryHandler.getTargetInstruction();
78 }
79
80 /***
81 * Set the {@link Instruction} marking the beginning of the catch block.
82 * The instruction must already be a part of the method.
83 * WARNING: if this instruction is deleted, the results are undefined.
84 */
85 public void setHandlerStart(Instruction instruction) {
86 _tryHandler.setTargetInstruction(instruction);
87 }
88
89
90
91
92
93 /***
94 * Return the index into the class {@link ConstantPool} of the
95 * {@link ClassEntry} describing the exception type this handler catches.
96 */
97 public int getCatchIndex() {
98 return _catchIndex;
99 }
100
101 /***
102 * Set the index into the class {@link ConstantPool} of the
103 * {@link ClassEntry} describing the exception type this handler catches.
104 */
105 public void setCatchIndex(int catchTypeIndex) {
106 _catchIndex = catchTypeIndex;
107 }
108
109 /***
110 * Return the name of the exception type; returns null for catch-all
111 * clauses used to implement finally blocks. The name will be returned
112 * in a forum suitable for a {@link Class#forName} call.
113 */
114 public String getCatchName() {
115 if (_catchIndex == 0)
116 return null;
117
118 ClassEntry entry = (ClassEntry) getPool().getEntry(_catchIndex);
119 return getProject().getNameCache().getExternalForm(entry.getNameEntry().
120 getValue(), false);
121 }
122
123 /***
124 * Return the {@link Class} of the exception type; returns null for
125 * catch-all clauses used to implement finally blocks.
126 */
127 public Class getCatchType() {
128 String name = getCatchName();
129 if (name == null)
130 return null;
131 return Strings.toClass(name, getClassLoader());
132 }
133
134 /***
135 * Return the bytecode of the exception type; returns null for
136 * catch-all clauses used to implement finally blocks.
137 */
138 public BCClass getCatchBC() {
139 String name = getCatchName();
140 if (name == null)
141 return null;
142 return getProject().loadClass(name, getClassLoader());
143 }
144
145 /***
146 * Set the class of the exception type, or null for catch-all clauses used
147 * with finally blocks.
148 */
149 public void setCatch(String name) {
150 if (name == null)
151 _catchIndex = 0;
152 else
153 _catchIndex = getPool().findClassEntry(getProject().getNameCache().
154 getInternalForm(name, false), true);
155 }
156
157 /***
158 * Set the class of the exception type, or null for catch-all clauses used
159 * for finally blocks.
160 */
161 public void setCatch(Class type) {
162 if (type == null)
163 setCatch((String) null);
164 else
165 setCatch(type.getName());
166 }
167
168 /***
169 * Set the class of the exception type, or null for catch-all clauses used
170 * for finally blocks.
171 */
172 public void setCatch(BCClass type) {
173 if (type == null)
174 setCatch((String) null);
175 else
176 setCatch(type.getName());
177 }
178
179
180
181
182
183 public void updateTargets() {
184 _tryStart.updateTargets();
185 _tryEnd.updateTargets();
186 _tryHandler.updateTargets();
187 }
188
189 public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
190 _tryStart.replaceTarget(oldTarget, newTarget);
191 _tryEnd.replaceTarget(oldTarget, newTarget);
192 _tryHandler.replaceTarget(oldTarget, newTarget);
193 }
194
195
196
197
198
199 public Project getProject() {
200 return _owner.getProject();
201 }
202
203 public ConstantPool getPool() {
204 return _owner.getPool();
205 }
206
207 public ClassLoader getClassLoader() {
208 return _owner.getClassLoader();
209 }
210
211 public boolean isValid() {
212 return _owner != null;
213 }
214
215
216
217
218
219 public void acceptVisit(BCVisitor visit) {
220 visit.enterExceptionHandler(this);
221 visit.exitExceptionHandler(this);
222 }
223
224
225
226
227
228 void read(ExceptionHandler orig) {
229 _tryStart.setByteIndex(orig._tryStart.getByteIndex());
230 _tryEnd.setByteIndex(orig._tryEnd.getByteIndex());
231 _tryHandler.setByteIndex(orig._tryHandler.getByteIndex());
232
233
234
235 setCatch(orig.getCatchName());
236 }
237
238 void read(DataInput in) throws IOException {
239 setTryStart(in.readUnsignedShort());
240 setTryEnd(in.readUnsignedShort());
241 setHandlerStart(in.readUnsignedShort());
242 setCatchIndex(in.readUnsignedShort());
243 }
244
245 void write(DataOutput out) throws IOException {
246 out.writeShort(getTryStartPc());
247 out.writeShort(getTryEndPc());
248 out.writeShort(getHandlerStartPc());
249 out.writeShort(getCatchIndex());
250 }
251
252 public void setTryStart(int start) {
253 _tryStart.setByteIndex(start);
254 }
255
256 public int getTryStartPc() {
257 return _tryStart.getByteIndex();
258 }
259
260 public void setTryEnd(int end) {
261 setTryEnd((Instruction) _owner.getInstruction(end).prev);
262 }
263
264 /***
265 * Return the program counter end position for this exception handler.
266 * This represents an index into the code byte array.
267 */
268 public int getTryEndPc() {
269 return _tryEnd.getByteIndex() + getTryEnd().getLength();
270 }
271
272 public void setHandlerStart(int handler) {
273 _tryHandler.setByteIndex(handler);
274 }
275
276 public int getHandlerStartPc() {
277 return _tryHandler.getByteIndex();
278 }
279
280 void invalidate() {
281 _owner = null;
282 }
283 }