KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quilt > cl > BytecodeCollector


1 /* BytecodeCollector.java */
2
3 package org.quilt.cl;
4
5 import java.util.HashMap JavaDoc;
6 import java.util.HashSet JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import java.util.Set JavaDoc;
11 import java.util.Vector JavaDoc;
12
13 import org.apache.bcel.classfile.*;
14 import org.apache.bcel.generic.*;
15
16 import org.quilt.graph.*;
17
18 /**
19  * Collects the bytecode for a method while walking the method
20  * control flow graph.
21  *
22  * Inspired by Quilt 0.5's BytecodeLayout,
23  * @author <a HREF="mailto:ddp@apache.org">David Dixon-Peugh</a> and the
24  * rest of the Quilt development team.
25  *
26  * However, errors and omissions in this version are entirely due to
27  * @author <a HREF="mailto:jddixon@users.sourceforge.net">Jim Dixon</a>
28  */

29
30 public class BytecodeCollector implements org.quilt.graph.Visitor {
31
32     private ControlFlowGraph graph = null;
33
34     private Map JavaDoc startHandles = null;
35     private Map JavaDoc endHandles = null;
36     private Map JavaDoc gotoFixMeUps = null;
37     private InstructionList ilist = null;
38
39     /** No-arg constructor. */
40     public BytecodeCollector() { }
41
42     /**
43      * Action taken upon beginning to visit the graph.
44      * @param g Directed graph to be visited.
45      */

46     public void discoverGraph( Directed g ) {
47         graph = (ControlFlowGraph) g;
48         ilist = graph.getInstructionList();
49         startHandles = graph.getStartHandles();
50         endHandles = graph.getEndHandles();
51         gotoFixMeUps = graph.getGotoFixMeUps();
52     }
53     /**
54      * Action taken upon beginning to visit a graph vertex. Unless
55      * this is an Entry or Exit vertex, save the starting position in
56      * the bytecode to give a offset for edges with this vertex as target.
57      * Save the end instruction in the bytecode so that we can insert any
58      * connector code their later, in finishVertex.
59      *
60      * Entry and Exit vertices carry no bytecode and never have a
61      * connecting instruction, so they can be ignored when collecting
62      * code.
63      *
64      * @param v The vertex; carries a block of code and a final
65      * instruction in its Connector.
66      */

67     public void discoverVertex(Vertex vtx) {
68         if (vtx == null) {
69             throw new IllegalArgumentException JavaDoc ("null vertex");
70         }
71         // no code in Entry or Exit vertices
72
if (! (vtx instanceof Entry || vtx instanceof Exit) ) {
73             CodeVertex v = (CodeVertex) vtx;
74             InstructionList vIList = v.getInstructionList();
75             InstructionHandle vStart = null;
76
77             if (vIList.size() == 0) {
78                 vIList = new InstructionList ( new NOP() );
79             }
80             vStart = ilist.append(vIList); // consumes vIList
81
if (vStart == null) {
82                 System.out.println("discoverVertex INTERNAL ERROR: vertex "
83                     + v + " has null position in bytecode\n");
84             }
85             // DEBUG
86
// System.out.println("discoverVertex " + v + " - adding vStart");
87
if (vStart == null) {
88                 System.out.println(" ** vStart is null **");
89             }
90             // END
91
startHandles.put(v, vStart); // v a CodeVertex
92

93             Instruction inst = v.getConnInst();
94             if (inst != null) {
95                 // CONSOLIDATE THESE ////////////////////////////////
96
if (inst instanceof GotoInstruction) {
97                     BranchHandle bh = ilist.append ((GotoInstruction)inst);
98                     endHandles.put (v, bh);
99                 } else if (inst instanceof IfInstruction) {
100                     BranchHandle bh = ilist.append((IfInstruction) inst);
101                     endHandles.put (v, bh);
102                 } else if ( inst instanceof JsrInstruction ) {
103                     BranchHandle bh = ilist.append((JsrInstruction) inst);
104                     endHandles.put (v, bh);
105                 } else if ( inst instanceof Select) {
106                     BranchHandle bh = ilist.append((Select) inst);
107                     endHandles.put (v, bh );
108                 } else if ( (inst instanceof ExceptionThrower)
109                          || (inst instanceof ReturnInstruction)
110                          || (inst instanceof RET)
111                          || (inst instanceof InvokeInstruction) ) {
112                     InstructionHandle ih = ilist.append(inst);
113                     endHandles.put (v, ih );
114                 } else {
115                     ilist.append(inst);
116                 }
117             }
118         }
119     }
120
121     /**
122      * Action taken upon first encountering an edge.
123      * @param e A FlowControlEdge, a weighted, directed edge.
124      */

125     public void discoverEdge( Edge e ) {
126     }
127
128     /**
129      * Action taken before departing an edge.
130      *
131      * @param e The control flow graph edge.
132      */

133     public void finishEdge( Edge e ) {
134     }
135
136     /**
137      * Where the immediate target of an edge is an Entry or Exit,
138      * determine the ultimate target. That is, follow preferred
139      * edges until a code Vertex (neither Entry nor Exit) is found
140      * and return that. XXX Should throw exception if target becomes
141      * null.
142      *
143      * @param e Edge we are searching along.
144      * @return Ultimate target of the edge.
145      */

146     private CodeVertex getEffectiveTarget (final Edge e) {
147         Vertex target = e.getTarget();
148         // DEBUG
149
//System.out.println (
150
// "getEffectiveTarget: initially target is " + target);
151
// END
152
while (target != null
153          && (target instanceof Entry || target instanceof Exit) ) {
154             // DEBUG
155
// System.out.print (" replacing " + target + " with");
156
// END
157

158             target = target.getTarget();
159
160             //System.out.println (" " + target ); // DEBUG too ;-)
161
}
162         // DEBUG
163
// System.out.println (" returning: " + target);
164
// END
165
return (CodeVertex) target;
166     }
167     /**
168      * Action taken before leaving a vertex in the graph. The
169      * connection instruction, if any, is fixed up by setting
170      * its target(s).
171      *
172      * If the connection instruction is a goto, which might jump
173      * into another graph, fixup is delayed until the user asks
174      * for the instruction list, when the processing of all graphs
175      * has been completed.
176      *
177      * @see CodeVertex.getInstructionList
178      * @param v The vertex, either an Entry or Exit vertex, or a
179      * code vertex.
180      */

181     public void finishVertex( Vertex vtx ) {
182         if (vtx instanceof CodeVertex) {
183             CodeVertex v = (CodeVertex) vtx;
184             Instruction inst = v.getConnInst();
185             if (inst != null) {
186                 if ( inst instanceof GotoInstruction ) {
187 // // DEBUG
188
// Connector conn = v.getConnector();
189
// System.out.println("GotoInstruction in vertex " + v);
190
// if (conn instanceof UnaryConnector) {
191
// System.out.println(" has unary connector!!");
192
// } else if (conn instanceof BinaryConnector) {
193
// System.out.println(" has binary connector");
194
// System.out.println (" 'other' edge: "
195
// + ((BinaryConnector)conn).getOtherEdge());
196
// }
197
// // END
198
CodeVertex effTarget = getEffectiveTarget(
199                         ((BinaryConnector)v.getConnector()).getOtherEdge());
200                     InstructionHandle target
201                         = (InstructionHandle) startHandles.get(effTarget);
202                     gotoFixMeUps.put (v, effTarget); // delayed fixup
203

204                 } else if ( inst instanceof IfInstruction ) {
205                     Edge workingEdge
206                         = ((BinaryConnector)v.getConnector()).getOtherEdge();
207                     InstructionHandle target
208                         = (InstructionHandle) startHandles.get(
209                             getEffectiveTarget(workingEdge));
210                     BranchHandle bh = (BranchHandle) endHandles.get(v);
211                     bh.setTarget(target);
212
213                 } else if ( inst instanceof JsrInstruction ) {
214                     InstructionHandle target
215                         = (InstructionHandle) startHandles.get(
216                                 getEffectiveTarget(v.getEdge()));
217                     BranchHandle bh = (BranchHandle) endHandles.get(v);
218                     bh.setTarget(target);
219
220                 } else if (inst instanceof Select) {
221                     // has a complex connector - deal with default edge
222
InstructionHandle target
223                         = (InstructionHandle) startHandles.get(
224                                 getEffectiveTarget(v.getEdge()));
225                     // DEBUG
226
// if (target == null) {
227
// System.out.println(
228
// "BytecodeCollector.finishVertex "
229
// + v + " INTERNAL ERROR: \n"
230
// + " " + inst + " has null default target");
231
// }
232
// END
233
BranchHandle bh = (BranchHandle) endHandles.get(v);
234                     bh.setTarget(target);
235
236                     // now take care of the other edges
237
ComplexConnector conn = (ComplexConnector)v.getConnector();
238                     int edgeCount = conn.size();
239                     InstructionHandle[] targets = new InstructionHandle[edgeCount];
240                     for (int i = 0; i < edgeCount; i++) {
241                         target = (InstructionHandle) startHandles.get(
242                                     getEffectiveTarget(conn.getEdge(i)));
243                         // DEBUG
244
if (target == null) {
245                             System.out.println(
246                                 "BytecodeCollector.finishVertex "
247                                 + v + " INTERNAL ERROR: \n"
248                                 + " " + inst + " has null target " + i);
249                         }
250                         // END
251
((Select)bh.getInstruction()).setTarget(i, target);
252                     }
253                 }
254             }
255         }
256     }
257
258     /**
259      * Dump the instruction list. Debug method.
260      */

261     private void dumpIList(String JavaDoc where) {
262         System.out.println("BytecodeCollector."
263                                         + where + " instruction list:");
264         int i = 0;
265         for (InstructionHandle ih = ilist.getStart(); ih != null;
266                                                     ih = ih.getNext() ) {
267             System.out.println( " " + (i++) + " " + ih.getInstruction());
268         }
269     }
270     /**
271      * Finish the graph.
272      *
273      * @param g The control flow graph - ignored.
274      */

275     public void finishGraph( Directed g ) {
276
277     }
278
279     /**
280      * Get the instruction list after completing walking the graph,
281      * that is, after calling visit.
282      *
283      * @return A reference to the bytecode generated by walking
284      * the control flow graph.
285      */

286     public InstructionList getInstructionList() {
287         // maps vertices with gotos to their effective target vertices
288
Iterator JavaDoc k = gotoFixMeUps.keySet().iterator();
289         while (k.hasNext()) {
290             CodeVertex v = (CodeVertex) k.next();
291             // maps vertices to the handles on their connecting instructions
292
BranchHandle bh = (BranchHandle) endHandles.get(v);
293             // gets the handle on the first instruction in the target vertex
294
InstructionHandle target
295                         = (InstructionHandle) startHandles.get(
296                                                 gotoFixMeUps.get (v));
297             bh.setTarget(target); // sets the goto target
298
}
299         // dumpIList("BytecodeCollector.getInstructions, before update");
300
ilist.update();
301         // dumpIList("BytecodeCollector.getInstructions, after update");
302
return ilist;
303     }
304
305     /**
306      * Given an array of exception handler descriptions, return an
307      * array of CodeExceptionGen. The array may be empty.
308      *
309      * XXX This method has not been thoroughly tested.
310      *
311      * @param cd Array of exception handler descriptions in terms of vertices
312      * @return Array of BCEL exception handler structures.
313      */

314     public CodeExceptionGen[] getCEGs ( CatchData[] cd) {
315         CodeExceptionGen [] ceg;
316         if (cd == null) {
317             ceg = new CodeExceptionGen[ 0 ];
318         } else {
319             ceg = new CodeExceptionGen[ cd.length ];
320             for (int i = 0; i < cd.length; i++) {
321                 InstructionHandle start
322                     = (InstructionHandle) startHandles.get(cd[i].tryStart);
323                 InstructionHandle end
324                     = (InstructionHandle) startHandles.get(cd[i].tryEnd);
325                 InstructionHandle handler
326                     = (InstructionHandle) startHandles.get(cd[i].handlerPC);
327                 if ( start == null || end == null || handler == null) {
328                     System.out.println (
329                     "BytecodeCollector.getCEGs: INTERNAL ERROR - null handler\n"
330                         + " CatchData[" + i + "] start: " + cd[i].tryStart
331                         + " end: " + cd[i].tryEnd + " handler at: "
332                         + cd[i].handlerPC);
333                 }
334                 ceg[i] = new CodeExceptionGen( start, end, handler,
335                                                         cd[i].exception );
336             }
337         }
338         return ceg;
339     }
340 }
341
Popular Tags