1 salcianu 1.1 // InstrumentAllocs.java, created Tue Nov  7 14:29:16 2000 by root
  2 salcianu 1.1 // Copyright (C) 2000 Brian Demsky <bdemsky@mit.edu>
  3 salcianu 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 salcianu 1.1 package harpoon.Instrumentation.AllocationStatistics;
  5 salcianu 1.1 
  6 salcianu 1.1 import harpoon.Analysis.Transformation.MethodMutator;
  7 salcianu 1.1 import harpoon.ClassFile.HClass;
  8 salcianu 1.1 import harpoon.ClassFile.HCode;
  9 salcianu 1.1 import harpoon.ClassFile.HCodeAndMaps;
 10 salcianu 1.1 import harpoon.ClassFile.HCodeFactory;
 11 salcianu 1.1 import harpoon.ClassFile.HMethod;
 12 salcianu 1.1 import harpoon.ClassFile.Linker;
 13 salcianu 1.1 import harpoon.Temp.TempFactory;
 14 salcianu 1.1 import harpoon.Temp.Temp;
 15 salcianu 1.2 import harpoon.IR.Quads.Code;
 16 salcianu 1.1 import harpoon.IR.Quads.Quad;
 17 salcianu 1.1 import harpoon.IR.Quads.QuadVisitor;
 18 salcianu 1.1 import harpoon.IR.Quads.QuadFactory;
 19 salcianu 1.1 import harpoon.IR.Quads.QuadNoSSA;
 20 salcianu 1.1 import harpoon.IR.Quads.MONITORENTER;
 21 salcianu 1.1 import harpoon.IR.Quads.NEW;
 22 salcianu 1.1 import harpoon.IR.Quads.ALENGTH;
 23 salcianu 1.1 import harpoon.IR.Quads.ANEW;
 24 salcianu 1.1 import harpoon.IR.Quads.CALL;
 25 salcianu 1.1 import harpoon.IR.Quads.CONST;
 26 salcianu 1.1 import harpoon.IR.Quads.PHI;
 27 salcianu 1.1 import harpoon.IR.Quads.RETURN;
 28 salcianu 1.1 import harpoon.IR.Quads.THROW;
 29 cananian 1.4 import net.cscott.jutil.WorkSet;
 30 salcianu 1.1 import java.util.HashMap;
 31 salcianu 1.1 import java.util.Iterator;
 32 salcianu 1.1 import java.util.Map;
 33 salcianu 1.1 
 34 salcianu 1.1 /**
 35 salcianu 1.1  * <code>InstrumentAllocs</code> adds calls to instrumenting code to
 36 salcianu 1.1  * each allocation site and, if explicitly requested, to each
 37 salcianu 1.1  * synchronization instruction.  If call chain sensitivity is
 38 salcianu 1.1  * requested, instrumentation is added around method calls to.  The
 39 salcianu 1.1  * produced code prints the instrumentation statistics at the end of
 40 salcianu 1.1  * the program.
 41 salcianu 1.1  * 
 42 salcianu 1.1  * @author  Brian Demsky <bdemsky@mit.edu>
 43 cananian 1.5  * @version $Id: InstrumentAllocs.java,v 1.5 2004/02/08 03:21:32 cananian Exp $ */
 44 salcianu 1.1 public class InstrumentAllocs extends MethodMutator
 45 salcianu 1.1     implements java.io.Serializable {
 46 salcianu 1.1 
 47 salcianu 1.1     private final HMethod main;
 48 salcianu 1.1     private final AllocationNumbering an;
 49 salcianu 1.1 
 50 salcianu 1.1     private final boolean syncs;
 51 salcianu 1.1     private final boolean callchains;
 52 salcianu 1.1 
 53 salcianu 1.1     /** Creates a <code>InstrumentAllocs</code>.
 54 salcianu 1.1 
 55 salcianu 1.1         @param parent <code>HCodeFactory</code> that provides the code
 56 salcianu 1.1         to instrument
 57 salcianu 1.1 
 58 salcianu 1.1         @param main main method of the instrumented program
 59 salcianu 1.1 
 60 salcianu 1.1         @param linker linker for the code to instrument
 61 salcianu 1.1 
 62 salcianu 1.1         @param an <code>AllocationNumbering</code> for the
 63 salcianu 1.1         allocation/call sites
 64 salcianu 1.1 
 65 salcianu 1.1         @param syncs if true, then the synchronization operations are
 66 salcianu 1.1         instrumented too.
 67 salcianu 1.1 
 68 salcianu 1.1         @param callchains if true, the instrumented code will record
 69 salcianu 1.1         the call chains for ecah execution of the instrumented
 70 salcianu 1.1         instructions. */
 71 salcianu 1.1     public InstrumentAllocs(HCodeFactory parent, HMethod main,
 72 salcianu 1.1                             Linker linker, AllocationNumbering an,
 73 salcianu 1.1                             boolean syncs, boolean callchains) {
 74 salcianu 1.1         super(parent);
 75 salcianu 1.1         
 76 salcianu 1.1         assert
 77 salcianu 1.1             parent.getCodeName().equals(QuadNoSSA.codename) :
 78 salcianu 1.1             "InstrumentAllocs works only with QuadNoSSA";
 79 salcianu 1.1 
 80 salcianu 1.1         this.main   = main;
 81 salcianu 1.1         this.an     = an;
 82 salcianu 1.1         this.syncs      = syncs;
 83 salcianu 1.1         this.callchains = callchains;
 84 salcianu 1.1 
 85 salcianu 1.2         init_methods(linker);
 86 salcianu 1.1     }
 87 salcianu 1.1 
 88 salcianu 1.2 
 89 salcianu 1.2     private void init_methods(Linker linker) {
 90 salcianu 1.1         hc_obj = linker.forName("java.lang.Object");
 91 salcianu 1.1 
 92 salcianu 1.1         hm_count_alloc =
 93 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport", "count",
 94 salcianu 1.1                        new HClass[]{HClass.Int});    
 95 salcianu 1.1         hm_count_sync =
 96 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport", "countm",
 97 salcianu 1.1                        new HClass[]{hc_obj});
 98 salcianu 1.1 
 99 salcianu 1.1         method3 =
100 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport", "label",
101 salcianu 1.1                        new HClass[]{hc_obj, HClass.Int});
102 salcianu 1.1     
103 salcianu 1.1         hm_call_enter = 
104 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport", "callenter",
105 salcianu 1.1                        new HClass[]{HClass.Int});
106 salcianu 1.1     
107 salcianu 1.1         hm_call_exit =
108 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport", "callexit",
109 salcianu 1.1                        new HClass[0]);
110 salcianu 1.1         
111 salcianu 1.1         hm_instr_exit = 
112 salcianu 1.2             getMethod(linker, "harpoon.Runtime.CounterSupport",
113 salcianu 1.1                        "exit", new HClass[0]);
114 salcianu 1.1         
115 salcianu 1.2         hm_orig_exit = getMethod(linker, "java.lang.System", "exit", "(I)V");
116 salcianu 1.1     }
117 salcianu 1.1 
118 salcianu 1.3     /** Returns that method of class <code>clsn</code> that is called
119 salcianu 1.3         <code>mn</code> and has arguments of types
120 salcianu 1.3         <code>a_types</code>. */
121 salcianu 1.3     public static HMethod getMethod(Linker linker, String clsn, String mn,
122 salcianu 1.2                              HClass[] atypes) {
123 salcianu 1.1         return linker.forName(clsn).getMethod(mn, atypes);
124 salcianu 1.1     }
125 salcianu 1.2     
126 salcianu 1.1     // like previous method except that the arg types are given as a string
127 salcianu 1.2     static HMethod getMethod(Linker linker, String clsn, String mn,
128 salcianu 1.2                              String atypes) {
129 salcianu 1.1         return linker.forName(clsn).getMethod(mn, atypes);
130 salcianu 1.1     }
131 salcianu 1.1 
132 salcianu 1.1 
133 salcianu 1.1     // handles for important methods
134 salcianu 1.1     private HClass hc_obj;
135 salcianu 1.1 
136 salcianu 1.1     private HMethod hm_count_alloc;
137 salcianu 1.1     private HMethod hm_count_sync;
138 salcianu 1.1     // what's this? TODO: find more appropriate name [AS]
139 salcianu 1.1     private HMethod method3;
140 salcianu 1.1     private HMethod hm_call_enter;
141 salcianu 1.1     private HMethod hm_call_exit;
142 salcianu 1.1     private HMethod hm_instr_exit;
143 salcianu 1.1     private HMethod hm_orig_exit;
144 salcianu 1.1 
145 salcianu 1.1     protected HCode mutateHCode(HCodeAndMaps input) {
146 salcianu 1.1         HCode hc = input.hcode();
147 salcianu 1.1 
148 salcianu 1.1         // we avoid instrumenting the instrumentation itself !
149 salcianu 1.1         if (hc.getMethod().getDeclaringClass().getName().
150 salcianu 1.1             equals("harpoon.Runtime.CounterSupport"))
151 salcianu 1.1             return hc;
152 salcianu 1.1 
153 salcianu 1.2         instrumentProgramTermination(hc, hm_orig_exit, hm_instr_exit);
154 salcianu 1.1 
155 salcianu 1.1         WorkSet newset = new WorkSet();
156 salcianu 1.1         for(Iterator it = hc.getElementsI(); it.hasNext(); ) {
157 salcianu 1.1             Quad q = (Quad)it.next();
158 salcianu 1.1             if ((q instanceof NEW) || (q instanceof ANEW) ||
159 salcianu 1.1                 (syncs && (q instanceof MONITORENTER)) ||
160 salcianu 1.1                 (q instanceof CALL))
161 salcianu 1.1                 newset.add(q);
162 salcianu 1.1         }
163 salcianu 1.1         
164 salcianu 1.2         instr_visitor.ancestor = input.ancestorElementMap();
165 salcianu 1.2 
166 cananian 1.5         for(Object qO : newset) {
167 cananian 1.5             Quad q = (Quad) qO;
168 salcianu 1.1             instr_visitor.qf = q.getFactory();
169 salcianu 1.1             instr_visitor.tf = instr_visitor.qf.tempFactory();
170 salcianu 1.1             q.accept(instr_visitor);
171 salcianu 1.1         }
172 salcianu 1.1 
173 salcianu 1.1         instr_visitor.ancestor = null;
174 salcianu 1.2         instr_visitor.qf       = null;
175 salcianu 1.2         instr_visitor.tf       = null;
176 salcianu 1.1             
177 salcianu 1.1         if (hc.getMethod().equals(main))
178 salcianu 1.2             treatMainMethod(hc, hm_instr_exit);
179 salcianu 1.1 
180 salcianu 1.1         // hc.print(new java.io.PrintWriter(System.out, true));
181 salcianu 1.1         return hc;
182 salcianu 1.1     }
183 salcianu 1.1 
184 salcianu 1.1     private InstrQuadVisitor instr_visitor = new InstrQuadVisitor();
185 salcianu 1.1 
186 salcianu 1.1     private class InstrQuadVisitor extends QuadVisitor {
187 salcianu 1.1         QuadFactory qf;
188 salcianu 1.1         TempFactory tf;
189 salcianu 1.1         Map ancestor;
190 salcianu 1.1 
191 salcianu 1.1         public void visit(MONITORENTER q) {
192 salcianu 1.1             CALL qcall = 
193 salcianu 1.1                 new CALL(qf, q, hm_count_sync, new Temp[] {q.lock()}, null,
194 salcianu 1.1                          new Temp(tf), false, false,
195 salcianu 1.1                          new Temp[0][2], new Temp[0]);
196 salcianu 1.1             PHI qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
197 salcianu 1.1 
198 salcianu 1.1             make_links(q, qcall, qphi);
199 salcianu 1.1         }
200 salcianu 1.1         
201 salcianu 1.1         public void visit(CALL q) {
202 salcianu 1.1             if (q.method().equals(hm_orig_exit)) {
203 salcianu 1.1                 CALL qcall =
204 salcianu 1.1                     new CALL(qf, q, hm_instr_exit, new Temp[0], null,
205 salcianu 1.1                              new Temp(tf), false, false, new Temp[0][2],
206 salcianu 1.1                              new Temp[0]);
207 salcianu 1.1                 PHI qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
208 salcianu 1.1 
209 salcianu 1.1                 make_links(q, qcall, qphi);
210 salcianu 1.1             }
211 salcianu 1.1             
212 salcianu 1.1             if (callchains) {
213 salcianu 1.1                 try {
214 salcianu 1.1                     treat_callchains(q);
215 salcianu 1.1                 }
216 salcianu 1.1                 catch(Error e) {
217 salcianu 1.1                 }
218 salcianu 1.1             }
219 salcianu 1.1         }
220 salcianu 1.1 
221 salcianu 1.1         private void treat_callchains(Quad q) {
222 salcianu 1.1             Temp tconst = new Temp(tf);
223 salcianu 1.1             Temp texcept = new Temp(tf);
224 salcianu 1.1 
225 salcianu 1.1             // index inside AllocationNumbering
226 salcianu 1.1             int an_idx = an.callID((Quad) ancestor.get(q));
227 salcianu 1.1             CONST qconst =
228 salcianu 1.1                 new CONST(qf, q, tconst, new Integer(an_idx), HClass.Int);
229 salcianu 1.1             CALL qcall =
230 salcianu 1.1                 new CALL(qf, q, hm_call_enter, new Temp[]{tconst}, null,
231 salcianu 1.1                          texcept, false, false, new Temp[0][2], new Temp[0]);
232 salcianu 1.1             PHI qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
233 salcianu 1.1             
234 salcianu 1.1             Quad.addEdge(qconst, 0, qcall, 0);
235 salcianu 1.1             link_call_2_phi(qcall, qphi);
236 salcianu 1.1             Quad.addEdge(q.prev(0), q.prevEdge(0).which_succ(), qconst, 0);
237 salcianu 1.1             Quad.addEdge(qphi, 0, q, 0);
238 salcianu 1.1             
239 salcianu 1.1             CALL qcall2 = 
240 salcianu 1.1                 new CALL(qf, q, hm_call_exit, new Temp[]{}, null, texcept,
241 salcianu 1.1                          false, false, new Temp[0][2], new Temp[0]);
242 salcianu 1.1             PHI qphi2 = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
243 salcianu 1.1             
244 salcianu 1.1             link_call_2_phi(qcall2, qphi2);
245 salcianu 1.1             Quad.addEdge(qphi2, 0, q.next(0), q.nextEdge(0).which_pred());
246 salcianu 1.1             Quad.addEdge(q, 0, qcall2, 0);
247 salcianu 1.1             
248 salcianu 1.1             CALL qcall3 =
249 salcianu 1.1                 new CALL(qf, q, hm_call_exit, new Temp[]{}, null, texcept,
250 salcianu 1.1                          false, false, new Temp[0][2], new Temp[0]);
251 salcianu 1.1             PHI qphi3 = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
252 salcianu 1.1             
253 salcianu 1.1             link_call_2_phi(qcall3, qphi3);
254 salcianu 1.1             Quad.addEdge(qphi3, 0, q.next(1), q.nextEdge(1).which_pred());
255 salcianu 1.1             Quad.addEdge(q, 1, qcall3, 0);
256 salcianu 1.1         }
257 salcianu 1.1 
258 salcianu 1.1 
259 salcianu 1.1         public void visit(NEW q) {
260 salcianu 1.1             treat_allocs(q);
261 salcianu 1.1         }
262 salcianu 1.1         
263 salcianu 1.1         public void visit(ANEW q) {
264 salcianu 1.1             treat_allocs(q);
265 salcianu 1.1         }
266 salcianu 1.1         
267 salcianu 1.1         
268 salcianu 1.1         private void treat_allocs(Quad q) {
269 salcianu 1.1             try {
270 salcianu 1.1                 treat_allocs_real(q);
271 salcianu 1.3             } catch (UnknownAllocationSiteError e) {
272 salcianu 1.3                 // Ignore, means this code called only by our
273 salcianu 1.3                 // instrumenting code
274 salcianu 1.1             }
275 salcianu 1.1         }
276 salcianu 1.1         
277 salcianu 1.1         private void treat_allocs_real(Quad q) {
278 salcianu 1.1             assert ((q instanceof NEW) || (q instanceof ANEW)) :
279 salcianu 1.1                 "unexpected quad type " + q;
280 salcianu 1.2 
281 salcianu 1.2             Temp tconst  = new Temp(tf);
282 salcianu 1.1             Temp texcept = new Temp(tf);
283 salcianu 1.1 
284 salcianu 1.1             // index inside AllocationNumbering
285 salcianu 1.1             int an_idx = an.allocID((Quad) ancestor.get(q));
286 salcianu 1.1             CONST qconst =
287 salcianu 1.1                 new CONST(qf, q, tconst, new Integer(an_idx), HClass.Int);
288 salcianu 1.1             CALL qcall =
289 salcianu 1.1                 new CALL(qf, q, hm_count_alloc, new Temp[]{tconst}, null,
290 salcianu 1.1                          texcept, false, false, new Temp[0][2],
291 salcianu 1.1                          new Temp[0]);
292 salcianu 1.1             PHI qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
293 salcianu 1.1             
294 salcianu 1.1             Quad.addEdge(qconst, 0, qcall, 0);
295 salcianu 1.1             link_call_2_phi(qcall, qphi);
296 salcianu 1.1             Quad.addEdge(q.prev(0), q.prevEdge(0).which_succ(), qconst, 0);
297 salcianu 1.1             Quad.addEdge(qphi, 0, q, 0);
298 salcianu 1.1         
299 salcianu 1.1             if (syncs) {
300 salcianu 1.1                 Temp dst = (q instanceof NEW) ?
301 salcianu 1.1                     ((NEW)q).dst() : ((ANEW)q).dst();
302 salcianu 1.1                 
303 salcianu 1.1                 qcall =
304 salcianu 1.1                     new CALL(qf, q, method3, new Temp[]{dst, tconst}, null,
305 salcianu 1.1                              texcept, false, false, new Temp[0][2],
306 salcianu 1.1                              new Temp[0]);
307 salcianu 1.1                 qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
308 salcianu 1.1 
309 salcianu 1.1                 link_call_2_phi(qcall, qphi);
310 salcianu 1.1                 Quad.addEdge(qphi, 0, q.next(0), q.nextEdge(0).which_pred());
311 salcianu 1.1                 Quad.addEdge(q, 0, qcall, 0);
312 salcianu 1.1             }
313 salcianu 1.1         }
314 salcianu 1.1 
315 salcianu 1.1         // take care of all the other quad types
316 salcianu 1.1         public void visit(Quad q) {
317 salcianu 1.1             assert false : "unexpected quad type " + q;
318 salcianu 1.1         }
319 salcianu 1.1     };
320 salcianu 1.1 
321 salcianu 1.1 
322 salcianu 1.1     // merge both exits from the CALL qcall into PHI: qcall => qphi
323 salcianu 1.1     private static void link_call_2_phi(CALL qcall, PHI qphi) {
324 salcianu 1.1         Quad.addEdge(qcall, 0, qphi, 0);
325 salcianu 1.1         Quad.addEdge(qcall, 1, qphi, 1);
326 salcianu 1.1     }
327 salcianu 1.1     
328 salcianu 1.1     // connect q.prev(0) -> qcall => qphi -> q
329 salcianu 1.2     static void make_links(Quad q, CALL qcall, PHI qphi) {
330 salcianu 1.1         link_call_2_phi(qcall, qphi);
331 salcianu 1.1         Quad.addEdge(q.prev(0), q.prevEdge(0).which_succ(), qcall, 0);
332 salcianu 1.1         Quad.addEdge(qphi, 0, q, 0);
333 salcianu 1.1     }
334 salcianu 1.1     
335 salcianu 1.1 
336 salcianu 1.1     // make sure that any normal / exceptional return from main (which
337 salcianu 1.1     // is equivalent to the program termination) outputs the computed
338 salcianu 1.1     // allocated map by calling harpoon.Runtime.CounterSupport.exit();
339 salcianu 1.2     static void treatMainMethod(HCode hc, HMethod hm_instr_exit) {
340 salcianu 1.1         WorkSet exitset = new WorkSet();
341 salcianu 1.1         
342 salcianu 1.1         for(Iterator it = hc.getElementsI(); it.hasNext(); ) {
343 salcianu 1.2             Quad q = (Quad) it.next();
344 salcianu 1.1             if ((q instanceof RETURN) || (q instanceof THROW))
345 salcianu 1.1                 exitset.add(q);
346 salcianu 1.1         }
347 salcianu 1.1         
348 salcianu 1.1         QuadFactory qf = ((Quad) hc.getRootElement()).getFactory();
349 salcianu 1.1         TempFactory tf = qf.tempFactory();
350 salcianu 1.1 
351 cananian 1.5         for(Object qO : exitset) {
352 cananian 1.5             Quad q = (Quad) qO;
353 salcianu 1.1             CALL qcall =
354 salcianu 1.1                 new CALL(qf, q, hm_instr_exit, new Temp[0], null, new Temp(tf),
355 salcianu 1.1                          false, false, new Temp[0][2], new Temp[0]);
356 salcianu 1.1             PHI qphi = new PHI(qf, q, new Temp[0], new Temp[0][2], 2);
357 salcianu 1.1             make_links(q, qcall, qphi);
358 salcianu 1.2         }
359 salcianu 1.2     }
360 salcianu 1.2 
361 salcianu 1.2 
362 salcianu 1.2     // add code to precede each call to hm_exit by a call to hm_instr_exit
363 salcianu 1.2     // (the method that outputs the result of the instrumentation)
364 salcianu 1.2     static void instrumentProgramTermination
365 salcianu 1.2         (HCode hcode, HMethod hm_exit, HMethod hm_instr_exit) {
366 cananian 1.5         for(Object callO : ((Code) hcode).selectCALLs()) {
367 cananian 1.5             CALL call = (CALL) callO;
368 salcianu 1.2             if (call.method().equals(hm_exit)) {
369 salcianu 1.2                 QuadFactory qf = call.getFactory();
370 salcianu 1.2                 TempFactory tf = qf.tempFactory();
371 salcianu 1.2                 CALL qcall =
372 salcianu 1.2                     new CALL(qf, call, hm_instr_exit, new Temp[0], null,
373 salcianu 1.2                              new Temp(tf), false, false, new Temp[0][2],
374 salcianu 1.2                              new Temp[0]);
375 salcianu 1.2                 PHI qphi = new PHI(qf, call, new Temp[0], new Temp[0][2], 2);
376 salcianu 1.2                 make_links(call, qcall, qphi);
377 salcianu 1.2             }
378 salcianu 1.1         }
379 salcianu 1.1     }
380 salcianu 1.1 
381 salcianu 1.1 }