Package soot.jimple.toolkits.thread.synchronization

Source Code of soot.jimple.toolkits.thread.synchronization.LockAllocator

package soot.jimple.toolkits.thread.synchronization;

import java.util.*;

import soot.*;
import soot.util.Chain;
import soot.jimple.*;
import soot.jimple.toolkits.pointer.*;
import soot.jimple.toolkits.thread.ThreadLocalObjectsAnalysis;
import soot.jimple.toolkits.thread.mhp.MhpTester;
import soot.jimple.toolkits.thread.mhp.SynchObliviousMhpAnalysis;
import soot.jimple.toolkits.callgraph.*;
import soot.jimple.toolkits.infoflow.*;
import soot.jimple.spark.pag.*;
import soot.jimple.spark.sets.*;
import soot.toolkits.scalar.*;
import soot.toolkits.graph.*;

public class LockAllocator extends SceneTransformer
{
    public LockAllocator(Singletons.Global g){}
    public static LockAllocator v()
  {
    return G.v().soot_jimple_toolkits_thread_synchronization_LockAllocator();
  }
   
    List<CriticalSection> criticalSections = null;
    CriticalSectionInterferenceGraph interferenceGraph = null;
    DirectedGraph deadlockGraph = null;
 
  // Lock options
  boolean optionOneGlobalLock = false;
  boolean optionStaticLocks = false;
  boolean optionUseLocksets = false;
  boolean optionLeaveOriginalLocks = false;
  boolean optionIncludeEmptyPossibleEdges = false;
 
  // Semantic options
  boolean optionAvoidDeadlock = true;
  boolean optionOpenNesting = true
 
  // Analysis options
  boolean optionDoMHP = false;
  boolean optionDoTLO = false;
  boolean optionOnFlyTLO = false; // not a CLI option yet // on-fly is more efficient, but harder to measure in time
 
  // Output options
  boolean optionPrintMhpSummary = true; // not a CLI option yet
  boolean optionPrintGraph = false;
  boolean optionPrintTable = false;
  boolean optionPrintDebug = false;
 
    protected void internalTransform(String phaseName, Map options)
  {
    // Get phase options
    String lockingScheme = PhaseOptions.getString( options, "locking-scheme" );
    if(lockingScheme.equals("fine-grained"))
    {
      optionOneGlobalLock = false;
      optionStaticLocks = false;
      optionUseLocksets = true;
      optionLeaveOriginalLocks = false;
    }
//    if(lockingScheme.equals("fine-static"))
//    {
//      optionOneGlobalLock = false;
//      optionStaticLocks = true;
//      optionUseLocksets = true;
//      optionLeaveOriginalLocks = false;
//    }
    if(lockingScheme.equals("medium-grained")) // rename to coarse-grained
    {
      optionOneGlobalLock = false;
      optionStaticLocks = false;
      optionUseLocksets = false;
      optionLeaveOriginalLocks = false;
    }
    if(lockingScheme.equals("coarse-grained")) // rename to coarse-static
    {
      optionOneGlobalLock = false;
      optionStaticLocks = true;
      optionUseLocksets = false;
      optionLeaveOriginalLocks = false;
    }
    if(lockingScheme.equals("single-static"))
    {
      optionOneGlobalLock = true;
      optionStaticLocks = true;
      optionUseLocksets = false;
      optionLeaveOriginalLocks = false;
    }
    if(lockingScheme.equals("leave-original"))
    {
      optionOneGlobalLock = false;
      optionStaticLocks = false;
      optionUseLocksets = false;
      optionLeaveOriginalLocks = true;
    }
   
    optionAvoidDeadlock = PhaseOptions.getBoolean( options, "avoid-deadlock" );
    optionOpenNesting = PhaseOptions.getBoolean( options, "open-nesting" );

    optionDoMHP = PhaseOptions.getBoolean( options, "do-mhp" );
    optionDoTLO = PhaseOptions.getBoolean( options, "do-tlo" );
//    optionOnFlyTLO = PhaseOptions.getBoolean( options, "on-fly-tlo" ); // not a real option yet

//    optionPrintMhpSummary = PhaseOptions.getBoolean( options, "print-mhp" ); // not a real option yet
    optionPrintGraph = PhaseOptions.getBoolean( options, "print-graph" );
    optionPrintTable = PhaseOptions.getBoolean( options, "print-table" );
    optionPrintDebug = PhaseOptions.getBoolean( options, "print-debug" );
   
//    optionIncludeEmptyPossibleEdges = PhaseOptions.getBoolean( options, "include-empty-edges" ); // not a real option yet
   
    // *** Build May Happen In Parallel Info ***
    MhpTester mhp = null;
    if(optionDoMHP && Scene.v().getPointsToAnalysis() instanceof PAG)
    {
        G.v().out.println("[wjtp.tn] *** Build May-Happen-in-Parallel Info *** " + (new Date()));
      mhp = new SynchObliviousMhpAnalysis();
      if(optionPrintMhpSummary)
      {
        mhp.printMhpSummary();
      }
    }
   


    // *** Find Thread-Local Objects ***
    ThreadLocalObjectsAnalysis tlo = null;
      if(optionDoTLO)
      {
        G.v().out.println("[wjtp.tn] *** Find Thread-Local Objects *** " + (new Date()));
        if(mhp != null)
          tlo = new ThreadLocalObjectsAnalysis(mhp);
      else
          tlo = new ThreadLocalObjectsAnalysis(new SynchObliviousMhpAnalysis());
        if(!optionOnFlyTLO)
        {
          tlo.precompute();
          G.v().out.println("[wjtp.tn] TLO totals (#analyzed/#encountered): " + SmartMethodInfoFlowAnalysis.counter + "/" + ClassInfoFlowAnalysis.methodCount);
        }
        else
          G.v().out.println("[wjtp.tn] TLO so far (#analyzed/#encountered): " + SmartMethodInfoFlowAnalysis.counter + "/" + ClassInfoFlowAnalysis.methodCount);
      }



      // *** Find and Name Transactions ***
      // The transaction finder finds the start, end, and preparatory statements
      // for each transaction. It also calculates the non-transitive read/write
      // sets for each transaction.
      // For all methods, run the intraprocedural analysis (TransactionAnalysis)
    Date start = new Date();
      G.v().out.println("[wjtp.tn] *** Find and Name Transactions *** " + start);
      Map<SootMethod, FlowSet> methodToFlowSet = new HashMap<SootMethod, FlowSet>();
      Map<SootMethod, ExceptionalUnitGraph> methodToExcUnitGraph = new HashMap<SootMethod, ExceptionalUnitGraph>();
      Iterator runAnalysisClassesIt = Scene.v().getApplicationClasses().iterator();
      while (runAnalysisClassesIt.hasNext())
      {
          SootClass appClass = (SootClass) runAnalysisClassesIt.next();
          Iterator methodsIt = appClass.getMethods().iterator();
          while (methodsIt.hasNext())
          {
            SootMethod method = (SootMethod) methodsIt.next();
        if(method.isConcrete())
        {
              Body b = method.retrieveActiveBody();
              ExceptionalUnitGraph eug = new ExceptionalUnitGraph(b);
              methodToExcUnitGraph.put(method, eug);
             
              // run the intraprocedural analysis
            SynchronizedRegionFinder ta = new SynchronizedRegionFinder(eug, b, optionPrintDebug, optionOpenNesting, tlo);
            Chain units = b.getUnits();
            Unit lastUnit = (Unit) units.getLast();
            FlowSet fs = (FlowSet) ta.getFlowBefore(lastUnit);
         
            // add the results to the list of results
            methodToFlowSet.put(method, fs);
        }
          }
      }     
     
      // Create a composite list of all transactions
      criticalSections = new Vector<CriticalSection>();
      for(FlowSet fs : methodToFlowSet.values())
      {
        List fList = fs.toList();
        for(int i = 0; i < fList.size(); i++)
          criticalSections.add(((SynchronizedRegionFlowPair) fList.get(i)).tn);
      }

    // Assign Names To Transactions
    assignNamesToTransactions(criticalSections);

      if(optionOnFlyTLO)
      {
        G.v().out.println("[wjtp.tn] TLO so far (#analyzed/#encountered): " + SmartMethodInfoFlowAnalysis.counter + "/" + ClassInfoFlowAnalysis.methodCount);
      }

     

      // *** Find Transitive Read/Write Sets ***
      // Finds the transitive read/write set for each transaction using a given
      // nesting model.
      G.v().out.println("[wjtp.tn] *** Find Transitive Read/Write Sets *** " + (new Date()));
      PointsToAnalysis pta = Scene.v().getPointsToAnalysis();
      CriticalSectionAwareSideEffectAnalysis tasea = null;
    tasea = new CriticalSectionAwareSideEffectAnalysis(
          pta,
          Scene.v().getCallGraph(), (optionOpenNesting ? criticalSections : null), tlo);
      Iterator<CriticalSection> tnIt = criticalSections.iterator();
      while(tnIt.hasNext())
      {
        CriticalSection tn = tnIt.next();
        for(Unit unit : tn.invokes)
        {
          Stmt stmt = (Stmt) unit;
          HashSet uses = new HashSet();
          RWSet stmtRead = tasea.readSet(tn.method, stmt, tn, uses);
          if(stmtRead != null)
            tn.read.union(stmtRead);
         
          RWSet stmtWrite = tasea.writeSet(tn.method, stmt, tn, uses);
        if(stmtWrite != null)
          tn.write.union(stmtWrite);
      }
      }
      long longTime = ((new Date()).getTime() - start.getTime()) / 100;
      float time = ((float) longTime) / 10.0f;
      if(optionOnFlyTLO)
      {
        G.v().out.println("[wjtp.tn] TLO totals (#analyzed/#encountered): " + SmartMethodInfoFlowAnalysis.counter + "/" + ClassInfoFlowAnalysis.methodCount);
      G.v().out.println("[wjtp.tn] Time for stages utilizing on-fly TLO: " + time + "s");
      }



      // *** Find Stray Reads/Writes *** (DISABLED)
      // add external data races as one-line transactions
      // note that finding them isn't that hard (though it is time consuming)
      // For all methods, run the intraprocedural analysis (transaction finder)
      // Note that these will only be transformed if they are either added to
      // methodToFlowSet or if a loop and new body transformer are used for methodToStrayRWSet
/*      Map methodToStrayRWSet = new HashMap();
      Iterator runRWFinderClassesIt = Scene.v().getApplicationClasses().iterator();
      while (runRWFinderClassesIt.hasNext())
      {
          SootClass appClass = (SootClass) runRWFinderClassesIt.next();
          Iterator methodsIt = appClass.getMethods().iterator();
          while (methodsIt.hasNext())
          {
            SootMethod method = (SootMethod) methodsIt.next();
            Body b = method.retrieveActiveBody();
        UnitGraph g = (UnitGraph) methodToExcUnitGraph.get(method);
           
            // run the interprocedural analysis
//          PTFindStrayRW ptfrw = new PTFindStrayRW(new ExceptionalUnitGraph(b), b, AllTransactions);
          PTFindStrayRW ptfrw = new PTFindStrayRW(g, b, AllTransactions);
          Chain units = b.getUnits();
          Unit firstUnit = (Unit) units.iterator().next();
          FlowSet fs = (FlowSet) ptfrw.getFlowBefore(firstUnit);
         
          // add the results to the list of results
          methodToStrayRWSet.put(method, fs);
          }
      }
//*/     
   


      // *** Calculate Locking Groups ***
      // Search for data dependencies between transactions, and split them into disjoint sets
      G.v().out.println("[wjtp.tn] *** Calculate Locking Groups *** " + (new Date()));
      CriticalSectionInterferenceGraph ig =
        new CriticalSectionInterferenceGraph(
            criticalSections, mhp, optionOneGlobalLock,
            optionLeaveOriginalLocks, optionIncludeEmptyPossibleEdges);
      interferenceGraph = ig; // save in field for later retrieval
     
     
     
    // *** Detect the Possibility of Deadlock ***
    G.v().out.println("[wjtp.tn] *** Detect the Possibility of Deadlock *** " + (new Date()));
    DeadlockDetector dd = new DeadlockDetector(optionPrintDebug, optionAvoidDeadlock, true, criticalSections);
    if(!optionUseLocksets) // deadlock detection for all single-lock-per-region allocations
      deadlockGraph = dd.detectComponentBasedDeadlock();

   

    // *** Calculate Locking Objects ***
      // Get a list of all dependencies for each group
      G.v().out.println("[wjtp.tn] *** Calculate Locking Objects *** " + (new Date()));
    if(!optionStaticLocks)
    {
      // Calculate per-group contributing RWSet
      // (Might be preferable to use per-transaction contributing RWSet)
      for(CriticalSection tn : criticalSections)
        {
          if(tn.setNumber <= 0)
            continue;
          for(CriticalSectionDataDependency tdd : tn.edges)
            tn.group.rwSet.union(tdd.rw);
        }
      }

    // Inspect each group's RW dependencies to determine if there's a possibility
    // of a shared lock object (if all dependencies are fields/localobjs of the same object)
    Map<Value, Integer> lockToLockNum = null;
    List<PointsToSetInternal> lockPTSets = null;
    if(optionLeaveOriginalLocks)
    {
      analyzeExistingLocks(criticalSections, ig);
    }
    else if(optionStaticLocks)
    {
      setFlagsForStaticAllocations(ig);
    }
    else // for locksets and dynamic locks
    {
      setFlagsForDynamicAllocations(ig);

      // Data structures for determining lock numbers
      lockPTSets = new ArrayList<PointsToSetInternal>();
      lockToLockNum = new HashMap<Value, Integer>();

      findLockableReferences(criticalSections, pta, tasea, lockToLockNum,lockPTSets);

      // print out locksets
      if(optionUseLocksets)
      {
        for( CriticalSection tn : criticalSections )
        {
          if( tn.group != null )
          {
            G.v().out.println("[wjtp.tn] " + tn.name + " lockset: " + locksetToLockNumString(tn.lockset, lockToLockNum) + (tn.group.useLocksets ? "" : " (placeholder)"));
          }
        }
      }
    }

   
   
    // *** Detect the Possibility of Deadlock for Locksets ***
    if(optionUseLocksets) // deadlock detection and lock ordering for lockset allocations
    {
      G.v().out.println("[wjtp.tn] *** Detect " + (optionAvoidDeadlock ? "and Correct " : "") + "the Possibility of Deadlock for Locksets *** " + (new Date()));
      deadlockGraph = dd.detectLocksetDeadlock(lockToLockNum, lockPTSets);
      if(optionPrintDebug)
        ((HashMutableEdgeLabelledDirectedGraph) deadlockGraph).printGraph();
   
      G.v().out.println("[wjtp.tn] *** Reorder Locksets to Avoid Deadlock *** " + (new Date()));
      dd.reorderLocksets(lockToLockNum, (HashMutableEdgeLabelledDirectedGraph) deadlockGraph);
    }
   
    // *** Print Output and Transform Program ***
      G.v().out.println("[wjtp.tn] *** Print Output and Transform Program *** " + (new Date()));

    // Print topological graph in graphviz format
    if(optionPrintGraph)
      printGraph(criticalSections, ig, lockToLockNum);

    // Print table of transaction information
    if(optionPrintTable)
    {
      printTable(criticalSections, mhp);
      printGroups(criticalSections, ig);
    }

      // For all methods, run the lock transformer
    if(!optionLeaveOriginalLocks)
    {
        // Create an array of booleans to keep track of which global locks have been inserted into the program
      boolean[] insertedGlobalLock = new boolean[ig.groupCount()];
      insertedGlobalLock[0] = false;
      for(int i = 1; i < ig.groupCount(); i++)
      {
        CriticalSectionGroup tnGroup = ig.groups().get(i);
        insertedGlobalLock[i] = (!optionOneGlobalLock) && (tnGroup.useDynamicLock || tnGroup.useLocksets);
      }
     
      for(SootClass appClass : Scene.v().getApplicationClasses())
      {
            for(SootMethod method : appClass.getMethods())
            {
          if(method.isConcrete())
          {
                FlowSet fs = methodToFlowSet.get(method);
                if(fs != null) // (newly added methods need not be transformed)
                  LockAllocationBodyTransformer.v().internalTransform(method.getActiveBody(), fs, ig.groups(), insertedGlobalLock);
          }
            }
        }
      }
  }
   
  protected void findLockableReferences(List<CriticalSection> AllTransactions,
      PointsToAnalysis pta, CriticalSectionAwareSideEffectAnalysis tasea,
      Map<Value, Integer> lockToLockNum,
      List<PointsToSetInternal> lockPTSets) {
    // For each transaction, if the group's R/Ws may be fields of the same object,
    // then check for the transaction if they must be fields of the same RUNTIME OBJECT
    Iterator<CriticalSection> tnIt9 = AllTransactions.iterator();
    while(tnIt9.hasNext())
    {
      CriticalSection tn = tnIt9.next();
     
      int group = tn.setNumber - 1;
      if(group < 0)
        continue;
         
      if(tn.group.useDynamicLock || tn.group.useLocksets) // if attempting to use a dynamic lock or locksets
      {
       
        // Get list of objects (FieldRef or Local) to be locked (lockset analysis)
        G.v().out.println("[wjtp.tn] * " + tn.name + " *");
        LockableReferenceAnalysis la = new LockableReferenceAnalysis(new BriefUnitGraph(tn.method.retrieveActiveBody()));
        tn.lockset = la.getLocksetOf(tasea, tn.group.rwSet, tn);
       
        // Determine if list is suitable for the selected locking scheme
        // TODO check for nullness
        if(optionUseLocksets)
        {
          // Post-process the locksets
          if(tn.lockset == null || tn.lockset.size() <= 0)
          {
            // If the lockset is invalid, revert the entire group to static locks:
            tn.group.useLocksets = false;
           
            // Create a lockset containing a single placeholder static lock for each tn in the group
            Value newStaticLock = new NewStaticLock(tn.method.getDeclaringClass());
            EquivalentValue newStaticLockEqVal = new EquivalentValue(newStaticLock);
            for(CriticalSection groupTn : tn.group)
            {
              groupTn.lockset = new ArrayList<EquivalentValue>();
              groupTn.lockset.add(newStaticLockEqVal);
            }

            // Assign a lock number to the placeholder
            Integer lockNum = new Integer(-lockPTSets.size()); // negative indicates a static lock
            G.v().out.println("[wjtp.tn] Lock: num " + lockNum + " type " + newStaticLock.getType() + " obj " + newStaticLock);
            lockToLockNum.put(newStaticLockEqVal, lockNum);
            lockToLockNum.put(newStaticLock, lockNum);
            PointsToSetInternal dummyLockPT = new HashPointsToSet(newStaticLock.getType(), (PAG) pta); // KILLS CHA-BASED ANALYSIS (pointer exception)
            lockPTSets.add(dummyLockPT);
          }
          else
          {
            // If the lockset is valid
            // Assign a lock number for each lock in the lockset
            for( EquivalentValue lockEqVal : tn.lockset )
            {
              Value lock = lockEqVal.getValue();
             
              // Get reaching objects for this lock
              PointsToSetInternal lockPT;
              if(lock instanceof Local)
                lockPT = (PointsToSetInternal) pta.reachingObjects((Local) lock);
              else if(lock instanceof StaticFieldRef) // needs special treatment: could be primitive
                lockPT = null;
              else if(lock instanceof InstanceFieldRef)
              {
                Local base = (Local) ((InstanceFieldRef) lock).getBase();
                if(base instanceof FakeJimpleLocal)
                  lockPT = (PointsToSetInternal) pta.reachingObjects(((FakeJimpleLocal)base).getRealLocal(), ((FieldRef) lock).getField());
                else
                  lockPT = (PointsToSetInternal) pta.reachingObjects(base, ((FieldRef) lock).getField());
              }
              else if(lock instanceof NewStaticLock) // placeholder for anything that needs a static lock
                lockPT = null;
              else
                lockPT = null;
               
              if( lockPT != null )
              {
                // Assign an existing lock number if possible
                boolean foundLock = false;
                for(int i = 0; i < lockPTSets.size(); i++)
                {
                  PointsToSetInternal otherLockPT = lockPTSets.get(i);
                  if(lockPT.hasNonEmptyIntersection(otherLockPT)) // will never happen for empty, negative numbered sets
                  {
                    G.v().out.println("[wjtp.tn] Lock: num " + i + " type " + lock.getType() + " obj " + lock);
                    lockToLockNum.put(lock, new Integer(i));
                    otherLockPT.addAll(lockPT, null);
                    foundLock = true;
                    break;
                  }
                }
               
                // Assign a brand new lock number otherwise
                if(!foundLock)
                {
                  G.v().out.println("[wjtp.tn] Lock: num " + lockPTSets.size() + " type " + lock.getType() + " obj " + lock);
                  lockToLockNum.put(lock, new Integer(lockPTSets.size()));
                  PointsToSetInternal otherLockPT = new HashPointsToSet(lockPT.getType(), (PAG) pta);
                  lockPTSets.add(otherLockPT);
                  otherLockPT.addAll(lockPT, null);
                }
              }
              else // static field locks and pathological cases...
              {
                // Assign an existing lock number if possible
                if( lockToLockNum.get(lockEqVal) != null )
                {
                  Integer lockNum = lockToLockNum.get(lockEqVal);
                  G.v().out.println("[wjtp.tn] Lock: num " + lockNum + " type " + lock.getType() + " obj " + lock);
                  lockToLockNum.put(lock, lockNum);
                }
                else
                {
                  Integer lockNum = new Integer(-lockPTSets.size()); // negative indicates a static lock
                  G.v().out.println("[wjtp.tn] Lock: num " + lockNum + " type " + lock.getType() + " obj " + lock);
                  lockToLockNum.put(lockEqVal, lockNum);
                  lockToLockNum.put(lock, lockNum);
                  PointsToSetInternal dummyLockPT = new HashPointsToSet(lock.getType(), (PAG) pta);
                  lockPTSets.add(dummyLockPT);
                }
              }
            }

          }
        }
        else
        {
          if(tn.lockset == null || tn.lockset.size() != 1)
          {// Found too few or too many locks
            // So use a static lock instead
            tn.lockObject = null;
            tn.group.useDynamicLock = false;
            tn.group.lockObject = null;
          }
          else
          {// Found exactly one lock
            // Use it!
            tn.lockObject = (Value) tn.lockset.get(0);
           
            // If it's the best lock we've found in the group yet, use it for display
            if(tn.group.lockObject == null || tn.lockObject instanceof Ref)
              tn.group.lockObject = tn.lockObject;
          }
        }
      }
    }
    if(optionUseLocksets)
    {
      // If any lock has only a singleton reaching object, treat it like a static lock
      for(int i = 0; i < lockPTSets.size(); i++)
      {
        PointsToSetInternal pts = lockPTSets.get(i);
        if(pts.size() == 1 && false) // isSingleton(pts)) // It's NOT easy to find a singleton: single alloc node must be run just once
        {
          for(Object e : lockToLockNum.entrySet())
          {
            Map.Entry entry = (Map.Entry) e;
            Integer value = (Integer) entry.getValue();
            if(value == i)
            {
              entry.setValue(new Integer(-i));
            }
          }
        }
      }
    }
  }
  public void setFlagsForDynamicAllocations(CriticalSectionInterferenceGraph ig) {
    for(int group = 0; group < ig.groupCount() - 1; group++)
    {
      CriticalSectionGroup tnGroup = ig.groups().get(group + 1);

      if(optionUseLocksets)
      {
        tnGroup.useLocksets = true; // initially, guess that this is true
      }
      else
      {
        tnGroup.isDynamicLock = (tnGroup.rwSet.getGlobals().size() == 0);
        tnGroup.useDynamicLock = true;
        tnGroup.lockObject = null;
      }

      // empty groups don't get locks
      if(tnGroup.rwSet.size() <= 0) // There are no edges in this group
      {
        if(optionUseLocksets)
        {
          tnGroup.useLocksets = false;
        }
        else
        {
          tnGroup.isDynamicLock = false;
          tnGroup.useDynamicLock = false;
        }
        continue;
      }
    }
  }
  public void setFlagsForStaticAllocations(CriticalSectionInterferenceGraph ig) {
    // Allocate one new static lock for each group.
    for(int group = 0; group < ig.groupCount() - 1; group++)
    {
      CriticalSectionGroup tnGroup = ig.groups().get(group + 1);
      tnGroup.isDynamicLock = false;
      tnGroup.useDynamicLock = false;
      tnGroup.lockObject = null;
    }
  }

    private void analyzeExistingLocks(List<CriticalSection> AllTransactions,
      CriticalSectionInterferenceGraph ig) {
    setFlagsForStaticAllocations(ig);
   
    // if for any lock there is any def to anything other than a static field, then it's a local lock.     
    // for each transaction, check every def of the lock
    Iterator<CriticalSection> tnAIt = AllTransactions.iterator();
    while(tnAIt.hasNext())
    {
      CriticalSection tn = tnAIt.next();
      if(tn.setNumber <= 0)
        continue;
      ExceptionalUnitGraph egraph = new ExceptionalUnitGraph(tn.method.retrieveActiveBody());
      SmartLocalDefs sld = new SmartLocalDefs(egraph, new SimpleLiveLocals(egraph));
      if(tn.origLock == null || !(tn.origLock instanceof Local)) // || tn.begin == null)
        continue;
      List<Unit> rDefs = sld.getDefsOfAt( (Local) tn.origLock , tn.entermonitor );
      if(rDefs == null)
        continue;
      Iterator<Unit> rDefsIt = rDefs.iterator();
      while (rDefsIt.hasNext())
      {
        Stmt next = (Stmt) rDefsIt.next();
        if(next instanceof DefinitionStmt)
        {
          Value rightOp = ((DefinitionStmt) next).getRightOp();
          if(rightOp instanceof FieldRef)
          {
            if(((FieldRef) rightOp).getField().isStatic())
            {
              // lock may be static
              tn.group.lockObject = rightOp;
            }
            else
            {
              // this lock must be dynamic
              tn.group.isDynamicLock = true;
              tn.group.useDynamicLock = true;
              tn.group.lockObject = tn.origLock;
            }
          }
          else
          {
            // this lock is probably dynamic (but it's hard to tell for sure)
            tn.group.isDynamicLock = true;
            tn.group.useDynamicLock = true;
            tn.group.lockObject = tn.origLock;
          }
        }
        else
        {
          // this lock is probably dynamic (but it's hard to tell for sure)
          tn.group.isDynamicLock = true;
          tn.group.useDynamicLock = true;
          tn.group.lockObject = tn.origLock;
        }
      }
    }
  }
   
  public static String locksetToLockNumString(List<EquivalentValue> lockset, Map<Value, Integer> lockToLockNum)
  {
    if( lockset == null ) return "null";
    String ret = "[";
    boolean first = true;
    for( EquivalentValue lockEqVal : lockset )
    {
      if(!first)
        ret = ret + " ";
      first = false;
      ret = ret + lockToLockNum.get(lockEqVal.getValue());
    }
    return ret + "]";
  }
   
    public void assignNamesToTransactions(List<CriticalSection> AllTransactions)
    {
         // Give each method a unique, deterministic identifier
         // Sort transactions into bins... one for each method name
        
         // Get list of method names
      List<String> methodNamesTemp = new ArrayList<String>();
      Iterator<CriticalSection> tnIt5 = AllTransactions.iterator();
      while (tnIt5.hasNext())
      {
          CriticalSection tn1 = tnIt5.next();
          String mname = tn1.method.getSignature(); //tn1.method.getSignature() + "." + tn1.method.getName();
          if(!methodNamesTemp.contains(mname))
            methodNamesTemp.add(mname);
    }
    String methodNames[] = new String[1];
    methodNames = methodNamesTemp.toArray(methodNames);
    Arrays.sort(methodNames);

    // Initialize method-named bins
    // this matrix is <# method names> wide and <max txns possible in one method> + 1 tall
    int identMatrix[][] = new int[methodNames.length][CriticalSection.nextIDNum - methodNames.length + 2];
    for(int i = 0; i < methodNames.length; i++)
    {
      identMatrix[i][0] = 0;
      for(int j = 1; j < CriticalSection.nextIDNum - methodNames.length + 1; j++)
      {
        identMatrix[i][j] = 50000;
      }
    }
   
    // Put transactions into bins
      Iterator<CriticalSection> tnIt0 = AllTransactions.iterator();
      while(tnIt0.hasNext())
      {
        CriticalSection tn1 = tnIt0.next();
      int methodNum = Arrays.binarySearch(methodNames, tn1.method.getSignature());
      identMatrix[methodNum][0]++;
      identMatrix[methodNum][identMatrix[methodNum][0]] = tn1.IDNum;
      }
     
      // Sort bins by transaction IDNum
      // IDNums vary, but always increase in code-order within a method
      for(int j = 0; j < methodNames.length; j++)
      {
        identMatrix[j][0] = 0; // set the counter to 0 so it sorts out (into slot 0).
        Arrays.sort(identMatrix[j]); // sort this subarray
    }
   
    // Generate a name based on the bin number and location within the bin
      Iterator<CriticalSection> tnIt4 = AllTransactions.iterator();
      while(tnIt4.hasNext())
      {
        CriticalSection tn1 = tnIt4.next();
      int methodNum = Arrays.binarySearch(methodNames, tn1.method.getSignature());
      int tnNum = Arrays.binarySearch(identMatrix[methodNum], tn1.IDNum) - 1;
        tn1.name = "m" + (methodNum < 10? "00" : (methodNum < 100? "0" : "")) + methodNum + "n" + (tnNum < 10? "0" : "") + tnNum;
      }
  } 

  public void printGraph(Collection<CriticalSection> AllTransactions, CriticalSectionInterferenceGraph ig, Map<Value, Integer> lockToLockNum)
  {
    final String[] colors = {"black", "blue", "blueviolet", "chartreuse", "crimson", "darkgoldenrod1", "darkseagreen", "darkslategray", "deeppink",
      "deepskyblue1", "firebrick1", "forestgreen", "gold", "gray80", "navy", "pink", "red", "sienna", "turquoise1", "yellow"};
    Map<Integer, String> lockColors = new HashMap<Integer, String>();
    int colorNum = 0;
    HashSet<CriticalSection> visited = new HashSet<CriticalSection>();
   
    G.v().out.println("[transaction-graph]" + (optionUseLocksets ? "" : " strict") + " graph transactions {"); // "\n[transaction-graph] start=1;");

    for(int group = 0; group < ig.groups().size(); group++)
    {
      boolean printedHeading = false;
      Iterator<CriticalSection> tnIt = AllTransactions.iterator();
      while(tnIt.hasNext())
      {
        CriticalSection tn = tnIt.next();
        if(tn.setNumber == group + 1)
        {
          if(!printedHeading)
          {
//            if(localLock[group] && lockObject[group] != null)
            if(tn.group.useDynamicLock && tn.group.lockObject != null)
            {
              String typeString = "";
//              if(lockObject[group].getType() instanceof RefType)
//                typeString = ((RefType) lockObject[group].getType()).getSootClass().getShortName();
//              else
//                typeString = lockObject[group].getType().toString();
              if(tn.group.lockObject.getType() instanceof RefType)
                typeString = ((RefType) tn.group.lockObject.getType()).getSootClass().getShortName();
              else
                typeString = tn.group.lockObject.getType().toString();
              G.v().out.println("[transaction-graph] subgraph cluster_" + (group + 1) + " {\n[transaction-graph] color=blue;\n[transaction-graph] label=\"Lock: a \\n" + typeString + " object\";");
            }
            else if(tn.group.useLocksets)
            {
              G.v().out.println("[transaction-graph] subgraph cluster_" + (group + 1) + " {\n[transaction-graph] color=blue;\n[transaction-graph] label=\"Locksets\";");
            }
            else
            {
              String objString = "";
//              if(lockObject[group] == null)
              if(tn.group.lockObject == null)
              {
                objString = "lockObj" + (group + 1);
              }
//              else if(lockObject[group] instanceof FieldRef)
              else if(tn.group.lockObject instanceof FieldRef)
              {
//                SootField field = ((FieldRef) lockObject[group]).getField();
                SootField field = ((FieldRef) tn.group.lockObject).getField();
                objString = field.getDeclaringClass().getShortName() + "." + field.getName();
              }
              else
                objString = tn.group.lockObject.toString();
//                objString = lockObject[group].toString();
              G.v().out.println("[transaction-graph] subgraph cluster_" + (group + 1) + " {\n[transaction-graph] color=blue;\n[transaction-graph] label=\"Lock: \\n" + objString + "\";");
            }
            printedHeading = true;
          }
          if(Scene.v().getReachableMethods().contains(tn.method))
            G.v().out.println("[transaction-graph] " + tn.name + " [name=\"" + tn.method.toString() + "\" style=\"setlinewidth(3)\"];");
          else
            G.v().out.println("[transaction-graph] " + tn.name + " [name=\"" + tn.method.toString() + "\" color=cadetblue1 style=\"setlinewidth(1)\"];");

          if(tn.group.useLocksets) // print locks instead of dependence edges
          {
            for(EquivalentValue lockEqVal : tn.lockset)
            {
              Integer lockNum = lockToLockNum.get(lockEqVal.getValue());
              for(CriticalSection tn2 : tn.group)
              {
                if(!visited.contains(tn2) && ig.mayHappenInParallel(tn, tn2))
                {
                  for(EquivalentValue lock2EqVal : tn2.lockset)
                  {
                    Integer lock2Num = lockToLockNum.get(lock2EqVal.getValue());
                    if(lockNum.intValue() == lock2Num.intValue())
                    {
                      // Get the color for this lock
                      if(!lockColors.containsKey(lockNum))
                      {
                        lockColors.put(lockNum, colors[colorNum % colors.length]);
                        colorNum++;
                      }
                      String color = lockColors.get(lockNum);

                      // Draw an edge for this lock
                      G.v().out.println("[transaction-graph] " + tn.name + " -- " + tn2.name + " [color=" + color + " style=" + (lockNum >= 0 ? "dashed" : "solid") + " exactsize=1 style=\"setlinewidth(3)\"];");
                    }
                  }
                }
              }
              visited.add(tn);
            }
          }
          else
          {
            Iterator<CriticalSectionDataDependency> tnedgeit = tn.edges.iterator();
            while(tnedgeit.hasNext())
            {
              CriticalSectionDataDependency edge = tnedgeit.next();
              CriticalSection tnedge = edge.other;
              if(tnedge.setNumber == group + 1)
                G.v().out.println("[transaction-graph] " + tn.name + " -- " + tnedge.name + " [color=" + (edge.size > 0 ? "black" : "cadetblue1") + " style=" + (tn.setNumber > 0 && tn.group.useDynamicLock ? "dashed" : "solid") + " exactsize=" + edge.size + " style=\"setlinewidth(3)\"];");
            }
          }
        }
       
      }
      if(printedHeading)
        G.v().out.println("[transaction-graph] }");
    }
   
    // Print nodes with no group
    {
      boolean printedHeading = false;
      Iterator<CriticalSection> tnIt = AllTransactions.iterator();
      while(tnIt.hasNext())
      {
        CriticalSection tn = tnIt.next();
        if(tn.setNumber == -1)
        {
          if(!printedHeading)
          {
            // putting these nodes in a "source" ranked subgraph makes them appear above all the clusters
            G.v().out.println("[transaction-graph] subgraph lone {\n[transaction-graph] rank=source;");
            printedHeading = true;
          }
          if(Scene.v().getReachableMethods().contains(tn.method))
            G.v().out.println("[transaction-graph] " + tn.name + " [name=\"" + tn.method.toString() + "\" style=\"setlinewidth(3)\"];");
          else
            G.v().out.println("[transaction-graph] " + tn.name + " [name=\"" + tn.method.toString() + "\" color=cadetblue1 style=\"setlinewidth(1)\"];");

          Iterator<CriticalSectionDataDependency> tnedgeit = tn.edges.iterator();
          while(tnedgeit.hasNext())
          {
            CriticalSectionDataDependency edge = tnedgeit.next();
            CriticalSection tnedge = edge.other;
            if(tnedge.setNumber != tn.setNumber || tnedge.setNumber == -1)
              G.v().out.println("[transaction-graph] " + tn.name + " -- " + tnedge.name + " [color=" + (edge.size > 0 ? "black" : "cadetblue1") + " style=" + (tn.setNumber > 0 && tn.group.useDynamicLock ? "dashed" : "solid") + " exactsize=" + edge.size + " style=\"setlinewidth(1)\"];");
          }
        }
      }
      if(printedHeading)
        G.v().out.println("[transaction-graph] }");
    }

    G.v().out.println("[transaction-graph] }");
 

  public void printTable(Collection<CriticalSection> AllTransactions, MhpTester mhp)
  {
    G.v().out.println("[transaction-table] ");
    Iterator<CriticalSection> tnIt7 = AllTransactions.iterator();
    while(tnIt7.hasNext())
    {
      CriticalSection tn = tnIt7.next();
     
      // Figure out if it's reachable, and if it MHP itself
      boolean reachable = false;
      boolean mhpself = false;
      {
          ReachableMethods rm = Scene.v().getReachableMethods();
          reachable = rm.contains(tn.method);
          if(mhp != null)
            mhpself = mhp.mayHappenInParallel(tn.method, tn.method);
        }
      G.v().out.println("[transaction-table] Transaction " + tn.name + (reachable ? " reachable" : " dead") + (mhpself ? " [called from >= 2 threads]" : " [called from <= 1 thread]"));
      G.v().out.println("[transaction-table] Where: " + tn.method.getDeclaringClass().toString() + ":" + tn.method.toString() + ":  ");
      G.v().out.println("[transaction-table] Orig : " + tn.origLock);
      G.v().out.println("[transaction-table] Prep : " + tn.prepStmt);
      G.v().out.println("[transaction-table] Begin: " + tn.entermonitor);
      G.v().out.print("[transaction-table] End  : early:" + tn.earlyEnds.toString() + " exc:" + tn.exceptionalEnd + " through:" + tn.end + " \n");
      G.v().out.println("[transaction-table] Size : " + tn.units.size());
      if(tn.read.size() < 100)
        G.v().out.print("[transaction-table] Read : " + tn.read.size() + "\n[transaction-table] " +
          tn.read.toString().replaceAll("\\[", "     : [").replaceAll("\n", "\n[transaction-table] "));
      else
        G.v().out.print("[transaction-table] Read : " + tn.read.size() + "  \n[transaction-table] ");
      if(tn.write.size() < 100)
        G.v().out.print("Write: " + tn.write.size() + "\n[transaction-table] " +
          tn.write.toString().replaceAll("\\[", "     : [").replaceAll("\n", "\n[transaction-table] ")); // label provided by previous print statement
      else
        G.v().out.print("Write: " + tn.write.size() + "\n[transaction-table] "); // label provided by previous print statement
      G.v().out.print("Edges: (" + tn.edges.size() + ") "); // label provided by previous print statement
      Iterator<CriticalSectionDataDependency> tnedgeit = tn.edges.iterator();
      while(tnedgeit.hasNext())
        G.v().out.print(tnedgeit.next().other.name + " ");
      if(tn.group != null && tn.group.useLocksets)
      {
        G.v().out.println("\n[transaction-table] Locks: " + tn.lockset);
       
      }
      else
        G.v().out.println("\n[transaction-table] Lock : " + (tn.setNumber == -1 ? "-" : (tn.lockObject == null ? "Global" : (tn.lockObject.toString() + (tn.lockObjectArrayIndex == null ? "" : "[" + tn.lockObjectArrayIndex + "]")) )));
      G.v().out.println("[transaction-table] Group: " + tn.setNumber + "\n[transaction-table] ");
    }
  }
 
  public void printGroups(Collection<CriticalSection> AllTransactions, CriticalSectionInterferenceGraph ig)
  {
      G.v().out.print("[transaction-groups] Group Summaries\n[transaction-groups] ");
      for(int group = 0; group < ig.groupCount() - 1; group++)
        {
          CriticalSectionGroup tnGroup = ig.groups().get(group + 1);
          if(tnGroup.size() > 0)
          {
            G.v().out.print("Group " + (group + 1) + " ");
          G.v().out.print("Locking: " + (tnGroup.useLocksets ? "using " : (tnGroup.isDynamicLock && tnGroup.useDynamicLock ? "Dynamic on " : "Static on ")) + (tnGroup.useLocksets ? "locksets" : (tnGroup.lockObject == null ? "null" : tnGroup.lockObject.toString())) );
          G.v().out.print("\n[transaction-groups]      : ");
          Iterator<CriticalSection> tnIt = AllTransactions.iterator();
          while(tnIt.hasNext())
          {
            CriticalSection tn = tnIt.next();
            if(tn.setNumber == group + 1)
              G.v().out.print(tn.name + " ");
          }
          G.v().out.print("\n[transaction-groups] " +
                    tnGroup.rwSet.toString().replaceAll("\\[", "     : [").replaceAll("\n", "\n[transaction-groups] "));
          }
        }
      G.v().out.print("Erasing \n[transaction-groups]      : ");
      Iterator<CriticalSection> tnIt = AllTransactions.iterator();
      while(tnIt.hasNext())
      {
        CriticalSection tn = tnIt.next();
        if(tn.setNumber == -1)
          G.v().out.print(tn.name + " ");
      }
      G.v().out.println("\n[transaction-groups] ");
  }
  public CriticalSectionInterferenceGraph getInterferenceGraph() {
    return interferenceGraph;
  }
  public DirectedGraph getDeadlockGraph() {
    return deadlockGraph;
  }
  public List<CriticalSection> getCriticalSections() {
    return criticalSections;
  }
}
TOP

Related Classes of soot.jimple.toolkits.thread.synchronization.LockAllocator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.