exhaustive arity improves for benchmarks with ad=1
[IRC.git] / Robust / src / Analysis / OwnershipAnalysis / OwnershipGraph.java
index ff8e20c92131ad9faa75be2df9493016d8682e46..4084da96d684c5aef44872ec04074e7621ac2122 100644 (file)
@@ -8,6 +8,7 @@ import java.io.*;
 public class OwnershipGraph {
 
   private int allocationDepth;
+  private TypeUtil typeUtil;
 
   // there was already one other very similar reason
   // for traversing heap nodes that is no longer needed
@@ -30,8 +31,9 @@ public class OwnershipGraph {
 
 
 
-  public OwnershipGraph(int allocationDepth) {
+  public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
     this.allocationDepth = allocationDepth;
+    this.typeUtil        = typeUtil;
 
     id2hrn         = new Hashtable<Integer,        HeapRegionNode>();
     td2ln          = new Hashtable<TempDescriptor, LabelNode     >();
@@ -887,7 +889,6 @@ public class OwnershipGraph {
                                 FlatMethod fm,
                                 OwnershipGraph ogCallee) {
 
-
     // define rewrite rules and other structures to organize
     // data by parameter/argument index
     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
@@ -1010,9 +1011,11 @@ public class OwnershipGraph {
       Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
       while( edgeItr.hasNext() ) {
        ReferenceEdge edge = edgeItr.next();
-       D_i = D_i.union(edge.getBeta() );
+       D_i = D_i.union(edge.getBeta());
       }
+
       D_i = D_i.exhaustiveArityCombinations();
+
       paramIndex2rewriteD.put(paramIndex, D_i);
     }
 
@@ -1105,7 +1108,6 @@ public class OwnershipGraph {
        }
       }
 
-
       // update reachable edges
       Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
       while( edgeReachableItr.hasNext() ) {
@@ -1124,7 +1126,6 @@ public class OwnershipGraph {
        edgesWithNewBeta.add(edgeReachable);
       }
 
-
       // update upstream edges
       Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges
       = new Hashtable<ReferenceEdge, ChangeTupleSet>();
@@ -1164,7 +1165,6 @@ public class OwnershipGraph {
     }
 
 
-
     // verify the existence of allocation sites and their
     // shadows from the callee in the context of this caller graph
     // then map allocated nodes of callee onto the caller shadows
@@ -1280,31 +1280,40 @@ public class OwnershipGraph {
          edgeNewInCallerTemplate.applyBetaNew();
 
 
-
          // So now make a set of possible source heaps in the caller graph
          // and a set of destination heaps in the caller graph, and make
          // a reference edge in the caller for every possible (src,dst) pair
          HashSet<HeapRegionNode> possibleCallerSrcs =
            getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
                                                (HeapRegionNode) edgeCallee.getSrc(),
-                                               true,
                                                paramIndex2reachableCallerNodes);
 
          HashSet<HeapRegionNode> possibleCallerDsts =
            getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
                                                edgeCallee.getDst(),
-                                               false,
                                                paramIndex2reachableCallerNodes);
 
+
          // make every possible pair of {srcSet} -> {dstSet} edges in the caller
          Iterator srcItr = possibleCallerSrcs.iterator();
          while( srcItr.hasNext() ) {
            HeapRegionNode src = (HeapRegionNode) srcItr.next();
 
+           if( !hasMatchingField(src, edgeCallee) ) {
+             // prune this source node possibility
+             continue;
+           }
+
            Iterator dstItr = possibleCallerDsts.iterator();
            while( dstItr.hasNext() ) {
              HeapRegionNode dst = (HeapRegionNode) dstItr.next();
 
+             if( !hasMatchingType(edgeCallee, dst) ) {
+               // prune
+               continue;
+             }
+
+             // otherwise the caller src and dst pair can match the edge, so make it
              ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
              edgeNewInCaller.setSrc(src);
              edgeNewInCaller.setDst(dst);
@@ -1324,11 +1333,11 @@ public class OwnershipGraph {
     }
 
 
-
     // return value may need to be assigned in caller
-    if( fc.getReturnTemp() != null ) {
+    TempDescriptor returnTemp = fc.getReturnTemp();
+    if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
 
-      LabelNode lnLhsCaller = getLabelNodeFromTemp(fc.getReturnTemp() );
+      LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
       clearReferenceEdgesFrom(lnLhsCaller, null, true);
 
       LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
@@ -1337,52 +1346,57 @@ public class OwnershipGraph {
        ReferenceEdge edgeCallee = edgeCalleeItr.next();
 
        ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
-                                                                 null,
-                                                                 edgeCallee.getFieldDesc(),
-                                                                 false,
-                                                                 toShadowTokens(ogCallee, edgeCallee.getBeta() )
-                                                                 );
+                                                                 null,
+                                                                 edgeCallee.getFieldDesc(),
+                                                                 false,
+                                                                 toShadowTokens(ogCallee, edgeCallee.getBeta() )
+                                                                 );
        rewriteCallerEdgeBeta(fm.numParameters(),
-                             bogusIndex,
-                             edgeNewInCallerTemplate,
-                             paramIndex2rewriteJ,
-                             paramIndex2rewriteD,
-                             paramIndex2paramToken,
-                             paramIndex2paramTokenStar,
-                             false,
-                             null);
-       
+                             bogusIndex,
+                             edgeNewInCallerTemplate,
+                             paramIndex2rewriteJ,
+                             paramIndex2rewriteD,
+                             paramIndex2paramToken,
+                             paramIndex2paramTokenStar,
+                             false,
+                             null);
+
        edgeNewInCallerTemplate.applyBetaNew();
 
 
        HashSet<HeapRegionNode> assignCallerRhs =
          getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
                                              edgeCallee.getDst(),
-                                             false,
                                              paramIndex2reachableCallerNodes);
 
        Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
        while( itrHrn.hasNext() ) {
          HeapRegionNode hrnCaller = itrHrn.next();
-        
+
+         if( !hasMatchingType(edgeCallee, hrnCaller) ) {
+           // prune
+           continue;
+         }
+
+         // otherwise caller node can match callee edge, so make it
          ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
          edgeNewInCaller.setSrc(lnLhsCaller);
          edgeNewInCaller.setDst(hrnCaller);
 
          ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
          if( edgeExisting == null ) {
+
            // if this edge doesn't exist in the caller, create it
            addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
          } else {
            // if it already exists, merge with it
            edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
-         }      
+         }
        }
       }
     }
 
 
-
     // merge the shadow nodes of allocation sites back down to normal capacity
     Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
     while( allocItr.hasNext() ) {
@@ -1452,6 +1466,67 @@ public class OwnershipGraph {
   }
 
 
+  protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
+
+    // if no allocation site, then it's a match-everything region
+    AllocationSite asSrc = src.getAllocationSite();
+    if( asSrc == null ) {
+      return true;
+    }
+
+    TypeDescriptor tdSrc = asSrc.getType();
+    assert tdSrc != null;
+
+    // if it's not a class, it doesn't have any fields to match
+    if( !tdSrc.isClass() ) {
+      return false;
+    }
+
+    Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
+    while( fieldsSrcItr.hasNext() ) {
+      FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
+      if( fd == edge.getFieldDesc() ) {
+       return true;
+      }
+    }
+
+    // otherwise it is a class with fields
+    // but we didn't find a match
+    return false;
+  }
+
+
+  protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
+
+    // if the region has no type, matches everything
+    AllocationSite asDst = dst.getAllocationSite();
+    if( asDst == null ) {
+      return true;
+    }
+
+    TypeDescriptor tdDst = asDst.getType();
+    assert tdDst != null;
+
+    // if the type is not a class don't match because
+    // primitives are copied, no memory aliases
+    ClassDescriptor cdDst = tdDst.getClassDesc();
+    if( cdDst == null ) {
+      return false;
+    }
+
+    // if the field is null, it matches everything
+    FieldDescriptor fd = edge.getFieldDesc();
+    if( fd == null ) {
+      return true;
+    }
+    TypeDescriptor tdFd = fd.getType();
+    assert tdFd != null;
+
+    return typeUtil.isSuperorType(tdFd, tdDst);
+  }
+
+
+
   protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
     edge.setBeta(edge.getBeta().unshadowTokens(as) );
   }
@@ -1539,8 +1614,8 @@ public class OwnershipGraph {
     while( ttsItr.hasNext() ) {
       TokenTupleSet tts = ttsItr.next();
 
-      Hashtable<TokenTupleSet, TokenTupleSet> forChangeSet =
-        new Hashtable<TokenTupleSet, TokenTupleSet>();
+      Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > forChangeSet =
+        new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
 
       ReachabilitySet rTemp = tts.rewriteToken(tokenToRewrite,
                                                edge.getBeta(),
@@ -1551,13 +1626,17 @@ public class OwnershipGraph {
       while( fcsItr.hasNext() ) {
        Map.Entry me = (Map.Entry)fcsItr.next();
        TokenTupleSet ttsMatch = (TokenTupleSet) me.getKey();
-       TokenTupleSet ttsAdd   = (TokenTupleSet) me.getValue();
+       HashSet<TokenTupleSet> ttsAddSet = (HashSet<TokenTupleSet>) me.getValue();
+       Iterator<TokenTupleSet> ttsAddItr = ttsAddSet.iterator();
+       while( ttsAddItr.hasNext() ) {
+         TokenTupleSet ttsAdd = ttsAddItr.next();
 
-       ChangeTuple ct = new ChangeTuple(ttsMatch,
-                                        ttsAdd
-                                        ).makeCanonical();
+         ChangeTuple ct = new ChangeTuple(ttsMatch,
+                                          ttsAdd
+                                          ).makeCanonical();
 
-       cts0 = cts0.union(ct);
+         cts0 = cts0.union(ct);
+       }
       }
     }
 
@@ -1672,7 +1751,6 @@ public class OwnershipGraph {
   private HashSet<HeapRegionNode>
   getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
                                       HeapRegionNode hrnCallee,
-                                      boolean mapFromSrc,
                                       Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
                                       ) {
 
@@ -1712,8 +1790,6 @@ public class OwnershipGraph {
       // so it maps to a whole mess of heap regions
       assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
       possibleCallerHRNs = paramIndex2reachableCallerNodes.get(paramIndexCallee);
-
-      // TODO PRUNE BY TYPE/FIELD NAME!!
     }
 
     return possibleCallerHRNs;
@@ -2163,105 +2239,281 @@ public class OwnershipGraph {
   }
 
 
-  /*
-     // given a set B of heap region node ID's, return the set of heap
-     // region node ID's that is reachable from B
-     public HashSet<Integer> getReachableSet( HashSet<Integer> idSetB ) {
+  public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
 
-      HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
-      HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
+    // get parameter's heap region
+    assert paramIndex2id.containsKey(paramIndex1);
+    Integer idParam1 = paramIndex2id.get(paramIndex1);
 
-      // initial nodes to visit are from set B
-      Iterator initialItr = idSetB.iterator();
-      while( initialItr.hasNext() ) {
-          Integer idInitial = (Integer) initialItr.next();
-          assert id2hrn.contains( idInitial );
-          HeapRegionNode hrnInitial = id2hrn.get( idInitial );
-          toVisit.add( hrnInitial );
-      }
+    assert id2hrn.containsKey(idParam1);
+    HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
+    assert hrnParam1 != null;
+
+    // get tokens for this parameter
+    TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
+                                   true,
+                                   TokenTuple.ARITY_ONE).makeCanonical();
+
+    TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
+                                       true,
+                                       TokenTuple.ARITY_MANY).makeCanonical();
+
+
+    // get tokens for the other parameter
+    assert paramIndex2id.containsKey(paramIndex2);
+    Integer idParam2 = paramIndex2id.get(paramIndex2);
+
+    assert id2hrn.containsKey(idParam2);
+    HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
+    assert hrnParam2 != null;
+
+    TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
+                                   true,
+                                   TokenTuple.ARITY_ONE).makeCanonical();
+
+    TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
+                                       true,
+                                       TokenTuple.ARITY_MANY).makeCanonical();
+
+
+    // get special label p_q for first parameter
+    TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
+    assert tdParamQ1 != null;
+    LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
+    assert lnParamQ1 != null;
+
+    // then get the edge from label q to parameter's hrn
+    ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
+    assert edgeSpecialQ1 != null;
+
+    // if the beta of this edge has tokens from both parameters in one
+    // token tuple set, then there is a potential alias between them
+    ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
+    assert beta1 != null;
+
+    if( beta1.containsTupleSetWithBoth(p1,     p2) ) {
+      return true;
+    }
+    if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
+      return true;
+    }
+    if( beta1.containsTupleSetWithBoth(p1,     pStar2) ) {
+      return true;
+    }
+    if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
+      return true;
+    }
+
+    return false;
+  }
 
-      HashSet<Integer> idSetReachableFromB = new HashSet<Integer>();
 
-      // do a heap traversal
-      while( !toVisit.isEmpty() ) {
-          HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
-          toVisit.remove( hrnVisited );
-          visited.add   ( hrnVisited );
+  public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
 
-          // for every node visited, add it to the total
-          // reachable set
-          idSetReachableFromB.add( hrnVisited.getID() );
+    // get parameter's heap region
+    assert paramIndex2id.containsKey(paramIndex);
+    Integer idParam = paramIndex2id.get(paramIndex);
 
-          // find other reachable nodes
-          Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
-          while( referenceeItr.hasNext() ) {
-              Map.Entry me                 = (Map.Entry)               referenceeItr.next();
-              HeapRegionNode hrnReferencee = (HeapRegionNode)          me.getKey();
-              ReferenceEdgeProperties rep  = (ReferenceEdgeProperties) me.getValue();
+    assert id2hrn.containsKey(idParam);
+    HeapRegionNode hrnParam = id2hrn.get(idParam);
+    assert hrnParam != null;
 
-              if( !visited.contains( hrnReferencee ) ) {
-                  toVisit.add( hrnReferencee );
-              }
-          }
+    // get tokens for this parameter
+    TokenTuple p = new TokenTuple(hrnParam.getID(),
+                                  true,
+                                  TokenTuple.ARITY_ONE).makeCanonical();
+
+    TokenTuple pStar = new TokenTuple(hrnParam.getID(),
+                                      true,
+                                      TokenTuple.ARITY_MANY).makeCanonical();
+
+    // get special label p_q
+    TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
+    assert tdParamQ != null;
+    LabelNode lnParamQ = td2ln.get(tdParamQ);
+    assert lnParamQ != null;
+
+    // then get the edge from label q to parameter's hrn
+    ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
+    assert edgeSpecialQ != null;
+
+    // look through this beta set for potential aliases
+    ReachabilitySet beta = edgeSpecialQ.getBeta();
+    assert beta != null;
+
+
+    // get tokens for summary node
+    TokenTuple gs = new TokenTuple(as.getSummary(),
+                                   true,
+                                   TokenTuple.ARITY_ONE).makeCanonical();
+
+    TokenTuple gsStar = new TokenTuple(as.getSummary(),
+                                       true,
+                                       TokenTuple.ARITY_MANY).makeCanonical();
+
+    if( beta.containsTupleSetWithBoth(p,     gs) ) {
+      return true;
+    }
+    if( beta.containsTupleSetWithBoth(pStar, gs) ) {
+      return true;
+    }
+    if( beta.containsTupleSetWithBoth(p,     gsStar) ) {
+      return true;
+    }
+    if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
+      return true;
+    }
+
+    // check for other nodes
+    for( int i = 0; i < as.getAllocationDepth(); ++i ) {
+
+      // the other nodes of an allocation site are single, no stars
+      TokenTuple gi = new TokenTuple(as.getIthOldest(i),
+                                     false,
+                                     TokenTuple.ARITY_ONE).makeCanonical();
+
+      if( beta.containsTupleSetWithBoth(p,     gi) ) {
+       return true;
       }
+      if( beta.containsTupleSetWithBoth(pStar, gi) ) {
+       return true;
+      }
+    }
 
-      return idSetReachableFromB;
-     }
+    return false;
+  }
+
+
+  public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
 
+    // get tokens for summary nodes
+    TokenTuple gs1 = new TokenTuple(as1.getSummary(),
+                                    true,
+                                    TokenTuple.ARITY_ONE).makeCanonical();
 
-     // used to find if a heap region can possibly have a reference to
-     // any of the heap regions in the given set
-     // if the id supplied is in the set, then a self-referencing edge
-     // would return true, but that special case is specifically allowed
-     // meaning that it isn't an external alias
-     public boolean canIdReachSet( Integer id, HashSet<Integer> idSet ) {
+    TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
+                                        true,
+                                        TokenTuple.ARITY_MANY).makeCanonical();
 
-      assert id2hrn.contains( id );
-      HeapRegionNode hrn = id2hrn.get( id );
+    // get summary node's alpha
+    Integer idSum1 = as1.getSummary();
+    assert id2hrn.containsKey(idSum1);
+    HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
+    assert hrnSum1 != null;
+    ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
+    assert alphaSum1 != null;
 
 
-      //HashSet<HeapRegionNode> hrnSet = new HashSet<HeapRegionNode>();
+    // and for the other one
+    TokenTuple gs2 = new TokenTuple(as2.getSummary(),
+                                    true,
+                                    TokenTuple.ARITY_ONE).makeCanonical();
 
-      //Iterator i = idSet.iterator();
-      //while( i.hasNext() ) {
-      //    Integer idFromSet = (Integer) i.next();
-      //   assert id2hrn.contains( idFromSet );
-      //    hrnSet.add( id2hrn.get( idFromSet ) );
-      //}
+    TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
+                                        true,
+                                        TokenTuple.ARITY_MANY).makeCanonical();
 
+    // get summary node's alpha
+    Integer idSum2 = as2.getSummary();
+    assert id2hrn.containsKey(idSum2);
+    HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
+    assert hrnSum2 != null;
+    ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
+    assert alphaSum2 != null;
 
-      // do a traversal from hrn and see if any of the
-      // heap regions from the set come up during that
-      HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
-      HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
+    // does either one report reachability from the other tokens?
+    if( alphaSum1.containsTuple(gsStar2) ) {
+      return true;
+    }
+    if( alphaSum2.containsTuple(gsStar1) ) {
+      return true;
+    }
+
+    // only check non-star token if they are different sites
+    if( as1 != as2 ) {
+      if( alphaSum1.containsTuple(gs2) ) {
+       return true;
+      }
+      if( alphaSum2.containsTuple(gs1) ) {
+       return true;
+      }
+    }
 
-      toVisit.add( hrn );
-      while( !toVisit.isEmpty() ) {
-          HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
-          toVisit.remove( hrnVisited );
-          visited.add   ( hrnVisited );
 
-          Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
-          while( referenceeItr.hasNext() ) {
-              Map.Entry me                 = (Map.Entry)               referenceeItr.next();
-              HeapRegionNode hrnReferencee = (HeapRegionNode)          me.getKey();
-              ReferenceEdgeProperties rep  = (ReferenceEdgeProperties) me.getValue();
+    // check sum2 against alloc1 nodes
+    for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
+      Integer idI1 = as1.getIthOldest(i);
+      assert id2hrn.containsKey(idI1);
+      HeapRegionNode hrnI1 = id2hrn.get(idI1);
+      assert hrnI1 != null;
+      ReachabilitySet alphaI1 = hrnI1.getAlpha();
+      assert alphaI1 != null;
 
-              if( idSet.contains( hrnReferencee.getID() ) ) {
-                  if( !id.equals( hrnReferencee.getID() ) ) {
-                      return true;
-                  }
-              }
+      // the other nodes of an allocation site are single, no stars
+      TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
+                                      false,
+                                      TokenTuple.ARITY_ONE).makeCanonical();
 
-              if( !visited.contains( hrnReferencee ) ) {
-                  toVisit.add( hrnReferencee );
-              }
-          }
+      if( alphaSum2.containsTuple(gi1) ) {
+       return true;
+      }
+      if( alphaI1.containsTuple(gs2) ) {
+       return true;
+      }
+      if( alphaI1.containsTuple(gsStar2) ) {
+       return true;
       }
+    }
 
-      return false;
-     }
-   */
+    // check sum1 against alloc2 nodes
+    for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
+      Integer idI2 = as2.getIthOldest(i);
+      assert id2hrn.containsKey(idI2);
+      HeapRegionNode hrnI2 = id2hrn.get(idI2);
+      assert hrnI2 != null;
+      ReachabilitySet alphaI2 = hrnI2.getAlpha();
+      assert alphaI2 != null;
+
+      TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
+                                      false,
+                                      TokenTuple.ARITY_ONE).makeCanonical();
+
+      if( alphaSum1.containsTuple(gi2) ) {
+       return true;
+      }
+      if( alphaI2.containsTuple(gs1) ) {
+       return true;
+      }
+      if( alphaI2.containsTuple(gsStar1) ) {
+       return true;
+      }
+
+      // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
+      for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
+       Integer idI1 = as1.getIthOldest(j);
+
+       // if these are the same site, don't look for the same token, no alias
+       // different tokens of the same site could alias together though
+       if( idI1 == idI2 ) {
+         continue;
+       }
+
+       HeapRegionNode hrnI1 = id2hrn.get(idI1);
+       ReachabilitySet alphaI1 = hrnI1.getAlpha();
+       TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
+                                       false,
+                                       TokenTuple.ARITY_ONE).makeCanonical();
+       if( alphaI2.containsTuple(gi1) ) {
+         return true;
+       }
+       if( alphaI1.containsTuple(gi2) ) {
+         return true;
+       }
+      }
+    }
+
+    return false;
+  }
 
 
   // for writing ownership graphs to dot files
@@ -2270,7 +2522,8 @@ public class OwnershipGraph {
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
     writeGraph(
       methodDesc.getSymbol() +
@@ -2279,55 +2532,43 @@ public class OwnershipGraph {
       writeLabels,
       labelSelect,
       pruneGarbage,
-      writeReferencers
+      writeReferencers,
+      writeParamMappings
       );
   }
 
-  /*
-     public void writeGraph(Descriptor methodDesc,
-                         FlatNode fn,
+  public void writeGraph(Descriptor methodDesc,
                          boolean writeLabels,
-                         boolean writeReferencers
+                         boolean labelSelect,
+                         boolean pruneGarbage,
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
-     writeGraph(
-      methodDesc.getSymbol() +
-      methodDesc.getNum() +
-      fn.toString(),
-      writeLabels,
-      false,
-      false,
-      writeReferencers
-      );
-     }
 
-     public void writeGraph(Descriptor methodDesc,
-                         boolean writeLabels,
-                         boolean writeReferencers
-                         ) throws java.io.IOException {
-     writeGraph(
-      methodDesc.getSymbol() +
-      methodDesc.getNum() +
-      "COMPLETE",
-      writeLabels,
-      false,
-      false,
-      writeReferencers
-      );
-     }
-   */
+    writeGraph(methodDesc+"COMPLETE",
+               writeLabels,
+               labelSelect,
+               pruneGarbage,
+               writeReferencers,
+              writeParamMappings
+               );
+  }
 
   public void writeGraph(Descriptor methodDesc,
+                         Integer numUpdate,
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
 
-    writeGraph(methodDesc+"COMPLETE",
+    writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
                writeLabels,
                labelSelect,
                pruneGarbage,
-               writeReferencers
+               writeReferencers,
+              writeParamMappings
                );
   }
 
@@ -2335,7 +2576,8 @@ public class OwnershipGraph {
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
 
     // remove all non-word characters from the graph name so
@@ -2344,7 +2586,6 @@ public class OwnershipGraph {
 
     BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
     bw.write("digraph "+graphName+" {\n");
-    //bw.write( "  size=\"7.5,10\";\n" );
 
     HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
 
@@ -2368,6 +2609,16 @@ public class OwnershipGraph {
 
     bw.write("  graphTitle[label=\""+graphName+"\",shape=box];\n");
 
+    if( writeParamMappings ) {
+      Set df = paramIndex2id.entrySet();
+      Iterator ih = df.iterator();
+      while( ih.hasNext() ) {
+       Map.Entry meh = (Map.Entry)ih.next();
+       Integer pi = (Integer) meh.getKey();
+       Integer id = (Integer) meh.getValue();
+       bw.write("  pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
+      }
+    }
 
     // then visit every label node, useful for debugging
     if( writeLabels ) {