running new experiments
[IRC.git] / Robust / src / Analysis / Disjoint / ReachGraph.java
index f43df03a3125b2e11d299900266d094b19dfe0cf..1e065cd9cec19c141c6bd91b49fae0b10410537e 100644 (file)
@@ -9,11 +9,22 @@ import java.io.*;
 public class ReachGraph {
 
   // use to disable improvements for comparison
-  protected static final boolean DISABLE_STRONG_UPDATES = false;
-  protected static final boolean DISABLE_GLOBAL_SWEEP   = false;
-
-  // a special out-of-scope temp
-  protected static final TempDescriptor tdReturn = new TempDescriptor("_Return___");
+  protected static boolean DISABLE_STRONG_UPDATES = false;
+  protected static boolean DISABLE_GLOBAL_SWEEP   = false;
+  protected static boolean DISABLE_PREDICATES     = false;
+
+  // a special out-of-scope temps
+  protected static TempDescriptor tdReturn;
+  protected static TempDescriptor tdStrLiteralBytes;
+  
+  public static void initOutOfScopeTemps() {
+    tdReturn = new TempDescriptor("_Return___");
+
+    tdStrLiteralBytes = 
+      new TempDescriptor("_strLiteralBytes___",
+                         new TypeDescriptor(TypeDescriptor.CHAR).makeArray( state )
+                         );
+  }
 
   // predicate constants
   public static final ExistPred predTrue   = ExistPred.factory();    // if no args, true
@@ -247,11 +258,21 @@ public class ReachGraph {
     referencee.removeReferencer(edge);
   }
 
-  // return whether at least one edge was removed
+
   protected boolean clearRefEdgesFrom(RefSrcNode referencer,
                                       TypeDescriptor type,
                                       String field,
                                       boolean removeAll) {
+    return clearRefEdgesFrom( referencer, type, field, removeAll, null, null );
+  }
+
+  // return whether at least one edge was removed
+  protected boolean clearRefEdgesFrom(RefSrcNode referencer,
+                                      TypeDescriptor type,
+                                      String field,
+                                      boolean removeAll,
+                                      Set<EdgeKey> edgeKeysRemoved,
+                                      FieldDescriptor fd) {
     assert referencer != null;
 
     boolean atLeastOneEdgeRemoved = false;
@@ -269,6 +290,15 @@ public class ReachGraph {
 
         HeapRegionNode referencee = edge.getDst();
 
+        if( edgeKeysRemoved != null ) {
+          assert fd != null;
+          assert referencer instanceof HeapRegionNode;
+          edgeKeysRemoved.add( new EdgeKey( ((HeapRegionNode)referencer).getID(), 
+                                            referencee.getID(),
+                                            fd )
+                                );
+        }
+
         removeRefEdge(referencer,
                       referencee,
                       edge.getType(),
@@ -380,6 +410,30 @@ public class ReachGraph {
   //
   ////////////////////////////////////////////////////
 
+  public void assignTempEqualToStringLiteral(TempDescriptor  x,
+                                             AllocSite       asStringLiteral,
+                                             AllocSite       asStringLiteralBytes,
+                                             FieldDescriptor fdStringBytesField) {
+    // model this to get points-to information right for
+    // pointers to string literals, even though it doesn't affect
+    // reachability paths in the heap
+    assignTempEqualToNewAlloc( x, 
+                               asStringLiteral );
+
+    assignTempEqualToNewAlloc( tdStrLiteralBytes, 
+                               asStringLiteralBytes );
+
+    assignTempXFieldFEqualToTempY( x,
+                                   fdStringBytesField,
+                                   tdStrLiteralBytes,
+                                   null,
+                                   false,
+                                   null,
+                                   null,
+                                   null );
+  }
+
+
   public void assignTempXEqualToTempY(TempDescriptor x,
                                       TempDescriptor y) {
     assignTempXEqualToCastedTempY(x, y, null);
@@ -444,7 +498,8 @@ public class ReachGraph {
   public void assignTempXEqualToTempYFieldF(TempDescriptor x,
                                             TempDescriptor y,
                                             FieldDescriptor f,
-                                            FlatNode currentProgramPoint
+                                            FlatNode currentProgramPoint,
+                                            Set<EdgeKey> edgeKeysForLoad
                                             ) {
 
     VariableNode lnX = getVariableNodeFromTemp(x);
@@ -483,6 +538,16 @@ public class ReachGraph {
           continue;
         }
 
+        // for definite reach analysis only
+        if( edgeKeysForLoad != null ) {
+          assert f != null;
+          edgeKeysForLoad.add( new EdgeKey( hrnY.getID(), 
+                                            hrnHrn.getID(),
+                                            f )
+                               );
+        }
+
+
         TypeDescriptor tdNewEdge =
           mostSpecificType(edgeHrn.getType(),
                            hrnHrn.getType()
@@ -531,7 +596,11 @@ public class ReachGraph {
   public boolean assignTempXFieldFEqualToTempY(TempDescriptor x,
                                                FieldDescriptor f,
                                                TempDescriptor y,
-                                               FlatNode currentProgramPoint
+                                               FlatNode currentProgramPoint,
+                                               boolean alreadyReachable,
+                                               Set<EdgeKey> edgeKeysRemoved,
+                                               Set<EdgeKey> edgeKeysAdded,
+                                               Set<DefiniteReachState.FdEntry> edgesToElideFromPropFd
                                                ) {
 
     VariableNode lnX = getVariableNodeFromTemp(x);
@@ -564,11 +633,12 @@ public class ReachGraph {
         if( !DISABLE_STRONG_UPDATES ) {
           strongUpdateCond = true;
 
-          boolean atLeastOne =
-            clearRefEdgesFrom(hrnX,
-                              f.getType(),
-                              f.getSymbol(),
-                              false);
+          boolean atLeastOne = clearRefEdgesFrom(hrnX,
+                                                 f.getType(),
+                                                 f.getSymbol(),
+                                                 false,
+                                                 edgeKeysRemoved,
+                                                 f);          
           if( atLeastOne ) {
             edgeRemovedByStrongUpdate = true;
           }
@@ -576,53 +646,108 @@ public class ReachGraph {
       }
     }
 
-    // then do all token propagation
-    itrXhrn = lnX.iteratorToReferencees();
-    while( itrXhrn.hasNext() ) {
-      RefEdge edgeX = itrXhrn.next();
-      HeapRegionNode hrnX  = edgeX.getDst();
-      ReachSet betaX = edgeX.getBeta();
-      ReachSet R     = Canonical.intersection(hrnX.getAlpha(),
-                                              edgeX.getBeta()
-                                              );
 
-      Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
-      while( itrYhrn.hasNext() ) {
-        RefEdge edgeY = itrYhrn.next();
-        HeapRegionNode hrnY  = edgeY.getDst();
-        ReachSet O     = edgeY.getBeta();
+    // definite reachability analysis can elide some edges from
+    // propagating reach information
+    Set<RefEdge> edgesToElideFromProp = null;
+    if( edgesToElideFromPropFd != null ) {
+      edgesToElideFromProp = new HashSet<RefEdge>();
+      Iterator<RefEdge> itrY = lnY.iteratorToReferencees();
+      while( itrY.hasNext() ) {
+        HeapRegionNode hrnSrc = itrY.next().getDst();
 
-        // check for impossible edges
-        if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
-          impossibleEdges.add(edgeY);
-          continue;
+        Iterator<RefEdge> itrhrn = hrnSrc.iteratorToReferencees();
+        while( itrhrn.hasNext() ) {
+          RefEdge        edgeToElide = itrhrn.next();
+          String         f0          = edgeToElide.getField();
+          HeapRegionNode hrnDst      = edgeToElide.getDst();
+
+          // does this graph edge match a statically-named edge
+          // that def reach says we don't have to prop over?
+          for( DefiniteReachState.FdEntry entry : edgesToElideFromPropFd ) {
+            if( !entry.f0.getSymbol().equals( f0 ) ) {
+              continue;
+            }
+            boolean refByZ = false;
+            Iterator<RefEdge> itrRef = hrnDst.iteratorToReferencers();
+            while( itrRef.hasNext() ) {
+              RefEdge edgeZ = itrRef.next();
+              if( edgeZ.getSrc() instanceof VariableNode ) {
+                VariableNode vnZ = (VariableNode) edgeZ.getSrc();
+                if( vnZ.getTempDescriptor().equals( entry.z ) ) {
+                  refByZ = true;
+                  break;
+                }
+              }
+            }
+            if( refByZ ) {
+              // this graph edge matches the def reach edge, mark it for
+              // no propagation
+              edgesToElideFromProp.add( edgeToElide );
+            }
+          }
         }
+      }
+    }
 
-        // propagate tokens over nodes starting from hrnSrc, and it will
-        // take care of propagating back up edges from any touched nodes
-        ChangeSet Cy = Canonical.unionUpArityToChangeSet(O, R);
-        propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
 
-        // then propagate back just up the edges from hrn
-        ChangeSet Cx = Canonical.unionUpArityToChangeSet(R, O);
-        HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
 
-        Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
-          new Hashtable<RefEdge, ChangeSet>();
+    // definite reachability analysis can elide reachability propagation
+    if( !alreadyReachable ) {
 
-        Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
-        while( referItr.hasNext() ) {
-          RefEdge edgeUpstream = referItr.next();
-          todoEdges.add(edgeUpstream);
-          edgePlannedChanges.put(edgeUpstream, Cx);
-        }
+      // then do all token propagation
+      itrXhrn = lnX.iteratorToReferencees();
+      while( itrXhrn.hasNext() ) {
+        RefEdge edgeX = itrXhrn.next();
+        HeapRegionNode hrnX  = edgeX.getDst();
+        ReachSet betaX = edgeX.getBeta();
+        ReachSet R     = Canonical.intersection(hrnX.getAlpha(),
+                                                edgeX.getBeta()
+                                                );
 
-        propagateTokensOverEdges(todoEdges,
-                                 edgePlannedChanges,
-                                 edgesWithNewBeta);
+        Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
+        while( itrYhrn.hasNext() ) {
+          RefEdge edgeY = itrYhrn.next();
+          HeapRegionNode hrnY  = edgeY.getDst();
+          ReachSet O     = edgeY.getBeta();
+
+          // check for impossible edges
+          if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
+            impossibleEdges.add(edgeY);
+            continue;
+          }
+
+          // propagate tokens over nodes starting from hrnSrc, and it will
+          // take care of propagating back up edges from any touched nodes
+          ChangeSet Cy = Canonical.unionUpArityToChangeSet(O, R);
+          propagateTokensOverNodes( hrnY, 
+                                    Cy, 
+                                    nodesWithNewAlpha, 
+                                    edgesWithNewBeta,
+                                    edgesToElideFromProp );
+
+          // then propagate back just up the edges from hrn
+          ChangeSet Cx = Canonical.unionUpArityToChangeSet(R, O);
+          HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
+
+          Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
+            new Hashtable<RefEdge, ChangeSet>();
+
+          Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
+          while( referItr.hasNext() ) {
+            RefEdge edgeUpstream = referItr.next();
+            todoEdges.add(edgeUpstream);
+            edgePlannedChanges.put(edgeUpstream, Cx);
+          }
+
+          propagateTokensOverEdges( todoEdges,
+                                    edgePlannedChanges,
+                                    edgesWithNewBeta,
+                                    edgesToElideFromProp );
+        }
       }
     }
-
+      
 
     // apply the updates to reachability
     Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
@@ -653,6 +778,18 @@ public class ReachGraph {
           continue;
         }
 
+
+        // for definite reach analysis only
+        if( edgeKeysAdded != null ) {
+          assert f != null;
+          edgeKeysAdded.add( new EdgeKey( hrnX.getID(),
+                                          hrnY.getID(),
+                                          f )
+                             );
+
+          
+        }
+
         // prepare the new reference edge hrnX.f -> hrnY
         TypeDescriptor tdNewEdge =
           mostSpecificType(y.getType(),
@@ -668,17 +805,23 @@ public class ReachGraph {
                                                 currentProgramPoint);
         }
 
+
+        ReachSet betaNew;
+        if( alreadyReachable ) {
+          betaNew = edgeY.getBeta();
+        } else {
+          betaNew = Canonical.pruneBy( edgeY.getBeta(),
+                                       hrnX.getAlpha() );
+        }
+
+
         RefEdge edgeNew =
           new RefEdge(hrnX,
                       hrnY,
                       tdNewEdge,
                       f.getSymbol(),
-                      Canonical.changePredsTo(
-                        Canonical.pruneBy(edgeY.getBeta(),
-                                          hrnX.getAlpha()
-                                          ),
-                        predsTrue
-                        ),
+                      Canonical.changePredsTo( betaNew,
+                                               predsTrue ),
                       predsTrue,
                       taints
                       );
@@ -841,8 +984,8 @@ public class ReachGraph {
 
     // after tokens have been aged, reset newest node's reachability
     // and a brand new node has a "true" predicate
-    hrn0.setAlpha(hrn0.getInherent() );
-    hrn0.setPreds(predsTrue);
+    hrn0.setAlpha( Canonical.changePredsTo( hrn0.getInherent(), predsTrue ) );
+    hrn0.setPreds( predsTrue);
   }
 
 
@@ -1097,7 +1240,8 @@ public class ReachGraph {
   protected void propagateTokensOverNodes(HeapRegionNode nPrime,
                                           ChangeSet c0,
                                           HashSet<HeapRegionNode> nodesWithNewAlpha,
-                                          HashSet<RefEdge>        edgesWithNewBeta) {
+                                          HashSet<RefEdge>        edgesWithNewBeta,
+                                          Set<RefEdge>            edgesToElideProp ) {
 
     HashSet<HeapRegionNode> todoNodes
       = new HashSet<HeapRegionNode>();
@@ -1121,6 +1265,10 @@ public class ReachGraph {
       Iterator<RefEdge> referItr = n.iteratorToReferencers();
       while( referItr.hasNext() ) {
         RefEdge edge = referItr.next();
+
+        if( edgesToElideProp != null && edgesToElideProp.contains( edge ) ) {
+          continue;
+        }
         todoEdges.add(edge);
 
         if( !edgePlannedChanges.containsKey(edge) ) {
@@ -1139,6 +1287,11 @@ public class ReachGraph {
       Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
       while( refeeItr.hasNext() ) {
         RefEdge edgeF = refeeItr.next();
+
+        if( edgesToElideProp != null && edgesToElideProp.contains( edgeF ) ) {
+          continue;
+        }
+
         HeapRegionNode m     = edgeF.getDst();
 
         ChangeSet changesToPass = ChangeSet.factory();
@@ -1201,14 +1354,15 @@ public class ReachGraph {
 
     propagateTokensOverEdges(todoEdges,
                              edgePlannedChanges,
-                             edgesWithNewBeta
-                             );
+                             edgesWithNewBeta,
+                             edgesToElideProp);
   }
 
 
   protected void propagateTokensOverEdges(HashSet  <RefEdge>            todoEdges,
                                           Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
-                                          HashSet  <RefEdge>            edgesWithNewBeta) {
+                                          HashSet  <RefEdge>            edgesWithNewBeta,
+                                          Set<RefEdge>                  edgesToElideProp ) {
 
     // first propagate all change tuples everywhere they can go
     while( !todoEdges.isEmpty() ) {
@@ -1244,6 +1398,10 @@ public class ReachGraph {
         while( referItr.hasNext() ) {
           RefEdge edgeF = referItr.next();
 
+          if( edgesToElideProp != null && edgesToElideProp.contains( edgeF ) ) {
+            continue;
+          }
+
           if( !edgePlannedChanges.containsKey(edgeF) ) {
             edgePlannedChanges.put(edgeF,
                                    ChangeSet.factory()
@@ -1554,7 +1712,7 @@ public class ReachGraph {
                                           predNodeOrEdge.e_hrnDstID,
                                           predNodeOrEdge.e_type,
                                           predNodeOrEdge.e_field,
-                                          stateCallee,
+                                          stateCaller,
                                           null,
                                           predNodeOrEdge.e_srcOutCalleeContext,
                                           predNodeOrEdge.e_srcOutCallerContext
@@ -1756,8 +1914,10 @@ public class ReachGraph {
 
     // caller edges from arg vars, and the matching param index
     // because these become a special edge in callee
-    Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
-      new Hashtable<RefEdge, Integer>();
+    // NOTE! One argument may be passed in as more than one parameter,
+    // so map to a set of parameter indices!
+    Hashtable< RefEdge, Set<Integer> > reachableCallerArgEdges2paramIndices =
+      new Hashtable< RefEdge, Set<Integer> >();
 
     // caller edges from local vars or callee-unreachable nodes
     // (out-of-context sources) to callee-reachable nodes
@@ -1791,8 +1951,17 @@ public class ReachGraph {
           if( reCaller.getSrc() instanceof HeapRegionNode ) {
             reachableCallerEdges.add(reCaller);
           } else {
+
             if( rsnCaller.equals(vnArgCaller) ) {
-              reachableCallerArgEdges2paramIndex.put(reCaller, i);
+              Set<Integer> pIndices = 
+                reachableCallerArgEdges2paramIndices.get( reCaller );
+
+              if( pIndices == null ) {
+                pIndices = new HashSet<Integer>();
+                reachableCallerArgEdges2paramIndices.put( reCaller, pIndices );
+              }
+              pIndices.add( i );
+
             } else {
               oocCallerEdges.add(reCaller);
             }
@@ -1807,6 +1976,7 @@ public class ReachGraph {
     } // end iterating over parameters as starting points
 
 
+
     // now collect out-of-callee-context IDs and
     // map them to whether the ID is out of the caller
     // context as well
@@ -1901,18 +2071,15 @@ public class ReachGraph {
 
     // add param edges to callee graph
     Iterator argEdges =
-      reachableCallerArgEdges2paramIndex.entrySet().iterator();
+      reachableCallerArgEdges2paramIndices.entrySet().iterator();
     while( argEdges.hasNext() ) {
-      Map.Entry me    = (Map.Entry)argEdges.next();
-      RefEdge reArg = (RefEdge)   me.getKey();
-      Integer index = (Integer)   me.getValue();
+      Map.Entry    me    = (Map.Entry)    argEdges.next();
+      RefEdge      reArg = (RefEdge)      me.getKey();
+      Set<Integer> pInxs = (Set<Integer>) me.getValue();
 
-      VariableNode vnCaller  = (VariableNode) reArg.getSrc();
+      VariableNode   vnCaller  = (VariableNode) reArg.getSrc();
       TempDescriptor argCaller = vnCaller.getTempDescriptor();
 
-      TempDescriptor paramCallee = fmCallee.getParameter(index);
-      VariableNode vnCallee    = rg.getVariableNodeFromTemp(paramCallee);
-
       HeapRegionNode hrnDstCaller = reArg.getDst();
       HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
       assert hrnDstCallee != null;
@@ -1932,24 +2099,30 @@ public class ReachGraph {
       ExistPredSet preds =
         ExistPredSet.factory(pred);
 
-      RefEdge reCallee =
-        new RefEdge(vnCallee,
-                    hrnDstCallee,
-                    reArg.getType(),
-                    reArg.getField(),
-                    toCalleeContext(reArg.getBeta(),
-                                    preds,
-                                    oocHrnIdOoc2callee
-                                    ),
-                    preds,
-                    toCalleeContext(reArg.getTaints(),
-                                    preds)
-                    );
+      for( Integer index: pInxs ) {
 
-      rg.addRefEdge(vnCallee,
-                    hrnDstCallee,
-                    reCallee
-                    );
+        TempDescriptor paramCallee = fmCallee.getParameter(index);
+        VariableNode vnCallee    = rg.getVariableNodeFromTemp(paramCallee);
+
+        RefEdge reCallee =
+          new RefEdge(vnCallee,
+                      hrnDstCallee,
+                      reArg.getType(),
+                      reArg.getField(),
+                      toCalleeContext(reArg.getBeta(),
+                                      preds,
+                                      oocHrnIdOoc2callee
+                                      ),
+                      preds,
+                      toCalleeContext(reArg.getTaints(),
+                                      preds)
+                      );
+        
+        rg.addRefEdge(vnCallee,
+                      hrnDstCallee,
+                      reCallee
+                      );
+      }
     }
 
     // add in-context edges to callee graph
@@ -2137,7 +2310,9 @@ public class ReachGraph {
           }
         }
 
-        assert hrnCalleeAndOutContext.reachHasOnlyOOC();
+        if( !DISABLE_GLOBAL_SWEEP ) {
+          assert hrnCalleeAndOutContext.reachHasOnlyOOC();
+        }
 
         rg.addRefEdge(hrnCalleeAndOutContext,
                       hrnDstCallee,
@@ -2211,14 +2386,13 @@ public class ReachGraph {
     new Hashtable<String, Integer>();
 
 
-  // useful since many graphs writes in the method call debug code
   private static boolean resolveMethodDebugDOTwriteLabels     = true;
   private static boolean resolveMethodDebugDOTselectTemps     = true;
   private static boolean resolveMethodDebugDOTpruneGarbage    = true;
-  private static boolean resolveMethodDebugDOThideReach       = true;
+  private static boolean resolveMethodDebugDOThideReach       = false;
   private static boolean resolveMethodDebugDOThideSubsetReach = true;
-  private static boolean resolveMethodDebugDOThidePreds       = true;
-  private static boolean resolveMethodDebugDOThideEdgeTaints  = false;
+  private static boolean resolveMethodDebugDOThidePreds       = false;
+  private static boolean resolveMethodDebugDOThideEdgeTaints  = true;
 
   static String debugGraphPrefix;
   static int debugCallSiteVisitCounter;
@@ -2302,6 +2476,7 @@ public class ReachGraph {
       new Hashtable< RefEdge, Set<RefSrcNode> >();
 
 
+
     Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
     while( meItr.hasNext() ) {
       Map.Entry me        = (Map.Entry)meItr.next();
@@ -2314,8 +2489,8 @@ public class ReachGraph {
       // should have, and it is inefficient to find this again later
       ExistPredSet predsIfSatis =
         hrnCallee.getPreds().isSatisfiedBy(this,
-                                           callerNodeIDsCopiedToCallee
-                                           );
+                                           callerNodeIDsCopiedToCallee,
+                                           null);
 
       if( predsIfSatis != null ) {
         calleeNodesSatisfied.put(hrnCallee, predsIfSatis);
@@ -2324,6 +2499,8 @@ public class ReachGraph {
         continue;
       }
 
+
+
       // since the node is coming over, find out which reach
       // states on it should come over, too
       assert calleeNode2calleeStatesSatisfied.get(hrnCallee) == null;
@@ -2334,8 +2511,8 @@ public class ReachGraph {
 
         predsIfSatis =
           stateCallee.getPreds().isSatisfiedBy(this,
-                                               callerNodeIDsCopiedToCallee
-                                               );
+                                               callerNodeIDsCopiedToCallee,
+                                               null);
         if( predsIfSatis != null ) {
 
           Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
@@ -2404,8 +2581,8 @@ public class ReachGraph {
 
             predsIfSatis =
               hrnSrcCallee.getPreds().isSatisfiedBy(this,
-                                                    callerNodeIDsCopiedToCallee
-                                                    );
+                                                    callerNodeIDsCopiedToCallee,
+                                                    null);
             if( predsIfSatis != null ) {
               calleeNodesSatisfied.put(hrnSrcCallee, predsIfSatis);
             } else {
@@ -2415,55 +2592,18 @@ public class ReachGraph {
 
           } else {
             // hrnSrcCallee is out-of-context
-
             assert !calleeEdges2oocCallerSrcMatches.containsKey(reCallee);
 
             Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
 
-            // is the target node in the caller?
-            HeapRegionNode hrnDstCaller = this.id2hrn.get(hrnCallee.getID() );
-            if( hrnDstCaller == null ) {
-              continue;
-            }
-
-            Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
-            while( reDstItr.hasNext() ) {
-              // the edge and field (either possibly null) must match
-              RefEdge reCaller = reDstItr.next();
-
-              if( !reCaller.typeEquals(reCallee.getType()  ) ||
-                  !reCaller.fieldEquals(reCallee.getField() )
-                  ) {
-                continue;
-              }
-
-              RefSrcNode rsnCaller = reCaller.getSrc();
-              if( rsnCaller instanceof VariableNode ) {
-
-                // a variable node matches an OOC region with null type
-                if( hrnSrcCallee.getType() != null ) {
-                  continue;
-                }
-
-              } else {
-                // otherwise types should match
-                HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
-                if( hrnSrcCallee.getType() == null ) {
-                  if( hrnCallerSrc.getType() != null ) {
-                    continue;
-                  }
-                } else {
-                  if( !hrnSrcCallee.getType().equals(hrnCallerSrc.getType() ) ) {
-                    continue;
-                  }
-                }
-              }
-
-              rsnCallers.add(rsnCaller);
-              matchedOutOfContext = true;
-            }
+            // use the isSatisfiedBy with a non-null callers set to capture
+            // nodes in the caller that match the predicates
+            reCallee.getPreds().isSatisfiedBy( this,
+                                               callerNodeIDsCopiedToCallee,
+                                               rsnCallers );
 
             if( !rsnCallers.isEmpty() ) {
+              matchedOutOfContext = true;
               calleeEdges2oocCallerSrcMatches.put(reCallee, rsnCallers);
             }
           }
@@ -2477,8 +2617,9 @@ public class ReachGraph {
 
         predsIfSatis =
           reCallee.getPreds().isSatisfiedBy(this,
-                                            callerNodeIDsCopiedToCallee
-                                            );
+                                            callerNodeIDsCopiedToCallee,
+                                            null);
+
 
         if( predsIfSatis != null ) {
           calleeEdgesSatisfied.put(reCallee, predsIfSatis);
@@ -2493,8 +2634,8 @@ public class ReachGraph {
 
             predsIfSatis =
               stateCallee.getPreds().isSatisfiedBy(this,
-                                                   callerNodeIDsCopiedToCallee
-                                                   );
+                                                   callerNodeIDsCopiedToCallee,
+                                                   null);
             if( predsIfSatis != null ) {
 
               Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
@@ -2521,8 +2662,8 @@ public class ReachGraph {
 
             predsIfSatis =
               tCallee.getPreds().isSatisfiedBy(this,
-                                               callerNodeIDsCopiedToCallee
-                                               );
+                                               callerNodeIDsCopiedToCallee,
+                                               null);
             if( predsIfSatis != null ) {
 
               Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
@@ -2618,7 +2759,7 @@ public class ReachGraph {
 
       AllocSite as = hrnCallee.getAllocSite();
       allocSites.add(as);
-
+      
       Integer hrnIDshadow = as.getShadowIDfromID(hrnCallee.getID() );
 
       HeapRegionNode hrnCaller = id2hrn.get(hrnIDshadow);
@@ -2849,9 +2990,10 @@ public class ReachGraph {
     // of the caller graph edges
     HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
 
-    propagateTokensOverEdges(edgesForPropagation,  // source edges
-                             edgePlannedChanges,   // map src edge to change set
-                             edgesUpdated);        // list of updated edges
+    propagateTokensOverEdges( edgesForPropagation,  // source edges
+                              edgePlannedChanges,   // map src edge to change set
+                              edgesUpdated,         // list of updated edges
+                              null );        
 
     // commit beta' (beta<-betaNew)
     Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
@@ -3484,7 +3626,8 @@ public class ReachGraph {
 
     propagateTokensOverEdges(edgesForPropagation,
                              edgePlannedChanges,
-                             edgesUpdated);
+                             edgesUpdated,
+                             null);
 
     // at the end of the 1st phase reference edges have
     // beta, betaNew that correspond to beta and betaR
@@ -3939,7 +4082,7 @@ public class ReachGraph {
 
 
 
-  static boolean dbgEquals = false;
+  static public boolean dbgEquals = false;
 
 
   // it is necessary in the equals() member functions
@@ -4165,9 +4308,7 @@ public class ReachGraph {
 
           // there is an edge in the right place with the right field,
           // but do they have the same attributes?
-          if( edgeA.getBeta().equals(edgeB.getBeta() ) &&
-              edgeA.equalsPreds(edgeB)
-              ) {
+          if( edgeA.equalsIncludingBetaPredsTaints( edgeB ) ) {
             edgeFound = true;
           }
         }
@@ -4188,7 +4329,6 @@ public class ReachGraph {
 
     //System.out.println( "*** Asking if A is no smaller than B ***" );
 
-
     Iterator iA = rgA.id2hrn.entrySet().iterator();
     while( iA.hasNext() ) {
       Map.Entry meA  = (Map.Entry)iA.next();
@@ -4199,14 +4339,6 @@ public class ReachGraph {
         System.out.println("  regions smaller");
         return false;
       }
-
-      //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
-      /* NOT EQUALS, NO SMALLER THAN!
-         if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
-         System.out.println( "  regions smaller" );
-         return false;
-         }
-       */
     }
 
     // this works just fine, no smaller than
@@ -4252,14 +4384,6 @@ public class ReachGraph {
           System.out.println("  edges smaller:");
           return false;
         }
-
-        // REMEMBER, IS NO SMALLER THAN
-        /*
-           System.out.println( "  edges smaller" );
-           return false;
-           }
-         */
-
       }
     }
 
@@ -4436,7 +4560,9 @@ public class ReachGraph {
     try {
       // remove all non-word characters from the graph name so
       // the filename and identifier in dot don't cause errors
-      graphName = graphName.replaceAll("[\\W]", "");
+      // jjenista - also replace underscore '_' to prevent some
+      // really, really long names from IHMS debugging
+      graphName = graphName.replaceAll("[\\W_]", "");
 
       BufferedWriter bw =
         new BufferedWriter(new FileWriter(graphName+".dot") );
@@ -5189,4 +5315,135 @@ public class ReachGraph {
   public Set<TempDescriptor> getInaccessibleVars() {
     return inaccessibleVars;
   }
+
+
+
+
+  public Set<Alloc> canPointTo( TempDescriptor x ) {
+
+    if( !DisjointAnalysis.shouldAnalysisTrack( x.getType() ) ) {
+      // if we don't care to track it, return null which means
+      // "a client of this result shouldn't care either"
+      return HeapAnalysis.DONTCARE_PTR;
+    }
+
+    Set<Alloc> out = new HashSet<Alloc>();
+
+    VariableNode vn = getVariableNodeNoMutation( x );
+    if( vn == null ) {
+      // the empty set means "can't point to anything"
+      return out;
+    }
+
+    Iterator<RefEdge> edgeItr = vn.iteratorToReferencees();
+    while( edgeItr.hasNext() ) {
+      HeapRegionNode hrn = edgeItr.next().getDst();
+      out.add( hrn.getAllocSite() );
+    }
+
+    return out;
+  }
+
+
+
+  public Hashtable< Alloc, Set<Alloc> > canPointTo( TempDescriptor x,
+                                                    String         field,
+                                                    TypeDescriptor fieldType ) {
+
+    if( !DisjointAnalysis.shouldAnalysisTrack( x.getType() ) ) {
+      // if we don't care to track it, return null which means
+      // "a client of this result shouldn't care either"
+      return HeapAnalysis.DONTCARE_DREF;
+    }
+
+    Hashtable< Alloc, Set<Alloc> > out = new Hashtable< Alloc, Set<Alloc> >();
+    
+    VariableNode vn = getVariableNodeNoMutation( x );
+    if( vn == null ) {
+      // the empty table means "x can't point to anything"
+      return out;
+    }
+
+    Iterator<RefEdge> edgeItr = vn.iteratorToReferencees();
+    while( edgeItr.hasNext() ) {
+      HeapRegionNode hrn = edgeItr.next().getDst();
+      Alloc          key = hrn.getAllocSite();
+
+      if( !DisjointAnalysis.shouldAnalysisTrack( fieldType ) ) {
+        // if we don't care to track it, put no entry which means
+        // "a client of this result shouldn't care either"
+        out.put( key, HeapAnalysis.DONTCARE_PTR );
+        continue;
+      }
+
+      Set<Alloc> moreValues = new HashSet<Alloc>();
+      Iterator<RefEdge> edgeItr2 = hrn.iteratorToReferencees();
+      while( edgeItr2.hasNext() ) {
+        RefEdge edge = edgeItr2.next();
+        
+        if( field.equals( edge.getField() ) ) {
+          moreValues.add( edge.getDst().getAllocSite() );
+        }
+      }
+
+      if( out.containsKey( key ) ) {
+        out.get( key ).addAll( moreValues );
+      } else {
+        out.put( key, moreValues );
+      }
+    }
+    
+    return out;
+  }
+
+
+
+  // for debugging
+  public TempDescriptor findVariableByName( String name ) {
+
+    for( TempDescriptor td: td2vn.keySet() ) {
+      if( td.getSymbol().contains( name ) ) {
+        return td;
+      }
+    }
+    
+    return null;
+  }
+
+
+  public String countGraphElements() {
+    long numNodes = 0;
+    long numEdges = 0;
+    long numNodeStates = 0;
+    long numEdgeStates = 0;
+    long numNodeStateNonzero = 0;
+    long numEdgeStateNonzero = 0;
+
+    for( HeapRegionNode node : id2hrn.values() ) {
+      numNodes++;
+      numNodeStates       += node.getAlpha().numStates();
+      numNodeStateNonzero += node.getAlpha().numNonzeroTuples();
+
+      // all edges in the graph point TO a heap node, so scanning
+      // all referencers of all nodes gets every edge
+      Iterator<RefEdge> refItr = node.iteratorToReferencers();
+      while( refItr.hasNext() ) {
+        RefEdge edge = refItr.next();
+
+        numEdges++;
+        numEdgeStates       += edge.getBeta().numStates();
+        numEdgeStateNonzero += edge.getBeta().numNonzeroTuples();
+      }
+    }
+
+    return 
+      "################################################\n"+
+      "Nodes                = "+numNodes+"\n"+
+      "Edges                = "+numEdges+"\n"+
+      "Node states          = "+numNodeStates+"\n"+
+      "Edge states          = "+numEdgeStates+"\n"+
+      "Node non-zero tuples = "+numNodeStateNonzero+"\n"+
+      "Edge non-zero tuples = "+numEdgeStateNonzero+"\n"+
+      "################################################\n";
+  }
 }