going to start with just enough definite reach analysis to do a simple example
[IRC.git] / Robust / src / Analysis / Disjoint / DisjointAnalysis.java
index 4e851640f73ebd65bec6c66705e954d3cf0a8ec0..00f0735f648b9a0d5e476f1046fd7b5fe0c0b639 100644 (file)
@@ -412,6 +412,9 @@ public class DisjointAnalysis implements HeapAnalysis {
   protected EffectsAnalysis effectsAnalysis;
   protected BuildStateMachines buildStateMachines;
 
+  protected boolean doDefiniteReachAnalysis = false;
+  protected DefiniteReachAnalysis definiteReachAnalysis;
+
 
   // data structure for public interface
   private Hashtable< Descriptor, HashSet<AllocSite> >
@@ -521,6 +524,17 @@ public class DisjointAnalysis implements HeapAnalysis {
   protected Hashtable<Descriptor, ReachGraph>
   mapDescriptorToInitialContext;
 
+  // mapping of current partial results for a given node.  Note that
+  // to reanalyze a method we discard all partial results because a
+  // null reach graph indicates the node needs to be visited on the
+  // way to the fixed point.
+  // The reason for a persistent mapping is so after the analysis we
+  // can ask for the graph of any node at the fixed point, but this
+  // option is only enabled with a compiler flag.
+  protected Hashtable<FlatNode, ReachGraph> mapFlatNodeToReachGraphPersist;
+  protected Hashtable<FlatNode, ReachGraph> mapFlatNodeToReachGraph;
+
+
   // make the result for back edges analysis-wide STRICTLY
   // MONOTONIC as well, but notice we use FlatNode as the
   // key for this map: in case we want to consider other
@@ -673,6 +687,9 @@ public class DisjointAnalysis implements HeapAnalysis {
     mapDescriptorToInitialContext =
       new Hashtable<Descriptor, ReachGraph>();
 
+    mapFlatNodeToReachGraphPersist =
+      new Hashtable<FlatNode, ReachGraph>();
+
     mapBackEdgeToMonotone =
       new Hashtable<FlatNode, ReachGraph>();
 
@@ -832,6 +849,10 @@ public class DisjointAnalysis implements HeapAnalysis {
     ReachGraph.debugCallSiteVisitCounter
       = 0; // count visits from 1, is incremented before first visit    
 
+    if( state.DO_DEFINITE_REACH_ANALYSIS ) {
+      doDefiniteReachAnalysis = true;
+      definiteReachAnalysis = new DefiniteReachAnalysis();
+    }
 
 
     if( suppressOutput ) {
@@ -877,14 +898,18 @@ public class DisjointAnalysis implements HeapAnalysis {
         writeFinalGraphs();
       }
 
-      if( state.DISJOINTWRITEIHMS && !suppressOutput ) {
+      if( state.DISJOINTWRITEIHMS ) {
         writeFinalIHMs();
       }
 
-      if( state.DISJOINTWRITEINITCONTEXTS && !suppressOutput ) {
+      if( state.DISJOINTWRITEINITCONTEXTS ) {
         writeInitialContexts();
       }
 
+      if( state.DISJOINT_WRITE_ALL_NODE_FINAL_GRAPHS ) {
+        writeFinalGraphsForEveryNode();
+      }
+
       if( state.DISJOINTALIASFILE != null && !suppressOutput ) {
         if( state.TASK ) {
           writeAllSharing(state.DISJOINTALIASFILE, treport, justtime, state.DISJOINTALIASTAB, state.lines);
@@ -1111,8 +1136,8 @@ public class DisjointAnalysis implements HeapAnalysis {
       flatNodesToVisitQ.add(fm);
     }
 
-    // mapping of current partial results
-    Hashtable<FlatNode, ReachGraph> mapFlatNodeToReachGraph =
+    // start a new mapping of partial results
+    mapFlatNodeToReachGraph =
       new Hashtable<FlatNode, ReachGraph>();
 
     // the set of return nodes partial results that will be combined as
@@ -1197,6 +1222,12 @@ public class DisjointAnalysis implements HeapAnalysis {
       if( !rg.equals(rgPrev) ) {
         mapFlatNodeToReachGraph.put(fn, rg);
 
+        // we don't necessarily want to keep the reach graph for every
+        // node in the program unless a client or the user wants it
+        if( state.DISJOINT_WRITE_ALL_NODE_FINAL_GRAPHS ) {
+          mapFlatNodeToReachGraphPersist.put(fn, rg);
+        }
+
         for( int i = 0; i < pm.numNext(fn); i++ ) {
           FlatNode nn = pm.getNext(fn, i);
 
@@ -1214,6 +1245,10 @@ public class DisjointAnalysis implements HeapAnalysis {
     // states after the flat method returns
     ReachGraph completeGraph = new ReachGraph();
 
+    if( setReturns.isEmpty() ) {
+      System.out.println( "d = "+d );
+      
+    }
     assert !setReturns.isEmpty();
     Iterator retItr = setReturns.iterator();
     while( retItr.hasNext() ) {
@@ -1267,6 +1302,8 @@ public class DisjointAnalysis implements HeapAnalysis {
     FlatSESEEnterNode sese;
     FlatSESEExitNode fsexn;
 
+    Set<EdgeKey> edgeKeysRemoved;
+
     //Stores the flatnode's reach graph at enter
     ReachGraph rgOnEnter = new ReachGraph();
     rgOnEnter.merge(rg);
@@ -1286,15 +1323,23 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       rg.writeGraph("genReach"+fgrn.getGraphName(),
                     true,     // write labels (variables)
-                    false, //true,    // selectively hide intermediate temp vars
+                    true,    // selectively hide intermediate temp vars
                     true,     // prune unreachable heap regions
-                    true,    // hide reachability altogether
+                    false,    // hide reachability altogether
                     true,    // hide subset reachability states
                     true,     // hide predicates
                     true); //false);    // hide edge taints
     } break;
 
 
+    case FKind.FlatGenDefReachNode: {
+      FlatGenDefReachNode fgdrn = (FlatGenDefReachNode) fn;
+      if( doDefiniteReachAnalysis ) {
+        definiteReachAnalysis.writeState( fn, fgdrn.getOutputName() );
+      }
+    } break;
+
+
     case FKind.FlatMethod: {
       // construct this method's initial heap model (IHM)
       // since we're working on the FlatMethod, we know
@@ -1325,6 +1370,14 @@ public class DisjointAnalysis implements HeapAnalysis {
       rg.merge(rgPrevContext);
       mapDescriptorToInitialContext.put(d, rg);
 
+      if( doDefiniteReachAnalysis ) {
+        FlatMethod fm = (FlatMethod) fn;
+        Set<TempDescriptor> params = new HashSet<TempDescriptor>();
+        for( int i = 0; i < fm.numParameters(); ++i ) {
+          params.add( fm.getParameter( i ) );
+        }
+        definiteReachAnalysis.methodEntry( fn, params );
+      }
     } break;
 
     case FKind.FlatOpNode:
@@ -1337,7 +1390,6 @@ public class DisjointAnalysis implements HeapAnalysis {
         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
           if(rblockRel.isPotentialStallSite(fn)) {
             // x gets status of y
-//            if(!rg.isAccessible(rhs)){
             if(!accessible.isAccessible(fn, rhs)) {
               rg.makeInaccessible(lhs);
             }
@@ -1346,6 +1398,10 @@ public class DisjointAnalysis implements HeapAnalysis {
 
         // transfer func
         rg.assignTempXEqualToTempY(lhs, rhs);
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.copy( fn, lhs, rhs );
+        }
       }
       break;
 
@@ -1361,7 +1417,6 @@ public class DisjointAnalysis implements HeapAnalysis {
       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
         if(rblockRel.isPotentialStallSite(fn)) {
           // x gets status of y
-//          if(!rg.isAccessible(rhs)){
           if(!accessible.isAccessible(fn,rhs)) {
             rg.makeInaccessible(lhs);
           }
@@ -1370,6 +1425,10 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       // transfer func
       rg.assignTempXEqualToCastedTempY(lhs, rhs, td);
+
+      if( doDefiniteReachAnalysis ) {
+        definiteReachAnalysis.copy( fn, lhs, rhs );
+      }
       break;
 
     case FKind.FlatFieldNode:
@@ -1386,7 +1445,6 @@ public class DisjointAnalysis implements HeapAnalysis {
         if(rblockRel.isPotentialStallSite(fn)) {
           // x=y.f, stall y if not accessible
           // contributes read effects on stall site of y
-//          if(!rg.isAccessible(rhs)) {
           if(!accessible.isAccessible(fn,rhs)) {
             rg.taintStallSite(fn, rhs);
           }
@@ -1400,6 +1458,10 @@ public class DisjointAnalysis implements HeapAnalysis {
       if( shouldAnalysisTrack(fld.getType() ) ) {
         // transfer func
         rg.assignTempXEqualToTempYFieldF(lhs, rhs, fld, fn);
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.load( fn, lhs, rhs, fld );
+        }
       }
 
       // after transfer, use updated graph to
@@ -1418,6 +1480,11 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       boolean strongUpdate = false;
 
+      edgeKeysRemoved = null;
+      if( doDefiniteReachAnalysis ) {
+        edgeKeysRemoved = new HashSet<EdgeKey>();
+      }
+
       // before transfer func, possibly inject
       // stall-site taints
       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
@@ -1425,12 +1492,10 @@ public class DisjointAnalysis implements HeapAnalysis {
         if(rblockRel.isPotentialStallSite(fn)) {
           // x.y=f , stall x and y if they are not accessible
           // also contribute write effects on stall site of x
-//          if(!rg.isAccessible(lhs)) {
           if(!accessible.isAccessible(fn,lhs)) {
             rg.taintStallSite(fn, lhs);
           }
 
-//          if(!rg.isAccessible(rhs)) {
           if(!accessible.isAccessible(fn,rhs)) {
             rg.taintStallSite(fn, rhs);
           }
@@ -1443,7 +1508,11 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       if( shouldAnalysisTrack(fld.getType() ) ) {
         // transfer func
-        strongUpdate = rg.assignTempXFieldFEqualToTempY(lhs, fld, rhs, fn);
+        strongUpdate = rg.assignTempXFieldFEqualToTempY(lhs, fld, rhs, fn, edgeKeysRemoved);
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.store( fn, lhs, fld, rhs, edgeKeysRemoved );
+        }
       }
 
       // use transformed graph to do effects analysis
@@ -1471,7 +1540,6 @@ public class DisjointAnalysis implements HeapAnalysis {
           // x=y.f, stall y if not accessible
           // contributes read effects on stall site of y
           // after this, x and y are accessbile.
-//          if(!rg.isAccessible(rhs)) {
           if(!accessible.isAccessible(fn,rhs)) {
             rg.taintStallSite(fn, rhs);
           }
@@ -1484,6 +1552,10 @@ public class DisjointAnalysis implements HeapAnalysis {
       if( shouldAnalysisTrack(lhs.getType() ) ) {
         // transfer func
         rg.assignTempXEqualToTempYFieldF(lhs, rhs, fdElement, fn);
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.load( fn, lhs, rhs, fdElement );
+        }
       }
 
       // use transformed graph to do effects analysis
@@ -1497,13 +1569,18 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       lhs = fsen.getDst();
       rhs = fsen.getSrc();
-
+      
       assert lhs.getType() != null;
       assert lhs.getType().isArray();
 
       tdElement = lhs.getType().dereference();
       fdElement = getArrayField(tdElement);
 
+      edgeKeysRemoved = null;
+      if( doDefiniteReachAnalysis ) {
+        edgeKeysRemoved = new HashSet<EdgeKey>();
+      }
+
       // before transfer func, possibly inject
       // stall-site taints
       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
@@ -1511,12 +1588,10 @@ public class DisjointAnalysis implements HeapAnalysis {
         if(rblockRel.isPotentialStallSite(fn)) {
           // x.y=f , stall x and y if they are not accessible
           // also contribute write effects on stall site of x
-//          if(!rg.isAccessible(lhs)) {
           if(!accessible.isAccessible(fn,lhs)) {
             rg.taintStallSite(fn, lhs);
           }
 
-//          if(!rg.isAccessible(rhs)) {
           if(!accessible.isAccessible(fn,rhs)) {
             rg.taintStallSite(fn, rhs);
           }
@@ -1531,7 +1606,11 @@ public class DisjointAnalysis implements HeapAnalysis {
         // transfer func, BUT
         // skip this node if it cannot create new reachability paths
         if( !arrayReferencees.doesNotCreateNewReaching(fsen) ) {
-          rg.assignTempXFieldFEqualToTempY(lhs, fdElement, rhs, fn);
+          rg.assignTempXFieldFEqualToTempY(lhs, fdElement, rhs, fn, edgeKeysRemoved);
+        }
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.store( fn, lhs, fdElement, rhs, edgeKeysRemoved );
         }
       }
 
@@ -1558,6 +1637,10 @@ public class DisjointAnalysis implements HeapAnalysis {
 
         // transfer func
         rg.assignTempEqualToNewAlloc(lhs, as);
+
+        if( doDefiniteReachAnalysis ) {
+          definiteReachAnalysis.newObject( fn, lhs );
+        }
       }
       break;
 
@@ -1623,6 +1706,10 @@ public class DisjointAnalysis implements HeapAnalysis {
       FlatMethod fmCallee = state.getMethodFlat(mdCallee);
 
 
+      if( doDefiniteReachAnalysis ) {
+        definiteReachAnalysis.methodCall( fn, fc.getReturnTemp() );
+      }
+
       
       // the transformation for a call site should update the
       // current heap abstraction with any effects from the callee,
@@ -1680,6 +1767,7 @@ public class DisjointAnalysis implements HeapAnalysis {
         Set<Integer> callerNodeIDsCopiedToCallee =
           new HashSet<Integer>();
 
+
         ReachGraph heapForThisCall_cur =
           rg.makeCalleeView(fc,
                             fmPossible,
@@ -1687,6 +1775,7 @@ public class DisjointAnalysis implements HeapAnalysis {
                             dcsd.writeDebugDOTs
                             );
 
+
         // enforce that a call site contribution can only
         // monotonically increase
         heapForThisCall_cur.merge(heapForThisCall_old);
@@ -1701,7 +1790,7 @@ public class DisjointAnalysis implements HeapAnalysis {
           fc2enclosing.put(fc, mdCaller);
 
           if( state.DISJOINTDEBUGSCHEDULING ) {
-            System.out.println("  context changed, scheduling callee: "+mdPossible);
+            System.out.println("  context changed at callsite: "+fc+", scheduling callee: "+mdPossible);
           }
 
           if( state.DISJOINTDVISITSTACKEESONTOP ) {
@@ -1759,9 +1848,11 @@ public class DisjointAnalysis implements HeapAnalysis {
       }
       
 
+
       statusDebugCallSite( dcsd );
 
 
+
       // now that we've taken care of building heap models for
       // callee analysis, finish this transformation
       rg = rgMergeOfPossibleCallers;
@@ -1790,7 +1881,6 @@ public class DisjointAnalysis implements HeapAnalysis {
 
       // before transfer, do effects analysis support
       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
-//        if(!rg.isAccessible(rhs)){
         if(!accessible.isAccessible(fn,rhs)) {
           rg.makeInaccessible(ReachGraph.tdReturn);
         }
@@ -1827,6 +1917,7 @@ public class DisjointAnalysis implements HeapAnalysis {
     fn2rgAtExit.put(fn, rgOnExit);
 
 
+
     // at this point rg should be the correct update
     // by an above transfer function, or untouched if
     // the flat node type doesn't affect the heap
@@ -1930,6 +2021,25 @@ public class DisjointAnalysis implements HeapAnalysis {
     }
   }
 
+  private void writeFinalGraphsForEveryNode() {
+    Set entrySet = mapFlatNodeToReachGraphPersist.entrySet();
+    Iterator itr = entrySet.iterator();
+    while( itr.hasNext() ) {
+      Map.Entry  me = (Map.Entry)  itr.next();
+      FlatNode   fn = (FlatNode)   me.getKey();
+      ReachGraph rg = (ReachGraph) me.getValue();
+
+      rg.writeGraph("NODEFINAL"+fn,
+                    true,    // write labels (variables)
+                    false,   // selectively hide intermediate temp vars
+                    true,    // prune unreachable heap regions
+                    true,    // hide all reachability
+                    true,    // hide subset reachability states
+                    true,    // hide predicates
+                    true);   // hide edge taints
+    }
+  }
+
 
   protected ReachGraph getPartial(Descriptor d) {
     return mapDescriptorToCompleteReachGraph.get(d);
@@ -2321,7 +2431,13 @@ public class DisjointAnalysis implements HeapAnalysis {
     Hashtable<FlatCall, ReachGraph> heapsFromCallers =
       getIHMcontributions(d);
 
-    heapsFromCallers.put(fc, rg);
+    // ensure inputs to initial contexts increase monotonically
+    ReachGraph merged = new ReachGraph();
+    merged.merge( rg );
+    merged.merge( heapsFromCallers.get( fc ) );
+
+    heapsFromCallers.put( fc, merged );
+    
   }
 
 
@@ -2872,12 +2988,25 @@ public class DisjointAnalysis implements HeapAnalysis {
         state.DISJOINTDEBUGCALLER.equals( taskOrMethodCaller.getSymbol() );
     }
 
+
     dcsd.debugCallSite = debugCalleeMatches && debugCallerMatches;
-    dcsd.writeDebugDOTs = dcsd.debugCallSite;
+
+
+    dcsd.writeDebugDOTs = 
+      
+      dcsd.debugCallSite &&
+
+      (ReachGraph.debugCallSiteVisitCounter >=
+       ReachGraph.debugCallSiteVisitStartCapture)  &&
+         
+      (ReachGraph.debugCallSiteVisitCounter <
+       ReachGraph.debugCallSiteVisitStartCapture +
+       ReachGraph.debugCallSiteNumVisitsToCapture);
+         
+
 
     if( dcsd.debugCallSite ) {
       dcsd.didOneDebug = true;
-      System.out.println( "       --> Debugging "+taskOrMethodCaller+" calling "+mdCallee );
     }
   }
 
@@ -2887,7 +3016,6 @@ public class DisjointAnalysis implements HeapAnalysis {
     dcsd.stopAfter      = false;
 
     if( dcsd.didOneDebug ) {
-      ++ReachGraph.debugCallSiteVisitCounter;
       System.out.println("    $$$ Debug call site visit "+
                          ReachGraph.debugCallSiteVisitCounter+
                          " $$$"
@@ -2910,6 +3038,8 @@ public class DisjointAnalysis implements HeapAnalysis {
           dcsd.stopAfter = true;
         }
       }
+
+      ++ReachGraph.debugCallSiteVisitCounter;
     }
 
     if( dcsd.stopAfter ) {
@@ -2964,7 +3094,7 @@ public class DisjointAnalysis implements HeapAnalysis {
                     true,    // selectively hide intermediate temp vars
                     true,    // prune unreachable heap regions
                     false,   // hide reachability
-                    false,   // hide subset reachability states
+                    true,   // hide subset reachability states
                     true,    // hide predicates
                     true);   // hide edge taints
     }
@@ -2983,18 +3113,6 @@ public class DisjointAnalysis implements HeapAnalysis {
 
     return rgAtEnter.canPointTo( x );
   }
-
-
-  public Set<Alloc> canPointToAfter( TempDescriptor x,
-                                     FlatNode programPoint ) {
-
-    ReachGraph rgAtExit = fn2rgAtExit.get( programPoint );
-    if( rgAtExit == null ) {
-      return null; 
-    }
-
-    return rgAtExit.canPointTo( x );
-  }
   
 
   public Hashtable< Alloc, Set<Alloc> > canPointToAt( TempDescriptor x,
@@ -3023,4 +3141,45 @@ public class DisjointAnalysis implements HeapAnalysis {
 
     return rgAtEnter.canPointTo( x, arrayElementFieldName, x.getType().dereference() );
   }
+
+
+  public Set<Alloc> canPointToAfter( TempDescriptor x,
+                                     FlatNode programPoint ) {
+
+    ReachGraph rgAtExit = fn2rgAtExit.get( programPoint );
+
+    if( rgAtExit == null ) {
+      return null; 
+    }
+
+    return rgAtExit.canPointTo( x );
+  }
+
+
+  public Hashtable< Alloc, Set<Alloc> > canPointToAfter( TempDescriptor x,
+                                                         FieldDescriptor f,
+                                                         FlatNode programPoint ) {
+
+    ReachGraph rgAtExit = fn2rgAtExit.get( programPoint );
+    if( rgAtExit == null ) {
+      return null; 
+    }
+    
+    return rgAtExit.canPointTo( x, f.getSymbol(), f.getType() );
+  }
+
+
+  public Hashtable< Alloc, Set<Alloc> > canPointToAfterElement( TempDescriptor x,
+                                                                FlatNode programPoint ) {
+
+    ReachGraph rgAtExit = fn2rgAtExit.get( programPoint );
+    if( rgAtExit == null ) {
+      return null; 
+    }
+
+    assert x.getType() != null;
+    assert x.getType().isArray();
+
+    return rgAtExit.canPointTo( x, arrayElementFieldName, x.getType().dereference() );
+  }
 }