1 /* GraphAction.java */
2 package org.quilt.cover.stmt;
3
4 import org.apache.bcel.Constants;
5 import org.apache.bcel.classfile.ConstantPool;
6 import org.apache.bcel.generic.*;
7 import org.quilt.cl.*;
8 import org.quilt.graph.*;
9
10 /***
11 * Walk the control flow graph, adding counter vertices on all edges
12 * inbound to code vertices. XXX Except those likely to cause
13 * problems; need to review this code later to make sure that all
14 * possibilities are covered.
15 *
16 * @author <a href="mailto:jddixon@users.sourceforge.net">Jim Dixon</a>
17 */
18 public class GraphAction implements GraphXformer {
19
20 private static StmtRegistry stmtReg = null;
21 private ClassGen clazz_ = null;
22 private MethodGen method_ = null;
23
24 /*** Processor name for use in reports. */
25 private static String name_ = null;
26
27 private InstructionFactory factory_;
28
29 private ConstantPoolGen cpGen_;
30
31 /*** Number of counters added to the graph. */
32 private int counterCount = 0;
33
34 /*** The class Xformer responsible for tracking counter counts */
35 private ClassAction classAct_ = null;
36
37 /*** constructor. */
38 public GraphAction () {}
39
40 public GraphAction (StmtRegistry reg) {
41 stmtReg = reg;
42 setName(this.getClass().getName());
43 }
44
45 /***
46 * Constructor used by StmtRegistry. XXX Deprecate, dropping
47 * classAct argument. (Pass via registry if it's really necessary.)
48 *
49 * @param classAct The Xformer at the class level; the method needs
50 * to report back to it.
51 */
52 public GraphAction (StmtRegistry reg, ClassAction classAct) {
53 if (reg == null || classAct == null) {
54 throw new IllegalArgumentException("null argument");
55 }
56 stmtReg = reg;
57 classAct_ = classAct;
58 setName(this.getClass().getName());
59 }
60 /*** The visitor that actually adds the vertices to the graph. */
61 private class LampLighter implements org.quilt.graph.Visitor,
62 org.apache.bcel.Constants,
63 org.apache.bcel.generic.InstructionConstants {
64 private ControlFlowGraph graph = null;
65 public LampLighter() {}
66 public void discoverGraph(Directed g) {
67 graph = (ControlFlowGraph)g;
68 }
69 public void discoverVertex(Vertex v) {
70 }
71 /***
72 * Instrument edges inbound to code vertex.
73 */
74 public void discoverEdge(Edge e) {
75 Vertex source = e.getSource();
76 Vertex target = e.getTarget();
77 ControlFlowGraph srcGraph = (ControlFlowGraph)source.getGraph();
78 ControlFlowGraph tgtGraph = (ControlFlowGraph)target.getGraph();
79 // DEBUG
80 if (tgtGraph != graph) {
81 System.out.println("GraphAction.discoverEdge:\n"
82 + " current graph is " + graph.getIndex()
83 + " but edge is " + e);
84 }
85 // END
86 boolean addingCounter = true;
87 if ( (target instanceof CodeVertex)
88 && !(target instanceof CounterVertex)
89 && !(source instanceof CounterVertex) ) {
90 Instruction srcConnInst = null;
91 if (source instanceof CodeVertex) {
92 srcConnInst = ((CodeVertex)source).getConnInst();
93 if (srcConnInst != null
94 && srcConnInst instanceof GotoInstruction
95 && (source.getGraph() != tgtGraph)) {
96 // Don't add a counter if the goto jumps out of
97 // this graph. XXX needs more thought! -- this
98 // eliminates some test failures but will fail to
99 // count some statement hits
100 addingCounter = false;
101 }
102 }
103 // XXX A BIT OF A KLUDGE (NestedTryBlocks bugfix)
104 if (srcGraph != graph) {
105 System.out.println("GraphAction.discoverEdge WARNING: "
106 + "graph index " + graph.getIndex()
107 + "\n but edge is " + e
108 + " - not adding counter");
109 addingCounter = false;
110 }
111 if (addingCounter) {
112 CounterVertex cv;
113 if (source instanceof Exit) {
114 // MOVED UP
115 // ControlFlowGraph tgtGraph
116 // = (ControlFlowGraph)target.getGraph();
117 cv = (CounterVertex) tgtGraph.insertCodeVertex(
118 (CodeVertex)new CounterVertex(tgtGraph), e);
119
120 } else {
121 cv = (CounterVertex) graph.insertCodeVertex(
122 (CodeVertex)new CounterVertex(graph), e);
123 }
124 InstructionList ilist = cv.getInstructionList();
125 InstructionHandle ih = ilist.append (
126 factory_.createFieldAccess(clazz_.getClassName(), "q$$q",
127 new ArrayType(Type.INT,1), Constants.GETSTATIC));
128 ilist.append(new PUSH(cpGen_, counterCount++));
129 ilist.append(InstructionConstants.DUP2);
130 ilist.append(InstructionConstants.IALOAD);
131 ilist.append(new PUSH(cpGen_, 1));
132 ilist.append(InstructionConstants.IADD);
133 ilist.append(InstructionConstants.IASTORE);
134 // end instruction list ///////////////////
135
136 // RETARGETING //////////////////////////////////////
137 if (source instanceof CodeVertex) {
138 if (srcConnInst != null) {
139 // UNARY ////////////////////////////////////
140
141 // BINARY ///////////////////////////////////
142 if (srcConnInst instanceof GotoInstruction) {
143 if (!( e == source.getEdge() )) {
144 ((CodeVertex)source).moveGoto(cv);
145 }
146 } else if (srcConnInst instanceof IfInstruction
147 || srcConnInst instanceof JsrInstruction ) {
148 Edge otherEdge
149 = ((BinaryConnector)source.getConnector())
150 .getOtherEdge();
151 if (e == otherEdge) {
152 // this is the 'else' branch; the
153 // counter needs to have a Goto
154 // connecting instruction
155 BranchInstruction bi
156 = (BranchInstruction) srcConnInst;
157 InstructionHandle targ = bi.getTarget();
158 bi.setTarget(ih);
159 cv.setConnInst( new GOTO (targ) );
160 // ignore the edge returned
161 cv.makeBinary();
162 BinaryConnector bc = (BinaryConnector)
163 cv.getConnector();
164 Vertex myTarget = bc.getTarget();
165 // main edge is the flow-through exit
166 // DEBUG
167 if (graph.getExit() == null) {
168 System.out.println(
169 "GRAPH HAS NULL EXIT");
170 }
171 // END
172 bc.setTarget(graph.getExit());
173 bc.setOtherTarget(myTarget);
174 }
175 }
176 // COMPLEX - Select /////////////////////////
177
178 } // if srcConnInst != null
179 }
180 } // GEEP
181 // ELSE IF ENTRY ... ////////////////////////////////
182 }
183 }
184 public void finishEdge(Edge e) {
185 }
186 public void finishVertex(Vertex v) {
187 }
188 public void finishGraph(Directed g) {
189 }
190 }
191 // Apply the transformation to the graph.
192 public void xform (final ClassGen cg, final MethodGen method,
193 final ControlFlowGraph cfg) {
194 clazz_ = cg;
195 method_ = method;
196 cpGen_ = cg.getConstantPool() ;
197 factory_ = new InstructionFactory (clazz_, cpGen_);
198
199 String className = clazz_.getClassName();
200 Ephemera eph = stmtReg.getEphemera(className);
201 // DEBUG
202 if (eph == null)
203 System.out.println("GraphAction.xform: eph is null!");
204 // END
205 counterCount = eph.getCounterCount();
206
207 int cfgSize = cfg.size();
208 Walker walker = new Walker();
209 walker.visit(cfg, new LampLighter());
210
211 // unnecessary, I think, because the ConstantPoolGen is part
212 // of the ClassGen
213 // clazz_.setConstantPool(cpGen_.getFinalConstantPool());
214
215 eph.setEndCount(method.getName(), counterCount);
216
217
218 }
219 // GET/SET METHODS //////////////////////////////////////////////
220 /*** Get the name for the transformation. */
221 public static String getName() {
222 return name_;
223 }
224 /***
225 * Set a name for the transformation, to allow reports to refer
226 * to it.
227 */
228 public static void setName(String name) {
229 name_ = name;
230 }
231 }
This page was automatically generated by Maven