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 }