|
22 | 22 |
|
23 | 23 | import org.eclipse.core.runtime.CoreException;
|
24 | 24 | import org.eclipse.core.runtime.NullProgressMonitor;
|
25 |
| -import org.eclipse.jdt.core.dom.MethodInvocation; |
26 | 25 |
|
27 | 26 | import com.google.common.collect.HashBasedTable;
|
28 | 27 | import com.google.common.collect.Table;
|
@@ -277,118 +276,122 @@ public void start() throws IOException, CoreException, CallGraphBuilderCancelExc
|
277 | 276 | // get the supergraph for the instance result.
|
278 | 277 | ICFGSupergraph supergraph = instanceResult.getSupergraph();
|
279 | 278 |
|
280 |
| - // FIXME This doesn't make a whole lot of sense. Only looking at |
281 |
| - // the node of where the stream was declared: TODO: Can this be |
282 |
| - // somehow rewritten to get blocks corresponding to terminal |
283 |
| - // operations? |
284 |
| - CGNode cgNode = this.getStream().getEnclosingMethodNode(); |
285 |
| - |
286 |
| - for (Iterator<CallSiteReference> callSites = cgNode.iterateCallSites(); callSites.hasNext();) { |
287 |
| - CallSiteReference callSiteReference = callSites.next(); |
288 |
| - MethodReference calledMethod = callSiteReference.getDeclaredTarget(); |
289 |
| - |
290 |
| - // is it a terminal operation? TODO: Should this be |
291 |
| - // cached somehow? Collection of all terminal operation |
292 |
| - // invocations? |
293 |
| - if (isTerminalOperation(calledMethod)) { |
294 |
| - // get the basic block for the call. |
295 |
| - ISSABasicBlock[] blocksForCall = cgNode.getIR().getBasicBlocksForCall(callSiteReference); |
296 |
| - |
297 |
| - assert blocksForCall.length == 1 : "Expecting only a single basic block for the call: " |
298 |
| - + callSiteReference; |
299 |
| - |
300 |
| - for (int i = 0; i < blocksForCall.length; i++) { |
301 |
| - ISSABasicBlock block = blocksForCall[i]; |
302 |
| - |
303 |
| - BasicBlockInContext<IExplodedBasicBlock> blockInContext = getBasicBlockInContextForBlock( |
304 |
| - block, cgNode, supergraph) |
305 |
| - .orElseThrow(() -> new IllegalStateException( |
306 |
| - "No basic block in context for block: " + block)); |
307 |
| - |
308 |
| - if (!terminalBlockToPossibleReceivers.containsKey(blockInContext)) { |
309 |
| - // associate possible receivers with the |
310 |
| - // blockInContext. |
311 |
| - // search through each instruction in the |
312 |
| - // block. |
313 |
| - int processedInstructions = 0; |
314 |
| - for (Iterator<SSAInstruction> it = block.iterator(); it.hasNext();) { |
315 |
| - SSAInstruction instruction = it.next(); |
316 |
| - |
317 |
| - // if it's a phi instruction. |
318 |
| - if (instruction instanceof SSAPhiInstruction) |
319 |
| - // skip it. The pointer analysis |
320 |
| - // below will handle it. |
321 |
| - continue; |
322 |
| - |
323 |
| - // Get the possible receivers. This |
324 |
| - // number corresponds to the value |
325 |
| - // number of the receiver of the method. |
326 |
| - int valueNumberForReceiver = instruction.getUse(0); |
327 |
| - |
328 |
| - // it should be represented by a pointer |
329 |
| - // key. |
330 |
| - PointerKey pointerKey = engine.getHeapGraph().getHeapModel() |
331 |
| - .getPointerKeyForLocal(cgNode, valueNumberForReceiver); |
332 |
| - |
333 |
| - // get the points to set for the |
334 |
| - // receiver. This will give us all |
335 |
| - // object instances that the receiver |
336 |
| - // reference points to. |
337 |
| - OrdinalSet<InstanceKey> pointsToSet = engine.getPointerAnalysis() |
338 |
| - .getPointsToSet(pointerKey); |
339 |
| - assert pointsToSet != null : "The points-to set (I think) should not be null for pointer: " |
340 |
| - + pointerKey; |
341 |
| - |
342 |
| - OrdinalSet<InstanceKey> previousReceivers = terminalBlockToPossibleReceivers |
343 |
| - .put(blockInContext, pointsToSet); |
344 |
| - assert previousReceivers == null : "Reassociating a blockInContext: " |
345 |
| - + blockInContext + " with a new points-to set: " + pointsToSet |
346 |
| - + " that was originally: " + previousReceivers; |
347 |
| - |
348 |
| - ++processedInstructions; |
| 279 | + // TODO: Can this be somehow rewritten to get blocks |
| 280 | + // corresponding to terminal operations? |
| 281 | + // for each call graph node in the call graph. |
| 282 | + for (CGNode cgNode : engine.getCallGraph()) { |
| 283 | + // for each call site in the call graph node. |
| 284 | + for (Iterator<CallSiteReference> callSites = cgNode.iterateCallSites(); callSites.hasNext();) { |
| 285 | + // get the call site reference. |
| 286 | + CallSiteReference callSiteReference = callSites.next(); |
| 287 | + |
| 288 | + // get the (declared) called method at the call site. |
| 289 | + MethodReference calledMethod = callSiteReference.getDeclaredTarget(); |
| 290 | + |
| 291 | + // is it a terminal operation? TODO: Should this be |
| 292 | + // cached somehow? Collection of all terminal operation |
| 293 | + // invocations? |
| 294 | + if (isTerminalOperation(calledMethod)) { |
| 295 | + // get the basic block for the call. |
| 296 | + |
| 297 | + ISSABasicBlock[] blocksForCall = cgNode.getIR().getBasicBlocksForCall(callSiteReference); |
| 298 | + |
| 299 | + assert blocksForCall.length == 1 : "Expecting only a single basic block for the call: " |
| 300 | + + callSiteReference; |
| 301 | + |
| 302 | + for (int i = 0; i < blocksForCall.length; i++) { |
| 303 | + ISSABasicBlock block = blocksForCall[i]; |
| 304 | + |
| 305 | + BasicBlockInContext<IExplodedBasicBlock> blockInContext = getBasicBlockInContextForBlock( |
| 306 | + block, cgNode, supergraph) |
| 307 | + .orElseThrow(() -> new IllegalStateException( |
| 308 | + "No basic block in context for block: " + block)); |
| 309 | + |
| 310 | + if (!terminalBlockToPossibleReceivers.containsKey(blockInContext)) { |
| 311 | + // associate possible receivers with the |
| 312 | + // blockInContext. |
| 313 | + // search through each instruction in the |
| 314 | + // block. |
| 315 | + int processedInstructions = 0; |
| 316 | + for (Iterator<SSAInstruction> it = block.iterator(); it.hasNext();) { |
| 317 | + SSAInstruction instruction = it.next(); |
| 318 | + |
| 319 | + // if it's a phi instruction. |
| 320 | + if (instruction instanceof SSAPhiInstruction) |
| 321 | + // skip it. The pointer analysis |
| 322 | + // below will handle it. |
| 323 | + continue; |
| 324 | + |
| 325 | + // Get the possible receivers. This |
| 326 | + // number corresponds to the value |
| 327 | + // number of the receiver of the method. |
| 328 | + int valueNumberForReceiver = instruction.getUse(0); |
| 329 | + |
| 330 | + // it should be represented by a pointer |
| 331 | + // key. |
| 332 | + PointerKey pointerKey = engine.getHeapGraph().getHeapModel() |
| 333 | + .getPointerKeyForLocal(cgNode, valueNumberForReceiver); |
| 334 | + |
| 335 | + // get the points to set for the |
| 336 | + // receiver. This will give us all |
| 337 | + // object instances that the receiver |
| 338 | + // reference points to. |
| 339 | + OrdinalSet<InstanceKey> pointsToSet = engine.getPointerAnalysis() |
| 340 | + .getPointsToSet(pointerKey); |
| 341 | + assert pointsToSet != null : "The points-to set (I think) should not be null for pointer: " |
| 342 | + + pointerKey; |
| 343 | + |
| 344 | + OrdinalSet<InstanceKey> previousReceivers = terminalBlockToPossibleReceivers |
| 345 | + .put(blockInContext, pointsToSet); |
| 346 | + assert previousReceivers == null : "Reassociating a blockInContext: " |
| 347 | + + blockInContext + " with a new points-to set: " + pointsToSet |
| 348 | + + " that was originally: " + previousReceivers; |
| 349 | + |
| 350 | + ++processedInstructions; |
| 351 | + } |
| 352 | + |
| 353 | + assert processedInstructions == 1 : "Expecting to process one and only one instruction here."; |
349 | 354 | }
|
350 | 355 |
|
351 |
| - assert processedInstructions == 1 : "Expecting to process one and only one instruction here."; |
352 |
| - } |
353 |
| - |
354 |
| - IntSet intSet = instanceResult.getResult().getResult(blockInContext); |
355 |
| - for (IntIterator it = intSet.intIterator(); it.hasNext();) { |
356 |
| - int nextInt = it.next(); |
357 |
| - |
358 |
| - // retrieve the state set for this instance |
359 |
| - // and block. |
360 |
| - Map<TypestateRule, Set<IDFAState>> ruleToStates = instanceBlockStateTable |
361 |
| - .get(instanceKey, blockInContext); |
362 |
| - |
363 |
| - // if it doesn't yet exist. |
364 |
| - if (ruleToStates == null) { |
365 |
| - // allocate a new rule map. |
366 |
| - ruleToStates = new HashMap<>(); |
367 |
| - |
368 |
| - // place it in the table. |
369 |
| - instanceBlockStateTable.put(instanceKey, blockInContext, ruleToStates); |
370 |
| - } |
371 |
| - |
372 |
| - Set<IDFAState> stateSet = ruleToStates.get(rule); |
373 |
| - |
374 |
| - // if it does not yet exist. |
375 |
| - if (stateSet == null) { |
376 |
| - // allocate a new set. |
377 |
| - stateSet = new HashSet<>(); |
378 |
| - |
379 |
| - // place it in the map. |
380 |
| - ruleToStates.put(rule, stateSet); |
381 |
| - } |
382 |
| - |
383 |
| - // get the facts. |
384 |
| - Factoid factoid = instanceResult.getDomain().getMappedObject(nextInt); |
385 |
| - if (factoid != DUMMY_ZERO) { |
386 |
| - BaseFactoid baseFactoid = (BaseFactoid) factoid; |
387 |
| - assert baseFactoid.instance.equals( |
388 |
| - instanceKey) : "Sanity check that the fact instance should be the same as the instance being examined."; |
389 |
| - |
390 |
| - // add the encountered state to the set. |
391 |
| - stateSet.add(baseFactoid.state); |
| 356 | + IntSet intSet = instanceResult.getResult().getResult(blockInContext); |
| 357 | + for (IntIterator it = intSet.intIterator(); it.hasNext();) { |
| 358 | + int nextInt = it.next(); |
| 359 | + |
| 360 | + // retrieve the state set for this instance |
| 361 | + // and block. |
| 362 | + Map<TypestateRule, Set<IDFAState>> ruleToStates = instanceBlockStateTable |
| 363 | + .get(instanceKey, blockInContext); |
| 364 | + |
| 365 | + // if it doesn't yet exist. |
| 366 | + if (ruleToStates == null) { |
| 367 | + // allocate a new rule map. |
| 368 | + ruleToStates = new HashMap<>(); |
| 369 | + |
| 370 | + // place it in the table. |
| 371 | + instanceBlockStateTable.put(instanceKey, blockInContext, ruleToStates); |
| 372 | + } |
| 373 | + |
| 374 | + Set<IDFAState> stateSet = ruleToStates.get(rule); |
| 375 | + |
| 376 | + // if it does not yet exist. |
| 377 | + if (stateSet == null) { |
| 378 | + // allocate a new set. |
| 379 | + stateSet = new HashSet<>(); |
| 380 | + |
| 381 | + // place it in the map. |
| 382 | + ruleToStates.put(rule, stateSet); |
| 383 | + } |
| 384 | + |
| 385 | + // get the facts. |
| 386 | + Factoid factoid = instanceResult.getDomain().getMappedObject(nextInt); |
| 387 | + if (factoid != DUMMY_ZERO) { |
| 388 | + BaseFactoid baseFactoid = (BaseFactoid) factoid; |
| 389 | + assert baseFactoid.instance.equals( |
| 390 | + instanceKey) : "Sanity check that the fact instance should be the same as the instance being examined."; |
| 391 | + |
| 392 | + // add the encountered state to the set. |
| 393 | + stateSet.add(baseFactoid.state); |
| 394 | + } |
392 | 395 | }
|
393 | 396 | }
|
394 | 397 | }
|
|
0 commit comments