if(!startStatements.isEmpty())
{
// Get supporting info and analyses
MHGPostDominatorsFinder pd = new MHGPostDominatorsFinder(new BriefUnitGraph(sm.getActiveBody()));
EqualUsesAnalysis lif = new EqualUsesAnalysis(g);
TransitiveTargets runMethodTargets = new TransitiveTargets( callGraph, new Filter(new RunMethodsPred()) );
// Build a map from start stmt to possible run methods,
// and a map from start stmt to possible allocation nodes,
// and a map from start stmt to guaranteed join stmt
Iterator<Stmt> startIt = startStatements.iterator();
while (startIt.hasNext())
{
Stmt start = startIt.next();
List<SootMethod> runMethodsList = new ArrayList<SootMethod>(); // will be a list of possible run methods called by this start stmt
List<AllocNode> allocNodesList = new ArrayList<AllocNode>(); // will be a list of possible allocation nodes for the thread object that's getting started
// Get possible thread objects (may alias)
Value startObject = ((InstanceInvokeExpr) (start).getInvokeExpr()).getBase();
PointsToSetInternal pts = (PointsToSetInternal) pag.reachingObjects((Local) startObject);
List<AllocNode> mayAlias = getMayAliasList(pts);
if( mayAlias.size() < 1 )
continue; // If the may alias is empty, this must be dead code
// For each possible thread object, get run method
Iterator<MethodOrMethodContext> mayRunIt = runMethodTargets.iterator( start ); // fails for some call graphs
while( mayRunIt.hasNext() )
{
SootMethod runMethod = (SootMethod) mayRunIt.next();
if( runMethod.getSubSignature().equals("void run()") )
{
runMethodsList.add(runMethod);
}
}
// If haven't found any run methods, then use the type of the startObject,
// and add run from it and all subclasses
if(runMethodsList.isEmpty() && ((RefType) startObject.getType()).getSootClass().isApplicationClass())
{
List<SootClass> threadClasses = hierarchy.getSubclassesOfIncluding( ((RefType) startObject.getType()).getSootClass() );
Iterator<SootClass> threadClassesIt = threadClasses.iterator();
while(threadClassesIt.hasNext())
{
SootClass currentClass = threadClassesIt.next();
if( currentClass.declaresMethod("void run()") )
{
runMethodsList.add(currentClass.getMethod("void run()"));
}
}
}
// For each possible thread object, get alloc node
Iterator<AllocNode> mayAliasIt = mayAlias.iterator();
while( mayAliasIt.hasNext() )
{
AllocNode allocNode = mayAliasIt.next();
allocNodesList.add(allocNode);
if(runMethodsList.isEmpty())
{
throw new RuntimeException("Can't find run method for: " + startObject);
/*
if( allocNode.getType() instanceof RefType )
{
List threadClasses = hierarchy.getSubclassesOf(((RefType) allocNode.getType()).getSootClass());
Iterator threadClassesIt = threadClasses.iterator();
while(threadClassesIt.hasNext())
{
SootClass currentClass = (SootClass) threadClassesIt.next();
if( currentClass.declaresMethod("void run()") )
{
runMethodsList.add(currentClass.getMethod("void run()"));
}
}
}
*/
}
}
// Add this start stmt to both maps
startToRunMethods.put(start, runMethodsList);
startToAllocNodes.put(start, allocNodesList);
// does this start stmt match any join stmt???
Iterator<Stmt> joinIt = joinStatements.iterator();
while (joinIt.hasNext())
{
Stmt join = joinIt.next();
Value joinObject = ((InstanceInvokeExpr) (join).getInvokeExpr()).getBase();
// If startObject and joinObject MUST be the same, and if join post-dominates start
List barriers = new ArrayList();
barriers.addAll(g.getSuccsOf(join)); // definitions of the start variable are tracked until they pass a join
if( lif.areEqualUses( start, (Local) startObject, join, (Local) joinObject, barriers) )
{
if((pd.getDominators(start)).contains(join)) // does join post-dominate start?
{
// G.v().out.println("START-JOIN PAIR: " + start + ", " + join);
startToJoin.put(start, join); // then this join always joins this start's thread