1 salcianu 1.1 // ComputeMuClosure.java, created Tue Oct 8 11:11:44 2002 by salcianu 2 salcianu 1.1 // Copyright (C) 2000 Alexandru Salcianu <salcianu@MIT.EDU> 3 salcianu 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 salcianu 1.1 package harpoon.Analysis.PointerAnalysis; 5 salcianu 1.1 6 salcianu 1.1 import harpoon.IR.Quads.CALL; 7 salcianu 1.1 import harpoon.Temp.Temp; 8 salcianu 1.1 import harpoon.Util.DataStructs.Relation; 9 salcianu 1.1 import harpoon.Util.DataStructs.RelationImpl; 10 salcianu 1.2 import harpoon.Util.Util; 11 salcianu 1.2 12 salcianu 1.4 import harpoon.Analysis.MetaMethods.GenType; 13 salcianu 1.4 14 salcianu 1.2 import java.util.Set; 15 salcianu 1.2 import java.util.HashSet; 16 salcianu 1.4 import java.util.Hashtable; 17 salcianu 1.2 import java.util.Iterator; 18 salcianu 1.1 19 salcianu 1.1 /** 20 salcianu 1.1 <code>ComputeMuClosure</code> is a [functional-programming style] 21 salcianu 1.1 closure for the <code>computeInterProcMu method</code>. See the 22 salcianu 1.1 comments around that method for more info. 23 salcianu 1.1 24 salcianu 1.1 @author Alexandru Salcianu <salcianu@MIT.EDU> 25 cananian 1.6 @version $Id: ComputeInterProcMuClosure.java,v 1.6 2004/02/08 03:20:02 cananian Exp $ */ 26 salcianu 1.1 public class ComputeInterProcMuClosure { 27 salcianu 1.1 28 salcianu 1.4 static boolean DEBUG = false; 29 salcianu 1.1 30 salcianu 1.1 /** Compute the node mappings for the inter-procedural analysis, 31 salcianu 1.1 according to the method outlined in Alex Salcianu's SM thesis 32 salcianu 1.1 (Figure 2-8, page 39). 33 salcianu 1.1 34 salcianu 1.1 @param call analyzed call site 35 salcianu 1.1 @param pig_caller graph for the point right before the call 36 salcianu 1.1 @param pig_callee summary graph for the end of the callee method 37 salcianu 1.1 @param callee_params PARAM nodes for the callee 38 salcianu 1.1 39 salcianu 1.1 @return node mapping relation */ 40 salcianu 1.1 public static Relation computeInterProcMu 41 salcianu 1.1 (CALL call, ParIntGraph pig_caller, ParIntGraph pig_callee, 42 salcianu 1.4 PANode[] callee_params, PointerAnalysis pa) { 43 salcianu 1.3 44 salcianu 1.1 if(DEBUG) { 45 salcianu 1.1 System.out.println 46 salcianu 1.1 ("computeInterProcMu:\n" + 47 salcianu 1.2 "call = " + Util.code2str(call) + "\n" + 48 salcianu 1.3 /* 49 salcianu 1.1 "pig_caller = " + pig_caller + "\n" + 50 salcianu 1.1 "pig_callee = " + pig_callee + "\n" + 51 salcianu 1.3 */ 52 salcianu 1.1 "callee_params = {"); 53 salcianu 1.1 for(int i = 0; i < callee_params.length; i++) 54 salcianu 1.1 System.out.println(" " + callee_params[i]); 55 salcianu 1.1 System.out.println("}\n"); 56 salcianu 1.1 } 57 salcianu 1.1 58 salcianu 1.1 ComputeInterProcMuClosure cmc = new ComputeInterProcMuClosure 59 salcianu 1.4 (call, pig_caller, pig_callee, callee_params, pa); 60 salcianu 1.1 cmc.compute_mu(); 61 salcianu 1.3 62 salcianu 1.1 return cmc.mu; 63 salcianu 1.1 } 64 salcianu 1.1 65 salcianu 1.1 66 salcianu 1.1 // no outside entity can create this object 67 salcianu 1.1 private ComputeInterProcMuClosure() { 68 salcianu 1.1 // this will never be executed; it's here only because 69 salcianu 1.1 // otherwise the compiler complains that the final vars are 70 salcianu 1.1 // not initialized. 71 salcianu 1.4 this(null, null, null, null, null); 72 salcianu 1.1 } 73 salcianu 1.1 74 salcianu 1.1 private ComputeInterProcMuClosure 75 salcianu 1.1 (CALL call, ParIntGraph pig_caller, ParIntGraph pig_callee, 76 salcianu 1.4 PANode[] callee_params, PointerAnalysis pa) { 77 salcianu 1.1 this.call = call; 78 salcianu 1.1 this.pig_caller = pig_caller; 79 salcianu 1.1 this.pig_callee = pig_callee; 80 salcianu 1.1 this.callee_params = callee_params; 81 salcianu 1.4 this.pa = pa; 82 salcianu 1.1 } 83 salcianu 1.1 84 salcianu 1.1 // closure fields 85 salcianu 1.1 private final CALL call; 86 salcianu 1.1 private final ParIntGraph pig_caller; 87 salcianu 1.1 private final ParIntGraph pig_callee; 88 salcianu 1.1 private final PANode[] callee_params; 89 salcianu 1.1 private final Relation mu = new RelationImpl(); 90 salcianu 1.4 private final PointerAnalysis pa; 91 salcianu 1.1 92 salcianu 1.1 // top-level driver for the node mapping generation 93 salcianu 1.1 private void compute_mu() { 94 salcianu 1.1 // 2.5 and 2.6 95 salcianu 1.1 initialize_mu(); 96 salcianu 1.1 97 salcianu 1.1 if(DEBUG) 98 salcianu 1.1 System.out.println("Initial mu: " + mu); 99 salcianu 1.1 100 salcianu 1.1 // 2.7 and 2.8 101 salcianu 1.1 extend_mu(); 102 salcianu 1.1 103 salcianu 1.1 if(DEBUG) 104 salcianu 1.1 System.out.println("Middle mu: " + mu); 105 salcianu 1.1 106 salcianu 1.1 // extend mu to obtain mu' 107 salcianu 1.1 compute_final_mu(); 108 salcianu 1.1 109 salcianu 1.3 /* 110 salcianu 1.1 if(DEBUG) 111 salcianu 1.1 System.out.println("Final mu: " + mu); 112 salcianu 1.3 */ 113 salcianu 1.1 } 114 salcianu 1.1 115 salcianu 1.1 116 salcianu 1.1 // Compute a node mapping initialized by 2.5 and 2.6 117 salcianu 1.1 private void initialize_mu() { 118 salcianu 1.1 // 2.5: map parameters nodes to the actual arguments 119 salcianu 1.1 map_parameters(); 120 salcianu 1.1 121 salcianu 1.4 if(!PointerAnalysis.TOPLAS_PAPER) { 122 salcianu 1.4 // 2.6: reflexive mapping of static nodes from callee 123 salcianu 1.4 pig_callee.forAllNodes(new PANodeVisitor() { 124 salcianu 1.4 public void visit(PANode node) { 125 salcianu 1.4 if((node.type == PANode.STATIC) || 126 salcianu 1.4 // LOST nodes may represent STATIC nodes 127 salcianu 1.4 (PointerAnalysis.COMPRESS_LOST_NODES && 128 salcianu 1.4 (node.type == PANode.LOST))) 129 salcianu 1.4 mu.add(node, node); 130 salcianu 1.4 } 131 salcianu 1.4 }); 132 salcianu 1.4 } 133 salcianu 1.1 } 134 salcianu 1.1 135 salcianu 1.1 // Update the mapping mu to contain the mappings for the parameter nodes 136 salcianu 1.1 private void map_parameters() { 137 salcianu 1.1 Temp[] args = call.params(); 138 salcianu 1.1 int object_params_count = 0; 139 salcianu 1.1 // map the object formal parameter nodes to the actual arguments 140 salcianu 1.1 for(int i = 0; i < args.length; i++) 141 salcianu 1.1 if(!call.paramType(i).isPrimitive()) { 142 salcianu 1.4 // null only for some native methods 143 salcianu 1.4 if(callee_params != null) 144 salcianu 1.4 addMappingAll(mu, 145 salcianu 1.4 callee_params[object_params_count], 146 salcianu 1.4 pig_caller.G.I.pointedNodes(args[i])); 147 salcianu 1.1 object_params_count++; 148 salcianu 1.1 } 149 salcianu 1.1 150 salcianu 1.4 assert (callee_params == null) || 151 salcianu 1.4 (object_params_count == callee_params.length) : 152 salcianu 1.1 "\tDifferent numbers of object formals (" + 153 salcianu 1.1 callee_params.length + ") and object arguments (" + 154 salcianu 1.2 object_params_count + ") for \n\t" + Util.code2str(call); 155 salcianu 1.1 } 156 salcianu 1.1 157 salcianu 1.1 158 salcianu 1.1 // Initially, all the nodes from the callee are put into the 159 salcianu 1.1 // caller's graph except for the PARAM nodes. Later, after 160 salcianu 1.1 // recomputing the escape info, the empty load nodes will be 161 salcianu 1.1 // removed. Thesis equivalent: part 2 of the mapping function 162 salcianu 1.1 // (Figure 2-8), mu is extended to produce mu' 163 salcianu 1.1 private void compute_final_mu() { 164 salcianu 1.1 pig_callee.forAllNodes(new PANodeVisitor() { 165 salcianu 1.1 public void visit(PANode node) { 166 salcianu 1.1 if(node.type != PANode.PARAM) 167 salcianu 1.1 mu.add(node, node); 168 salcianu 1.1 } 169 salcianu 1.1 }); 170 salcianu 1.1 } 171 salcianu 1.1 172 salcianu 1.1 173 salcianu 1.1 174 salcianu 1.1 // iteratively apply 2.7 and 2.8 to compute l.f.p. of 2.5-2.8 175 salcianu 1.1 private void extend_mu() { 176 salcianu 1.1 // worklist containing nodes with new mappings 177 salcianu 1.1 W = new PAWorkList(); 178 salcianu 1.1 // relation containing the new mappings for nodes from the worklist 179 salcianu 1.1 new_mu = (Relation) mu.clone(); 180 salcianu 1.4 rev_mu = mu.revert(new RelationImpl()); 181 salcianu 1.1 182 salcianu 1.1 W.addAll(mu.keys()); 183 salcianu 1.1 while(!W.isEmpty()) { 184 salcianu 1.1 PANode node = (PANode) W.remove(); 185 salcianu 1.1 // apply all newly enabled instances of 2.7 186 salcianu 1.1 match_callee_caller(node); 187 salcianu 1.1 // apply all newly enabled instances of 2.8 188 salcianu 1.4 match_callee_callee(node); 189 salcianu 1.1 } 190 salcianu 1.1 191 salcianu 1.1 W = null; 192 salcianu 1.1 new_mu = null; 193 salcianu 1.1 } 194 salcianu 1.1 // Yeah, I know these should be packaged with extend_mu (and 195 salcianu 1.1 // posibly other methods) into a separate closure! I'm lazy ... 196 salcianu 1.1 private PAWorkList W; 197 salcianu 1.1 private Relation new_mu; 198 salcianu 1.1 private Relation rev_mu; 199 salcianu 1.1 200 salcianu 1.1 201 salcianu 1.4 // add the (potentially new) mapping source -> target; return 202 salcianu 1.1 // true if this is indeed a new mapping 203 salcianu 1.1 private boolean add_mapping_aux(PANode source, PANode target) { 204 salcianu 1.4 if(addMapping(mu, source, target)) { 205 salcianu 1.3 NEWINFO = true; 206 salcianu 1.1 if(DEBUG) 207 salcianu 1.1 System.out.println("new mapping: " + source + " -> " + target); 208 salcianu 1.1 new_mu.add(source, target); 209 salcianu 1.1 rev_mu.add(target, source); 210 salcianu 1.1 return true; 211 salcianu 1.1 } 212 salcianu 1.1 return false; 213 salcianu 1.1 } 214 salcianu 1.1 215 salcianu 1.1 // add one mapping; if this adds new info, source is put into W 216 salcianu 1.1 private void add_mapping(PANode source, PANode target) { 217 salcianu 1.1 if(add_mapping_aux(source, target)) 218 salcianu 1.1 W.add(source); 219 salcianu 1.1 } 220 salcianu 1.1 221 salcianu 1.1 // add several mappings; if any new info, source is put into W 222 salcianu 1.1 private void add_mappings(PANode source, Set targets) { 223 salcianu 1.1 if(targets.isEmpty()) return; 224 salcianu 1.1 boolean changed = false; 225 cananian 1.6 for(Object targetO : targets) { 226 cananian 1.6 PANode target = (PANode) targetO; 227 salcianu 1.1 if(add_mapping_aux(source, target)) 228 salcianu 1.1 changed = true; 229 salcianu 1.1 } 230 salcianu 1.1 if(changed) 231 salcianu 1.1 W.add(source); 232 salcianu 1.1 } 233 salcianu 1.1 234 salcianu 1.1 235 salcianu 1.1 // try to apply constraint 2.7 for node1 236 salcianu 1.1 private void match_callee_caller(PANode node1) { 237 salcianu 1.1 for(Iterator itf = pig_callee.G.O.allFlagsForNode(node1).iterator(); 238 salcianu 1.1 itf.hasNext(); ) 239 salcianu 1.1 match_callee_caller(node1, (String) itf.next()); 240 salcianu 1.1 } 241 salcianu 1.1 242 salcianu 1.1 // apply 2.7 for the field f 243 salcianu 1.1 private void match_callee_caller(PANode node1, String f) { 244 salcianu 1.1 Set node2s = pig_callee.G.O.pointedNodes(node1, f); 245 salcianu 1.1 if(node2s.isEmpty()) return; 246 salcianu 1.1 Set node4s = pig_caller.G.I.pointedNodes(new_mu.getValues(node1), f); 247 salcianu 1.1 if(node4s.isEmpty()) return; 248 salcianu 1.1 249 salcianu 1.3 NEWINFO = false; 250 salcianu 1.1 251 cananian 1.6 for(Object node2O : node2s) { 252 cananian 1.6 PANode node2 = (PANode) node2O; 253 salcianu 1.1 add_mappings(node2, node4s); 254 salcianu 1.1 } 255 salcianu 1.3 256 salcianu 1.3 if(NEWINFO && DEBUG) 257 salcianu 1.3 System.out.println("2.7 for node1=" + node1 + ", f=" + f + "\n"); 258 salcianu 1.1 } 259 salcianu 1.1 260 salcianu 1.1 // try to apply constraint 2.8 for node1/node3 = node 261 salcianu 1.1 private void match_callee_callee(PANode node) { 262 salcianu 1.1 Set nodeps = new HashSet(); 263 salcianu 1.1 // We explore the set of possible elements in the set intersection 264 salcianu 1.1 // from the formal rule 2.8; it is safe to look only at the 265 salcianu 1.1 // the new mappings (plus node which is new in 1st iteration) 266 cananian 1.6 for(Object commonO : new_mu.getValues(node)) { 267 cananian 1.6 PANode common = (PANode) commonO; 268 salcianu 1.1 callee_callee_grab_nodep(node, common, nodeps); 269 salcianu 1.1 } 270 salcianu 1.1 callee_callee_grab_nodep(node, node, nodeps); 271 salcianu 1.1 272 cananian 1.6 for(Object node_primeO : nodeps) { 273 cananian 1.6 PANode node_prime = (PANode) node_primeO; 274 salcianu 1.1 match_callee_callee(node, node_prime); 275 salcianu 1.1 match_callee_callee(node_prime, node); 276 salcianu 1.1 } 277 salcianu 1.1 } 278 salcianu 1.1 279 salcianu 1.1 // try to apply 2.8 where the common element of the intersection is 280 salcianu 1.1 private void callee_callee_grab_nodep 281 salcianu 1.1 (PANode node, PANode common, Set nodeps) { 282 salcianu 1.1 // this corresponds to the "\ {n_null}" from the formal rule 283 salcianu 1.1 if(common.type == PANode.NULL) 284 salcianu 1.1 return; 285 salcianu 1.1 nodeps.addAll(rev_mu.getValues(common)); 286 salcianu 1.1 } 287 salcianu 1.1 288 salcianu 1.1 289 salcianu 1.1 // "apply" all possible instantiations of 2.8 for node1 and node3 290 salcianu 1.1 private void match_callee_callee(PANode node1, PANode node3) { 291 salcianu 1.3 if( ! ( (node1 != node3) || 292 salcianu 1.3 ((node1.type == PANode.LOAD) || 293 salcianu 1.3 (node1.type == PANode.LOST)) ) ) 294 salcianu 1.1 return; 295 salcianu 1.1 296 cananian 1.6 for(Object fO : pig_callee.G.O.allFlagsForNode(node1)) { 297 cananian 1.6 String f = (String) fO; 298 salcianu 1.1 Set node2s = pig_callee.G.O.pointedNodes(node1, f); 299 salcianu 1.1 Set node4s = pig_callee.G.I.pointedNodes(node3, f); 300 salcianu 1.1 if(node4s.isEmpty()) continue; 301 salcianu 1.3 302 cananian 1.6 for(Object node2O : node2s) { 303 cananian 1.6 PANode node2 = (PANode) node2O; 304 salcianu 1.1 for(Iterator it4 = node4s.iterator(); it4.hasNext(); ) { 305 salcianu 1.3 306 salcianu 1.3 NEWINFO = false; 307 salcianu 1.3 308 salcianu 1.1 PANode node4 = (PANode) it4.next(); 309 salcianu 1.1 if(node4.type != PANode.PARAM) 310 salcianu 1.1 add_mapping(node2, node4); 311 salcianu 1.3 312 salcianu 1.3 if(NEWINFO && DEBUG) 313 salcianu 1.3 System.out.println 314 salcianu 1.3 ("2.8a for node1=" + node1 + ", node2=" + node2 + 315 salcianu 1.3 ", f=" + f + 316 salcianu 1.3 ", node3=" + node3 + ", node4=" + node4 + "\n"); 317 salcianu 1.3 NEWINFO = false; 318 salcianu 1.3 319 salcianu 1.1 add_mappings(node2, mu.getValues(node4)); 320 salcianu 1.3 321 salcianu 1.3 if(NEWINFO && DEBUG) 322 salcianu 1.3 System.out.println 323 salcianu 1.3 ("2.8b for node1=" + node1 + ", node2=" + node2 + 324 salcianu 1.3 ", f=" + f + 325 salcianu 1.3 ", node3=" + node3 + ", node4=" + node4 + "\n"); 326 salcianu 1.1 } 327 salcianu 1.1 } 328 salcianu 1.1 } 329 salcianu 1.1 } 330 salcianu 1.3 private boolean NEWINFO = false; 331 salcianu 1.4 332 salcianu 1.4 333 salcianu 1.4 334 salcianu 1.4 private static boolean USE_TYPE_INFO = true; 335 salcianu 1.4 static { 336 salcianu 1.4 if(USE_TYPE_INFO) 337 salcianu 1.4 System.out.println("USE TYPE INFO IN INTERPROC MAPPING"); 338 salcianu 1.4 } 339 salcianu 1.4 340 salcianu 1.4 private boolean addMappingAll(Relation mu, PANode node, Set images) { 341 salcianu 1.4 if(!USE_TYPE_INFO) 342 salcianu 1.4 return mu.addAll(node, images); 343 salcianu 1.4 boolean changed = false; 344 salcianu 1.4 for(Iterator it = images.iterator(); it.hasNext(); ) { 345 salcianu 1.4 if(addMapping(mu, node, (PANode) it.next())) 346 salcianu 1.4 changed = true; 347 salcianu 1.4 } 348 salcianu 1.4 return changed; 349 salcianu 1.4 } 350 salcianu 1.4 351 salcianu 1.4 352 salcianu 1.4 private boolean addMapping(Relation mu, PANode node, PANode image) { 353 salcianu 1.4 if(!USE_TYPE_INFO) 354 salcianu 1.4 return mu.add(node, image); 355 salcianu 1.4 if(mu.contains(node, image)) return false; 356 salcianu 1.4 if(compatible(node, image)) 357 salcianu 1.4 return mu.add(node, image); 358 salcianu 1.4 else 359 salcianu 1.4 return false; 360 salcianu 1.4 } 361 salcianu 1.4 362 salcianu 1.4 363 salcianu 1.4 private static class CompatibleQuery { 364 salcianu 1.4 PANode node1; 365 salcianu 1.4 PANode node2; 366 salcianu 1.4 int hash; 367 salcianu 1.4 CompatibleQuery() {} // just to make the compiler happy 368 salcianu 1.4 CompatibleQuery(PANode node1, PANode node2) { 369 salcianu 1.4 init(node1, node2); 370 salcianu 1.4 } 371 salcianu 1.4 private void init(PANode node1, PANode node2) { 372 salcianu 1.4 this.node1 = node1; 373 salcianu 1.4 this.node2 = node2; 374 salcianu 1.4 this.hash = node1.hashCode() ^ node2.hashCode(); 375 salcianu 1.4 } 376 salcianu 1.4 public int hashCode() { return hash; } 377 salcianu 1.4 public boolean equals(Object o) { 378 salcianu 1.4 if(this.hashCode() != o.hashCode()) 379 salcianu 1.4 return false; 380 salcianu 1.4 CompatibleQuery q = (CompatibleQuery) o; 381 salcianu 1.4 return 382 salcianu 1.4 this.node1.equals(q.node1) && 383 salcianu 1.4 this.node2.equals(q.node2); 384 salcianu 1.4 } 385 salcianu 1.4 } 386 salcianu 1.4 private boolean compatible(PANode node1, PANode node2) { 387 salcianu 1.4 compatibleQuery.init(node1, node2); 388 salcianu 1.4 Boolean answer = (Boolean) compatibleCache.get(compatibleQuery); 389 salcianu 1.4 if(answer == null) { 390 salcianu 1.4 boolean banswer = _compatible(node1, node2); 391 salcianu 1.4 answer = new Boolean(banswer); 392 salcianu 1.4 compatibleCache.put(new CompatibleQuery(node1, node2), answer); 393 salcianu 1.5 /* // debug code 394 salcianu 1.4 if(!banswer) 395 salcianu 1.4 System.out.println("INCOMPAT: " + node1 + " , " + node2); 396 salcianu 1.5 */ 397 salcianu 1.4 } 398 salcianu 1.4 return answer.booleanValue(); 399 salcianu 1.4 } 400 salcianu 1.4 private static Hashtable/*<CompatibleQuery,Boolean>*/ compatibleCache = 401 salcianu 1.4 new Hashtable(); 402 salcianu 1.4 private CompatibleQuery compatibleQuery = new CompatibleQuery(); 403 salcianu 1.4 404 salcianu 1.4 private boolean _compatible(PANode node1, PANode node2) { 405 salcianu 1.4 GenType[] gts1 = node1.getPossibleClasses(); 406 salcianu 1.4 GenType[] gts2 = node2.getPossibleClasses(); 407 salcianu 1.4 if((gts1 == null) || (gts2 == null)) 408 salcianu 1.4 return true; 409 salcianu 1.4 else 410 salcianu 1.4 return !disjoint(pa.getAllConcreteClasses(gts1), 411 salcianu 1.4 pa.getAllConcreteClasses(gts2)); 412 salcianu 1.4 } 413 salcianu 1.4 414 salcianu 1.4 private static boolean disjoint(Set set1, Set set2) { 415 salcianu 1.4 if(set1.size() > set2.size()) { 416 salcianu 1.4 Set temp; 417 salcianu 1.4 temp = set1; 418 salcianu 1.4 set1 = set2; 419 salcianu 1.4 set2 = temp; 420 salcianu 1.4 } 421 salcianu 1.4 for(Iterator it = set1.iterator(); it.hasNext(); ) 422 salcianu 1.4 if(set2.contains(it.next())) 423 salcianu 1.4 return false; 424 salcianu 1.4 return true; 425 salcianu 1.4 } 426 salcianu 1.1 }