View Javadoc

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      // Body operations
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      // Handler operations
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      // Catch operations
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     // InstructionPtr implementation
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     // BCEntity implementation
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     // VisitAcceptor implementation
217     ////////////////////////////////
218 
219     public void acceptVisit(BCVisitor visit) {
220         visit.enterExceptionHandler(this);
221         visit.exitExceptionHandler(this);
222     }
223 
224     //////////////////
225     // I/O operations
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         // done at a high level so that if the name isn't in our constant pool,
234         // it will be added
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 }