Do effects as a global space, don't even need to consider call site transform, taints...
[IRC.git] / Robust / src / Analysis / Disjoint / ReachGraph.java
index f8c62b2baae46316ea26300034aa1d6b387f621e..71a6f98393ef339275d72dfdb779fcfde9bb9efb 100644 (file)
@@ -14,17 +14,17 @@ public class ReachGraph {
                   
   // a special out-of-scope temp
   protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
+
+  // predicate constants
+  public static final ExistPred    predTrue   = ExistPred.factory(); // if no args, true
+  public static final ExistPredSet predsEmpty = ExistPredSet.factory();
+  public static final ExistPredSet predsTrue  = ExistPredSet.factory( predTrue );
                   
   // some frequently used reachability constants
   protected static final ReachState rstateEmpty        = ReachState.factory();
   protected static final ReachSet   rsetEmpty          = ReachSet.factory();
-  protected static final ReachSet   rsetWithEmptyState = Canonical.makePredsTrue(ReachSet.factory( rstateEmpty ));
-
-  // predicate constants
-  protected static final ExistPred    predTrue   = ExistPred.factory(); // if no args, true
-  protected static final ExistPredSet predsEmpty = ExistPredSet.factory();
-  protected static final ExistPredSet predsTrue  = ExistPredSet.factory( predTrue );
-
+  protected static final ReachSet   rsetWithEmptyState = Canonical.changePredsTo( ReachSet.factory( rstateEmpty ),
+                                                                                  predsTrue );
 
   // from DisjointAnalysis for convenience
   protected static int      allocationDepth   = -1;
@@ -38,11 +38,16 @@ public class ReachGraph {
   // convenient set of alloc sites for all heap regions
   // present in the graph without having to search
   public HashSet<AllocSite> allocSites;  
+  
+  // set of accessible variables for current program statement
+  // if not contains, it is an inaccessible variable
+  public HashSet<TempDescriptor> accessibleVars;
 
   public ReachGraph() {
     id2hrn     = new Hashtable<Integer,        HeapRegionNode>();
     td2vn      = new Hashtable<TempDescriptor, VariableNode  >();
     allocSites = new HashSet<AllocSite>();
+    accessibleVars = new HashSet<TempDescriptor>();
   }
 
   
@@ -129,7 +134,7 @@ public class ReachGraph {
     if( inherent == null ) {
       if( markForAnalysis ) {
        inherent = 
-          Canonical.makePredsTrue(
+          Canonical.changePredsTo(
                                   ReachSet.factory(
                                                    ReachState.factory(
                                                                       ReachTuple.factory( id,
@@ -138,7 +143,8 @@ public class ReachGraph {
                                                                                           false // out-of-context
                                                                                           )
                                                                       )
-                                                   )
+                                                   ),
+                                  predsTrue
                                   );
       } else {
        inherent = rsetWithEmptyState;
@@ -236,12 +242,15 @@ public class ReachGraph {
 
   }
 
-  protected void clearRefEdgesFrom( RefSrcNode     referencer,
-                                    TypeDescriptor type,
-                                    String         field,
-                                    boolean        removeAll ) {
+  // return whether at least one edge was removed
+  protected boolean clearRefEdgesFrom( RefSrcNode     referencer,
+                                       TypeDescriptor type,
+                                       String         field,
+                                       boolean        removeAll ) {
     assert referencer != null;
 
+    boolean atLeastOneEdgeRemoved = false;
+
     // get a copy of the set to iterate over, otherwise
     // we will be trying to take apart the set as we
     // are iterating over it, which won't work
@@ -259,8 +268,12 @@ public class ReachGraph {
                        referencee,
                        edge.getType(),
                        edge.getField() );
+
+        atLeastOneEdgeRemoved = true;
       }
     }
+
+    return atLeastOneEdgeRemoved;
   }
 
   protected void clearRefEdgesTo( HeapRegionNode referencee,
@@ -338,7 +351,12 @@ public class ReachGraph {
                                             edgeNew.getPreds()
                                             )
                             );
-       
+      edgeExisting.setTaints(
+                             Canonical.unionORpreds( edgeExisting.getTaints(),
+                                                     edgeNew.getTaints()
+                                                     )
+                             );
+      
     } else {                     
       addRefEdge( src, dst, edgeNew );
     }
@@ -360,6 +378,12 @@ public class ReachGraph {
   public void assignTempXEqualToTempY( TempDescriptor x,
                                       TempDescriptor y ) {
     assignTempXEqualToCastedTempY( x, y, null );
+    
+    // x gets status of y
+    // if it is in region, 
+    //if(accessibleVars.contains(y)){
+    //  accessibleVars.add(x);
+    //}
   }
 
   public void assignTempXEqualToCastedTempY( TempDescriptor x,
@@ -466,8 +490,7 @@ public class ReachGraph {
                                        null,
                                        Canonical.intersection( betaY, betaHrn ),
                                        predsTrue,
-                                       null,
-                                       null
+                                       edgeY.getTaints()
                                        );
 
         addEdgeOrMergeWithExisting( edgeNew );
@@ -486,13 +509,19 @@ public class ReachGraph {
       if( !DISABLE_GLOBAL_SWEEP ) {
        globalSweep();
       }
-    }    
+    }
+    
+    // accessible status update
+    // if it is in region,
+    //accessibleVars.add(x);
+    //accessibleVars.add(y);
   }
 
 
-  public void assignTempXFieldFEqualToTempY( TempDescriptor  x,
-                                            FieldDescriptor f,
-                                            TempDescriptor  y ) {
+  // return whether a strong update was actually effected
+  public boolean assignTempXFieldFEqualToTempY( TempDescriptor  x,
+                                                FieldDescriptor f,
+                                                TempDescriptor  y ) {
 
     VariableNode lnX = getVariableNodeFromTemp( x );
     VariableNode lnY = getVariableNodeFromTemp( y );
@@ -506,7 +535,8 @@ public class ReachGraph {
     Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
 
     // first look for possible strong updates and remove those edges
-    boolean strongUpdate = false;
+    boolean strongUpdateCond          = false;
+    boolean edgeRemovedByStrongUpdate = false;
 
     Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
     while( itrXhrn.hasNext() ) {
@@ -521,8 +551,16 @@ public class ReachGraph {
              )
          ) {
         if( !DISABLE_STRONG_UPDATES ) {
-          strongUpdate = true;
-          clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
+          strongUpdateCond = true;
+
+          boolean atLeastOne = 
+            clearRefEdgesFrom( hrnX, 
+                               f.getType(), 
+                               f.getSymbol(), 
+                               false );
+          if( atLeastOne ) {
+            edgeRemovedByStrongUpdate = true;
+          }
         }
       }
     }
@@ -616,14 +654,15 @@ public class ReachGraph {
                        hrnY,
                        tdNewEdge,
                        f.getSymbol(),
-                       Canonical.makePredsTrue(
+                       Canonical.changePredsTo(
                                                Canonical.pruneBy( edgeY.getBeta(),
                                                                   hrnX.getAlpha() 
-                                                                  )
+                                                                  ),
+                                               predsTrue
                                                ),
                        predsTrue,
-                       null,
-                       null
+                       Canonical.changePredsTo( edgeY.getTaints(),
+                                                predsTrue )
                        );
 
         addEdgeOrMergeWithExisting( edgeNew );
@@ -638,11 +677,21 @@ public class ReachGraph {
 
     // if there was a strong update, make sure to improve
     // reachability with a global sweep    
-    if( strongUpdate || !impossibleEdges.isEmpty() ) {    
+    if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {    
       if( !DISABLE_GLOBAL_SWEEP ) {
         globalSweep();
       }
     }    
+    
+
+    // after x.y=f , stall x and y if they are not accessible
+    // also contribute write effects on stall site of x
+    // accessible status update
+    // if it is in region
+    //accessibleVars.add(x);
+    //accessibleVars.add(y);
+
+    return edgeRemovedByStrongUpdate;
   }
 
 
@@ -659,6 +708,10 @@ public class ReachGraph {
       HeapRegionNode referencee = edgeX.getDst();
       RefEdge        edgeNew    = edgeX.copy();
       edgeNew.setSrc( lnR );
+      edgeNew.setTaints( Canonical.changePredsTo( edgeNew.getTaints(),
+                                                  predsTrue 
+                                                  )
+                         );
 
       addRefEdge( lnR, referencee, edgeNew );
     }
@@ -693,10 +746,14 @@ public class ReachGraph {
                    null,                 // field name
                    hrnNewest.getAlpha(), // beta
                    predsTrue,            // predicates
-                   null, null
+                   TaintSet.factory()    // taints
                    );
 
     addRefEdge( lnX, hrnNewest, edgeNew );
+    
+    // after x=new , x is accessible
+    // if (isInRegion()) {
+    //accessibleVars.add(x);
   }
 
 
@@ -1240,6 +1297,81 @@ public class ReachGraph {
   }
 
 
+  public void taintInSetVars( FlatSESEEnterNode sese ) {
+    if( sese.getIsCallerSESEplaceholder() ) {
+      return;
+    }
+
+    Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
+    while( isvItr.hasNext() ) {
+      TempDescriptor isv = isvItr.next();
+      VariableNode   vn  = getVariableNodeFromTemp( isv );
+
+      Iterator<RefEdge> reItr = vn.iteratorToReferencees();
+      while( reItr.hasNext() ) {
+        RefEdge re = reItr.next();
+
+        // these in-set taints should have empty 
+        // predicates so they never propagate
+        // out to callers
+        Taint t = Taint.factory( sese,
+                                 null,
+                                 isv,
+                                 re.getDst().getAllocSite(),
+                                 ExistPredSet.factory()
+                                 );
+      
+        re.setTaints( Canonical.add( re.getTaints(),
+                                     t 
+                                     )
+                      );
+      }
+    }
+  }
+
+  // this is useful for more general tainting
+  public void taintTemp( Taint          taint,
+                         TempDescriptor td,
+                         ExistPredSet   preds
+                         ) {
+    
+    VariableNode vn = getVariableNodeFromTemp( td );
+    
+    Iterator<RefEdge> reItr = vn.iteratorToReferencees();
+    while( reItr.hasNext() ) {
+      RefEdge re = reItr.next();
+            
+      re.setTaints( Canonical.add( re.getTaints(),
+                                   taint 
+                                   )
+                    );
+    }
+  }
+  
+  public void removeInContextTaints( FlatSESEEnterNode sese ) {
+    if( sese.getIsCallerSESEplaceholder() ) {
+      return;
+    }
+
+    Iterator meItr = id2hrn.entrySet().iterator();
+    while( meItr.hasNext() ) {
+      Map.Entry      me  = (Map.Entry)      meItr.next();
+      Integer        id  = (Integer)        me.getKey();
+      HeapRegionNode hrn = (HeapRegionNode) me.getValue();
+
+      Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
+      while( reItr.hasNext() ) {
+        RefEdge re = reItr.next();
+
+        re.setTaints( Canonical.removeTaintsBy( re.getTaints(),
+                                                sese
+                                                )
+                      );
+      }
+    }
+  }
+
+
   // used in makeCalleeView below to decide if there is
   // already an appropriate out-of-context edge in a callee
   // view graph for merging, or null if a new one will be added
@@ -1299,7 +1431,7 @@ public class ReachGraph {
   // used below to convert a ReachSet to its callee-context
   // equivalent with respect to allocation sites in this graph
   protected ReachSet toCalleeContext( ReachSet      rs,
-                                      ExistPredSet  preds,
+                                      ExistPredSet  predsNodeOrEdge,
                                       Set<HrnIdOoc> oocHrnIdOoc2callee
                                       ) {
     ReachSet out = ReachSet.factory();
@@ -1382,14 +1514,36 @@ public class ReachGraph {
         stateCallee = stateNew;
       }
       
-      // attach the passed in preds
-      stateCallee = Canonical.attach( stateCallee,
-                                      preds );
+      // make a predicate of the caller graph element
+      // and the caller state we just converted
+      ExistPredSet predsWithState = ExistPredSet.factory();
+
+      Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
+      while( predItr.hasNext() ) {
+        ExistPred predNodeOrEdge = predItr.next();
+
+        predsWithState = 
+          Canonical.add( predsWithState,
+                         ExistPred.factory( predNodeOrEdge.n_hrnID, 
+                                            predNodeOrEdge.e_tdSrc,
+                                            predNodeOrEdge.e_hrnSrcID,
+                                            predNodeOrEdge.e_hrnDstID,
+                                            predNodeOrEdge.e_type,
+                                            predNodeOrEdge.e_field,
+                                            stateCallee,
+                                            null,
+                                            predNodeOrEdge.e_srcOutCalleeContext,
+                                            predNodeOrEdge.e_srcOutCallerContext                                           
+                                            )
+                         );
+      }
 
+      stateCallee = Canonical.changePredsTo( stateCallee,
+                                             predsWithState );
+      
       out = Canonical.add( out,
                            stateCallee
-                           );
-
+                           );      
     }
     assert out.isCanonical();
     return out;
@@ -1403,6 +1557,12 @@ public class ReachGraph {
                      ) {
     ReachSet out = ReachSet.factory();
 
+    // when the mapping is null it means there were no
+    // predicates satisfied
+    if( calleeStatesSatisfied == null ) {
+      return out;
+    }
+
     Iterator<ReachState> itr = rs.iterator();
     while( itr.hasNext() ) {
       ReachState stateCallee = itr.next();
@@ -1440,6 +1600,7 @@ public class ReachGraph {
     return out;
   }
 
+
   // used below to convert a ReachSet to an equivalent
   // version with shadow IDs merged into unshadowed IDs
   protected ReachSet unshadow( ReachSet rs ) {
@@ -1454,6 +1615,99 @@ public class ReachGraph {
   }
 
 
+  // convert a caller taint set into a callee taint set
+  protected TaintSet
+    toCalleeContext( TaintSet     ts,
+                     ExistPredSet predsEdge ) {
+    
+    TaintSet out = TaintSet.factory();
+
+    // the idea is easy, the taint identifier itself doesn't
+    // change at all, but the predicates should be tautology:
+    // start with the preds passed in from the caller edge
+    // that host the taints, and alter them to have the taint
+    // added, just becoming more specific than edge predicate alone
+
+    Iterator<Taint> itr = ts.iterator();
+    while( itr.hasNext() ) {
+      Taint tCaller = itr.next();
+
+      ExistPredSet predsWithTaint = ExistPredSet.factory();
+
+      Iterator<ExistPred> predItr = predsEdge.iterator();
+      while( predItr.hasNext() ) {
+        ExistPred predEdge = predItr.next();
+
+        predsWithTaint = 
+          Canonical.add( predsWithTaint,
+                         ExistPred.factory( predEdge.e_tdSrc,
+                                            predEdge.e_hrnSrcID,
+                                            predEdge.e_hrnDstID,
+                                            predEdge.e_type,
+                                            predEdge.e_field,
+                                            null,
+                                            tCaller,
+                                            predEdge.e_srcOutCalleeContext,
+                                            predEdge.e_srcOutCallerContext                                           
+                                            )
+                         );
+      }
+
+      Taint tCallee = Canonical.changePredsTo( tCaller,
+                                               predsWithTaint );
+
+      out = Canonical.add( out,
+                           tCallee
+                           );
+    }
+
+    assert out.isCanonical();
+    return out;
+  }
+
+
+  // used below to convert a TaintSet to its caller-context
+  // equivalent, just eliminate Taints with bad preds
+  protected TaintSet 
+    toCallerContext( TaintSet                       ts,
+                     Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
+                     ) {
+
+    TaintSet out = TaintSet.factory();
+
+    // when the mapping is null it means there were no
+    // predicates satisfied
+    if( calleeTaintsSatisfied == null ) {
+      return out;
+    }
+
+    Iterator<Taint> itr = ts.iterator();
+    while( itr.hasNext() ) {
+      Taint tCallee = itr.next();
+
+      if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
+        
+        Taint tCaller = 
+          Canonical.attach( Taint.factory( tCallee.sese,
+                                           tCallee.stallSite,
+                                           tCallee.var,
+                                           tCallee.allocSite,
+                                           ExistPredSet.factory() ),
+                            calleeTaintsSatisfied.get( tCallee )
+                            );
+        out = Canonical.add( out,
+                             tCaller
+                             );
+      }     
+    }    
+    
+    assert out.isCanonical();
+    return out;
+  }
+
+
+
+
   // use this method to make a new reach graph that is
   // what heap the FlatMethod callee from the FlatCall 
   // would start with reaching from its arguments in
@@ -1613,7 +1867,7 @@ public class ReachGraph {
                                                    ),
                                   toCalleeContext( hrnCaller.getAlpha(),
                                                    preds,
-                                                   oocHrnIdOoc2callee 
+                                                   oocHrnIdOoc2callee
                                                    ),
                                   preds,
                                   hrnCaller.getDescription()
@@ -1644,19 +1898,14 @@ public class ReachGraph {
                            hrnDstCallee.getID(),
                            reArg.getType(),
                            reArg.getField(),
-                           null,
+                           null,  // state
+                           null,  // taint
                            true,  // out-of-callee-context
                            false  // out-of-caller-context
                            );
       
       ExistPredSet preds = 
         ExistPredSet.factory( pred );
-      
-      Taint paramTaint = 
-        Taint.factory( index, paramCallee.toString() );
-
-      TaintSet paramTaints =
-        TaintSet.factory( paramTaint );
 
       RefEdge reCallee = 
         new RefEdge( vnCallee,
@@ -1668,8 +1917,8 @@ public class ReachGraph {
                                       oocHrnIdOoc2callee
                                       ),
                      preds,
-                     paramTaints, 
-                     null
+                     toCalleeContext( reArg.getTaints(),
+                                      preds )
                      );
       
       rg.addRefEdge( vnCallee,
@@ -1698,7 +1947,8 @@ public class ReachGraph {
                            hrnDstCallee.getID(),
                            reCaller.getType(),
                            reCaller.getField(),
-                           null,
+                           null,  // state
+                           null,  // taint
                            false, // out-of-callee-context
                            false  // out-of-caller-context
                            );
@@ -1716,7 +1966,7 @@ public class ReachGraph {
                                       oocHrnIdOoc2callee 
                                       ),
                      preds,
-                     null, null
+                     TaintSet.factory() // no taints for in-context edges
                      );
       
       rg.addRefEdge( hrnSrcCallee,
@@ -1771,6 +2021,7 @@ public class ReachGraph {
                            reCaller.getType(),
                            reCaller.getField(),
                            null,
+                           null,
                            outOfCalleeContext,
                            outOfCallerContext
                            );
@@ -1873,7 +2124,8 @@ public class ReachGraph {
                                                      oocHrnIdOoc2callee
                                                      ),
                                     preds,
-                                    null, null
+                                    toCalleeContext( reCaller.getTaints(),
+                                                     preds )
                                     )
                        );              
         
@@ -1892,6 +2144,13 @@ public class ReachGraph {
                                                   )
                                   );          
 
+        oocEdgeExisting.setTaints( Canonical.unionORpreds( oocEdgeExisting.getTaints(),
+                                                           toCalleeContext( reCaller.getTaints(),
+                                                                            preds
+                                                                            )
+                                                           )
+                                   );
+
         HeapRegionNode hrnCalleeAndOutContext =
           (HeapRegionNode) oocEdgeExisting.getSrc();
         hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
@@ -2000,12 +2259,22 @@ public class ReachGraph {
     Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
       new Hashtable<RefEdge, ExistPredSet>();
 
-    Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
-      new Hashtable<ReachState, ExistPredSet>();
+    Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
+      calleeNode2calleeStatesSatisfied =
+      new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
+
+    Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
+      calleeEdge2calleeStatesSatisfied =
+      new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
+
+    Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
+      calleeEdge2calleeTaintsSatisfied =
+      new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
 
     Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
       new Hashtable< RefEdge, Set<RefSrcNode> >();
 
+
     Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
     while( meItr.hasNext() ) {
       Map.Entry      me        = (Map.Entry)      meItr.next();
@@ -2030,6 +2299,8 @@ public class ReachGraph {
       
       // since the node is coming over, find out which reach
       // states on it should come over, too
+      assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
+
       Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
       while( stateItr.hasNext() ) {
         ReachState stateCallee = stateItr.next();
@@ -2038,17 +2309,19 @@ public class ReachGraph {
           stateCallee.getPreds().isSatisfiedBy( this,
                                                 callerNodeIDsCopiedToCallee
                                                 );
-        if( predsIfSatis != null ) {
-          ExistPredSet predsAlready = calleeStatesSatisfied.get( stateCallee );
-          if( predsAlready == null ) {
-            calleeStatesSatisfied.put( stateCallee, predsIfSatis );
-          } else {
-            calleeStatesSatisfied.put( stateCallee, 
-                                       Canonical.join( predsIfSatis,
-                                                       predsAlready 
-                                                       )
-                                       );
+        if( predsIfSatis != null ) {          
+      
+          Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
+            calleeNode2calleeStatesSatisfied.get( hrnCallee ); 
+
+          if( calleeStatesSatisfied == null ) {
+            calleeStatesSatisfied = 
+              new Hashtable<ReachState, ExistPredSet>();
+
+            calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
           }
+
+          calleeStatesSatisfied.put( stateCallee, predsIfSatis );
         } 
       }
 
@@ -2185,6 +2458,8 @@ public class ReachGraph {
 
           // since the edge is coming over, find out which reach
           // states on it should come over, too
+          assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
+
           stateItr = reCallee.getBeta().iterator();
           while( stateItr.hasNext() ) {
             ReachState stateCallee = stateItr.next();
@@ -2194,16 +2469,46 @@ public class ReachGraph {
                                                     callerNodeIDsCopiedToCallee
                                                     );
             if( predsIfSatis != null ) {
-              ExistPredSet predsAlready = calleeStatesSatisfied.get( stateCallee );
-              if( predsAlready == null ) {
-                calleeStatesSatisfied.put( stateCallee, predsIfSatis );
-              } else {
-                calleeStatesSatisfied.put( stateCallee, 
-                                           Canonical.join( predsIfSatis,
-                                                           predsAlready 
-                                                           )
-                                           );
+              
+              Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
+                calleeEdge2calleeStatesSatisfied.get( reCallee );
+
+              if( calleeStatesSatisfied == null ) {
+                calleeStatesSatisfied = 
+                  new Hashtable<ReachState, ExistPredSet>();
+
+                calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
+              }
+
+              calleeStatesSatisfied.put( stateCallee, predsIfSatis );             
+            } 
+          }
+
+          // since the edge is coming over, find out which taints
+          // on it should come over, too          
+          assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
+
+          Iterator<Taint> tItr = reCallee.getTaints().iterator();
+          while( tItr.hasNext() ) {
+            Taint tCallee = tItr.next();
+
+            predsIfSatis = 
+              tCallee.getPreds().isSatisfiedBy( this,
+                                                callerNodeIDsCopiedToCallee
+                                                );
+            if( predsIfSatis != null ) {
+              
+              Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
+                calleeEdge2calleeTaintsSatisfied.get( reCallee );
+
+              if( calleeTaintsSatisfied == null ) {
+                calleeTaintsSatisfied = 
+                  new Hashtable<Taint, ExistPredSet>();
+
+                calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
               }
+
+              calleeTaintsSatisfied.put( tCallee, predsIfSatis );
             } 
           }
         }        
@@ -2299,7 +2604,7 @@ public class ReachGraph {
                                    hrnCallee.getType(),        // type                          
                                    hrnCallee.getAllocSite(),   // allocation site                       
                                    toCallerContext( hrnCallee.getInherent(),
-                                                    calleeStatesSatisfied  ),    // inherent reach
+                                                    calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
                                    null,                       // current reach                 
                                    predsEmpty,                 // predicates
                                    hrnCallee.getDescription()  // description
@@ -2309,7 +2614,7 @@ public class ReachGraph {
       }
 
       hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
-                                           calleeStatesSatisfied 
+                                           calleeNode2calleeStatesSatisfied.get( hrnCallee )
                                            )
                           );
 
@@ -2435,9 +2740,10 @@ public class ReachGraph {
                                         reCallee.getType(),
                                         reCallee.getField(),
                                         toCallerContext( reCallee.getBeta(),
-                                                         calleeStatesSatisfied ),
+                                                         calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
                                         preds,
-                                        null, null
+                                        toCallerContext( reCallee.getTaints(),
+                                                         calleeEdge2calleeTaintsSatisfied.get( reCallee ) )
                                         );
 
         ChangeSet cs = ChangeSet.factory();
@@ -2466,28 +2772,16 @@ public class ReachGraph {
                                 );
           }
         }
-        
 
-        // look to see if an edge with same field exists
-        // and merge with it, otherwise just add the edge
-        RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
-                                                         reCallee.getType(),
-                                                         reCallee.getField()
-                                                         );    
-        if( edgeExisting != null ) {
-          edgeExisting.setBeta(
-                               Canonical.unionORpreds( edgeExisting.getBeta(),
-                                                reCaller.getBeta()
-                                                )
-                               );
-          edgeExisting.setPreds(
-                                Canonical.join( edgeExisting.getPreds(),
-                                                reCaller.getPreds()
-                                                )
-                                );
-
-          // for reach propagation
-          if( !cs.isEmpty() ) {
+        // we're just going to use the convenient "merge-if-exists"
+        // edge call below, but still take a separate look if there
+        // is an existing caller edge to build change sets properly
+        if( !cs.isEmpty() ) {
+          RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
+                                                           reCallee.getType(),
+                                                           reCallee.getField()
+                                                           );  
+          if( edgeExisting != null ) {
             ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
             if( csExisting == null ) {
               csExisting = ChangeSet.factory();
@@ -2496,19 +2790,16 @@ public class ReachGraph {
                                     Canonical.union( csExisting,
                                                      cs
                                                      ) 
-                                    );
-          }
-          
-        } else {                         
-          addRefEdge( rsnCaller, hrnDstCaller, reCaller );     
-
-          // for reach propagation
-          if( !cs.isEmpty() ) {
+                                    );                    
+          } else {                       
             edgesForPropagation.add( reCaller );
             assert !edgePlannedChanges.containsKey( reCaller );
-            edgePlannedChanges.put( reCaller, cs );
+            edgePlannedChanges.put( reCaller, cs );        
           }
         }
+
+        // then add new caller edge or merge
+        addEdgeOrMergeWithExisting( reCaller );
       }
     }
 
@@ -3391,6 +3682,7 @@ public class ReachGraph {
     mergeNodes     ( rg );
     mergeRefEdges  ( rg );
     mergeAllocSites( rg );
+    mergeAccessibleSet( rg );
   }
   
   protected void mergeNodes( ReachGraph rg ) {
@@ -3516,16 +3808,11 @@ public class ReachGraph {
                                                edgeA.getPreds()
                                                )
                                );
-          edgeToMerge.setParamTaints(
-                                     Canonical.union( edgeToMerge.getParamTaints(),
-                                                      edgeA.getParamTaints()
-                                                      )
-                                     );
-          edgeToMerge.setRblockTaints(
-                                      Canonical.union( edgeToMerge.getRblockTaints(),
-                                                       edgeA.getRblockTaints()
-                                                       )
-                                      );
+          edgeToMerge.setTaints(
+                                Canonical.union( edgeToMerge.getTaints(),
+                                                 edgeA.getTaints()
+                                                 )
+                                );
        }
       }
     }
@@ -3589,16 +3876,11 @@ public class ReachGraph {
                                                 edgeA.getPreds()
                                                 )
                                 );
-          edgeToMerge.setParamTaints(
-                                     Canonical.union( edgeToMerge.getParamTaints(),
-                                                      edgeA.getParamTaints()
-                                                      )
-                                     );
-          edgeToMerge.setRblockTaints(
-                                      Canonical.union( edgeToMerge.getRblockTaints(),
-                                                       edgeA.getRblockTaints()
-                                                       )
-                                      );
+          edgeToMerge.setTaints(
+                                Canonical.union( edgeToMerge.getTaints(),
+                                                 edgeA.getTaints()
+                                                 )
+                                );
        }
       }
     }
@@ -3607,6 +3889,23 @@ public class ReachGraph {
   protected void mergeAllocSites( ReachGraph rg ) {
     allocSites.addAll( rg.allocSites );
   }
+  
+  protected void mergeAccessibleSet( ReachGraph rg ){
+    // inaccesible status is prior to accessible status
+    
+    Set<TempDescriptor> varsToMerge=rg.getAccessibleVar();    
+    Set<TempDescriptor> varsRemoved=new HashSet<TempDescriptor>();
+    
+    for (Iterator iterator = accessibleVars.iterator(); iterator.hasNext();) {
+      TempDescriptor accessibleVar = (TempDescriptor) iterator.next();
+      if(!varsToMerge.contains(accessibleVar)){
+        varsRemoved.add(accessibleVar);
+      }
+    }
+    
+    accessibleVars.removeAll(varsRemoved);
+        
+  }
 
 
 
@@ -3652,6 +3951,10 @@ public class ReachGraph {
       }
       return false;
     }
+    
+    if( !accessibleVars.equals( rg.accessibleVars) ){
+      return false;
+    }
 
     // if everything is equal up to this point,
     // assert that allocSites is also equal--
@@ -4662,5 +4965,18 @@ public class ReachGraph {
     }
 
     return common;
+  }
+  
+  public void addAccessibleVar(TempDescriptor td){
+    accessibleVars.add(td);
+  }
+  
+  public Set<TempDescriptor> getAccessibleVar(){
+    return accessibleVars;
+  }
+  
+  public void clearAccessibleVarSet(){
+    accessibleVars.clear();
   }  
+  
 }