Tighten up use of canonical objects and halt system if a canonical object's hashcode...
[IRC.git] / Robust / src / Analysis / OwnershipAnalysis / OwnershipGraph.java
index 7c281455e18c9ef7b20e4efe418840f510522737..10376cfbd11eee8335489a27e8ba836273005ba5 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     >();
@@ -82,12 +84,15 @@ public class OwnershipGraph {
 
     if( alpha == null ) {
       if( isFlagged || isParameter ) {
-       alpha = new ReachabilitySet(new TokenTuple(id,
+       alpha = new ReachabilitySet(
+                                   new TokenTuple(id,
                                                   !isSingleObject,
-                                                  TokenTuple.ARITY_ONE)
+                                                  TokenTuple.ARITY_ONE
+                                                  ).makeCanonical()
                                    ).makeCanonical();
       } else {
-       alpha = new ReachabilitySet(new TokenTupleSet()
+       alpha = new ReachabilitySet(
+                                   new TokenTupleSet().makeCanonical()
                                    ).makeCanonical();
       }
     }
@@ -431,6 +436,7 @@ public class OwnershipGraph {
        // then propagate back just up the edges from hrn
        ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
 
+
        HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
 
        Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
@@ -448,8 +454,23 @@ public class OwnershipGraph {
                                 edgesWithNewBeta);
 
 
+       // THIS IS A HACK--NEED TO CHANGE GENERATATION OF BETA-NEW SO THIS DOESN'T
+       // HAPPEN OTHERWISE PROPAGATION FAILS
+       if( edgeY.getBetaNew().equals( new ReachabilitySet().makeCanonical() ) ) {
+         edgeY.setBetaNew( new ReachabilitySet( new TokenTupleSet().makeCanonical() ).makeCanonical() );
+       }
+       
 
-       //System.out.println( edgeY.getBetaNew() + "\nbeing pruned by\n" + hrnX.getAlpha() );
+
+       /*
+       System.out.println( "---------------------------\n" +
+                           edgeY.getBetaNew() + 
+                           "\nbeing pruned by\n" + 
+                           hrnX.getAlpha() + 
+                           "\nis\n" + 
+                           edgeY.getBetaNew().pruneBy(hrnX.getAlpha())
+                           );
+       */
 
        // create the actual reference edge hrnX.f -> hrnY
        ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
@@ -539,7 +560,8 @@ public class OwnershipGraph {
 
     ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
                                                               true,
-                                                              TokenTuple.ARITY_ONE) );
+                                                              TokenTuple.ARITY_ONE).makeCanonical()
+                                              ).makeCanonical();
 
     // heap regions for parameters are always multiple object (see above)
     // and have a reference to themselves, because we can't know the
@@ -693,13 +715,15 @@ public class OwnershipGraph {
 
     // after tokens have been aged, reset newest node's reachability
     if( hrn0.isFlagged() ) {
-      hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet(
-                                          new TokenTuple(hrn0)
-                                          )
+      hrn0.setAlpha(new ReachabilitySet(
+                                       new TokenTupleSet(
+                                                         new TokenTuple(hrn0).makeCanonical()
+                                                         ).makeCanonical()
                                         ).makeCanonical()
                     );
     } else {
-      hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet()
+      hrn0.setAlpha(new ReachabilitySet(
+                                       new TokenTupleSet().makeCanonical()
                                         ).makeCanonical()
                     );
     }
@@ -898,6 +922,9 @@ public class OwnershipGraph {
     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
       new Hashtable<Integer, ReachabilitySet>();
 
+    Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
+      new Hashtable<Integer, ReachabilitySet>();
+
     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
       new Hashtable<Integer, ReachabilitySet>();
 
@@ -908,10 +935,10 @@ public class OwnershipGraph {
     Hashtable<Integer, TokenTuple> paramIndex2paramToken =
       new Hashtable<Integer, TokenTuple>();
 
-    Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex =
+    Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex =
       new Hashtable<TokenTuple, Integer>();
 
-    Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar =
+    Hashtable<Integer, TokenTuple> paramIndex2paramTokenPlus =
       new Hashtable<Integer, TokenTuple>();
 
     Hashtable<Integer, LabelNode> paramIndex2ln =
@@ -925,17 +952,19 @@ public class OwnershipGraph {
     // of new callee nodes and edges, doesn't belong to any parameter
     Integer bogusID = new Integer(-1);
     Integer bogusIndex = new Integer(-1);
-    TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE);
-    TokenTuple bogusTokenStar = new TokenTuple(bogusID, true, TokenTuple.ARITY_MANY);
+    TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE).makeCanonical();
+    TokenTuple bogusTokenPlus = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONEORMORE).makeCanonical();
     ReachabilitySet rsIdentity =
-      new ReachabilitySet(new TokenTupleSet(bogusToken).makeCanonical() ).makeCanonical();
+      new ReachabilitySet(
+                         new TokenTupleSet(bogusToken).makeCanonical()
+                         ).makeCanonical();
 
     paramIndex2rewriteH.put(bogusIndex, rsIdentity);
     paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
     paramToken2paramIndex.put(bogusToken, bogusIndex);
     paramIndex2paramToken.put(bogusIndex, bogusToken);
-    paramTokenStar2paramIndex.put(bogusTokenStar, bogusIndex);
-    paramIndex2paramTokenStar.put(bogusIndex, bogusTokenStar);
+    paramTokenPlus2paramIndex.put(bogusTokenPlus, bogusIndex);
+    paramIndex2paramTokenPlus.put(bogusIndex, bogusTokenPlus);
 
 
     for( int i = 0; i < fm.numParameters(); ++i ) {
@@ -974,11 +1003,11 @@ public class OwnershipGraph {
       paramToken2paramIndex.put(p_i, paramIndex);
       paramIndex2paramToken.put(paramIndex, p_i);
 
-      TokenTuple p_i_star = new TokenTuple(hrnParam.getID(),
+      TokenTuple p_i_plus = new TokenTuple(hrnParam.getID(),
                                            true,
-                                           TokenTuple.ARITY_MANY).makeCanonical();
-      paramTokenStar2paramIndex.put(p_i_star, paramIndex);
-      paramIndex2paramTokenStar.put(paramIndex, p_i_star);
+                                           TokenTuple.ARITY_ONEORMORE).makeCanonical();
+      paramTokenPlus2paramIndex.put(p_i_plus, paramIndex);
+      paramIndex2paramTokenPlus.put(paramIndex, p_i_plus);
 
       // now depending on whether the callee is static or not
       // we need to account for a "this" argument in order to
@@ -987,7 +1016,7 @@ public class OwnershipGraph {
       if( isStatic ) {
        argTemp_i = fc.getArg(paramIndex);
       } else {
-       if( paramIndex == 0 ) {
+       if( paramIndex.equals( 0 ) ) {
          argTemp_i = fc.getThis();
        } else {
          argTemp_i = fc.getArg(paramIndex - 1);
@@ -1005,13 +1034,15 @@ public class OwnershipGraph {
       LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
       paramIndex2ln.put(paramIndex, argLabel_i);
 
-      ReachabilitySet D_i = new ReachabilitySet().makeCanonical();
+      ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
       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();
+      paramIndex2rewrite_d.put(paramIndex, d_i);
+
+      ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
       paramIndex2rewriteD.put(paramIndex, D_i);
     }
 
@@ -1064,13 +1095,17 @@ public class OwnershipGraph {
       while( hrnItr.hasNext() ) {
        HeapRegionNode hrn = hrnItr.next();
 
-       rewriteCallerNodeAlpha(fm.numParameters(),
-                              index,
-                              hrn,
-                              paramIndex2rewriteH,
-                              paramIndex2rewriteD,
-                              paramIndex2paramToken,
-                              paramIndex2paramTokenStar);
+       rewriteCallerReachability(index,
+                                 hrn,
+                                 null,
+                                 paramIndex2rewriteH.get(index),
+                                 paramIndex2rewrite_d,
+                                 paramIndex2rewriteD,
+                                 paramIndex2paramToken.get(index),
+                                 paramToken2paramIndex,
+                                 paramTokenPlus2paramIndex,
+                                 false,
+                                 null);
 
        nodesWithNewAlpha.add(hrn);
 
@@ -1104,43 +1139,45 @@ public class OwnershipGraph {
        }
       }
 
-
       // update reachable edges
       Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
       while( edgeReachableItr.hasNext() ) {
        ReferenceEdge edgeReachable = edgeReachableItr.next();
 
-       rewriteCallerEdgeBeta(fm.numParameters(),
-                             index,
-                             edgeReachable,
-                             paramIndex2rewriteJ,
-                             paramIndex2rewriteD,
-                             paramIndex2paramToken,
-                             paramIndex2paramTokenStar,
-                             false,
-                             null);
+       rewriteCallerReachability(index,
+                                 null,
+                                 edgeReachable,
+                                 paramIndex2rewriteJ.get(index),
+                                 paramIndex2rewrite_d,
+                                 paramIndex2rewriteD,
+                                 paramIndex2paramToken.get(index),
+                                 paramToken2paramIndex,
+                                 paramTokenPlus2paramIndex,
+                                 false,
+                                 null);
 
        edgesWithNewBeta.add(edgeReachable);
       }
 
-
       // update upstream edges
-      Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges
-      = new Hashtable<ReferenceEdge, ChangeTupleSet>();
+      Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
+       new Hashtable<ReferenceEdge, ChangeTupleSet>();
 
       Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
       while( edgeUpstreamItr.hasNext() ) {
        ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
 
-       rewriteCallerEdgeBeta(fm.numParameters(),
-                             index,
-                             edgeUpstream,
-                             paramIndex2rewriteK,
-                             paramIndex2rewriteD,
-                             paramIndex2paramToken,
-                             paramIndex2paramTokenStar,
-                             true,
-                             edgeUpstreamPlannedChanges);
+       rewriteCallerReachability(index,
+                                 null,
+                                 edgeUpstream,
+                                 paramIndex2rewriteK.get(index),
+                                 paramIndex2rewrite_d,
+                                 paramIndex2rewriteD,
+                                 paramIndex2paramToken.get(index),
+                                 paramToken2paramIndex,
+                                 paramTokenPlus2paramIndex,
+                                 true,
+                                 edgeUpstreamPlannedChanges);
 
        edgesWithNewBeta.add(edgeUpstream);
       }
@@ -1163,7 +1200,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
@@ -1190,13 +1226,17 @@ public class OwnershipGraph {
       // so rewrite and immediately commit--and they don't belong
       // to a particular parameter, so use a bogus param index
       // that pulls a self-rewrite out of H
-      rewriteCallerNodeAlpha(fm.numParameters(),
-                             bogusIndex,
-                             hrnShadowSummary,
-                             paramIndex2rewriteH,
-                             paramIndex2rewriteD,
-                             paramIndex2paramToken,
-                             paramIndex2paramTokenStar);
+      rewriteCallerReachability(bogusIndex,
+                               hrnShadowSummary,
+                               null,
+                               hrnShadowSummary.getAlpha(),
+                               paramIndex2rewrite_d,
+                               paramIndex2rewriteD,
+                               bogusToken,
+                               paramToken2paramIndex,
+                               paramTokenPlus2paramIndex,
+                               false,
+                               null);
 
       hrnShadowSummary.applyAlphaNew();
 
@@ -1218,13 +1258,17 @@ public class OwnershipGraph {
        HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
        hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
 
-       rewriteCallerNodeAlpha(fm.numParameters(),
-                              bogusIndex,
-                              hrnIthShadow,
-                              paramIndex2rewriteH,
-                              paramIndex2rewriteD,
-                              paramIndex2paramToken,
-                              paramIndex2paramTokenStar);
+       rewriteCallerReachability(bogusIndex,
+                                 hrnIthShadow,
+                                 null,
+                                 hrnIthShadow.getAlpha(),
+                                 paramIndex2rewrite_d,
+                                 paramIndex2rewriteD,
+                                 bogusToken,
+                                 paramToken2paramIndex,
+                                 paramTokenPlus2paramIndex,
+                                 false,
+                                 null);
 
        hrnIthShadow.applyAlphaNew();
       }
@@ -1264,17 +1308,20 @@ public class OwnershipGraph {
                                                                    null,
                                                                    edgeCallee.getFieldDesc(),
                                                                    false,
-                                                                   toShadowTokens(ogCallee, edgeCallee.getBeta() )
+                                                                   toShadowTokens(ogCallee,
+                                                                                  edgeCallee.getBeta() )
                                                                    );
-         rewriteCallerEdgeBeta(fm.numParameters(),
-                               bogusIndex,
-                               edgeNewInCallerTemplate,
-                               paramIndex2rewriteJ,
-                               paramIndex2rewriteD,
-                               paramIndex2paramToken,
-                               paramIndex2paramTokenStar,
-                               false,
-                               null);
+         rewriteCallerReachability(bogusIndex,
+                                   null,
+                                   edgeNewInCallerTemplate,
+                                   edgeNewInCallerTemplate.getBeta(),
+                                   paramIndex2rewrite_d,
+                                   paramIndex2rewriteD,
+                                   bogusToken,
+                                   paramToken2paramIndex,
+                                   paramTokenPlus2paramIndex,
+                                   false,
+                                   null);
 
          edgeNewInCallerTemplate.applyBetaNew();
 
@@ -1298,47 +1345,18 @@ public class OwnershipGraph {
          while( srcItr.hasNext() ) {
            HeapRegionNode src = (HeapRegionNode) srcItr.next();
 
-           // check that if this source node has a definite type that
-           // it also has the appropriate field, otherwise prune this
-           AllocationSite asSrc = src.getAllocationSite();
-           if( asSrc != null ) {
-             boolean foundField = false;
-             TypeDescriptor tdSrc = asSrc.getType();
-             if( tdSrc != null && tdSrc.isClass() ) {
-               Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
-               while( fieldsSrcItr.hasNext() ) {
-                 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
-                 if( fd == edgeCallee.getFieldDesc() ) {
-                   foundField = true;
-                   break;
-                 }
-               }
-               if( !foundField ) {
-                 // prune this source node possibility
-                 continue;
-               }
-             }
+           if( !hasMatchingField(src, edgeCallee) ) {
+             // prune this source node possibility
+             continue;
            }
 
            Iterator dstItr = possibleCallerDsts.iterator();
            while( dstItr.hasNext() ) {
              HeapRegionNode dst = (HeapRegionNode) dstItr.next();
 
-             // check if this dst node has a definite type and
-             // if it matches the callee edge
-             AllocationSite asDst = dst.getAllocationSite();
-             if( asDst != null && edgeCallee.getFieldDesc() != null ) {
-               if( asDst.getType() == null && edgeCallee.getFieldDesc().getType() != null ) {
-                 continue;
-               }
-               if( asDst.getType() != null && edgeCallee.getFieldDesc().getType() == null ) {
-                 continue;
-               }
-               if( asDst.getType() != null && edgeCallee.getFieldDesc().getType() != null ) {
-                 if( !asDst.getType().equals(edgeCallee.getFieldDesc().getType() ) ) {
-                   continue;
-                 }
-               }
+             if( !hasMatchingType(edgeCallee, dst) ) {
+               // prune
+               continue;
              }
 
              // otherwise the caller src and dst pair can match the edge, so make it
@@ -1361,11 +1379,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);
@@ -1377,17 +1395,20 @@ public class OwnershipGraph {
                                                                  null,
                                                                  edgeCallee.getFieldDesc(),
                                                                  false,
-                                                                 toShadowTokens(ogCallee, edgeCallee.getBeta() )
+                                                                 toShadowTokens(ogCallee,
+                                                                                edgeCallee.getBeta() )
                                                                  );
-       rewriteCallerEdgeBeta(fm.numParameters(),
-                             bogusIndex,
-                             edgeNewInCallerTemplate,
-                             paramIndex2rewriteJ,
-                             paramIndex2rewriteD,
-                             paramIndex2paramToken,
-                             paramIndex2paramTokenStar,
-                             false,
-                             null);
+       rewriteCallerReachability(bogusIndex,
+                                 null,
+                                 edgeNewInCallerTemplate,
+                                 edgeNewInCallerTemplate.getBeta(),
+                                 paramIndex2rewrite_d,
+                                 paramIndex2rewriteD,
+                                 bogusToken,
+                                 paramToken2paramIndex,
+                                 paramTokenPlus2paramIndex,
+                                 false,
+                                 null);
 
        edgeNewInCallerTemplate.applyBetaNew();
 
@@ -1401,23 +1422,9 @@ public class OwnershipGraph {
        while( itrHrn.hasNext() ) {
          HeapRegionNode hrnCaller = itrHrn.next();
 
-         // check if this dst node has a definite type and
-         // if it matches the callee edge
-         // check if this dst node has a definite type and
-         // if it matches the callee edge
-         AllocationSite asDst = hrnCaller.getAllocationSite();
-         if( asDst != null && edgeCallee.getFieldDesc() != null ) {
-           if( asDst.getType() == null && edgeCallee.getFieldDesc().getType() != null ) {
-             continue;
-           }
-           if( asDst.getType() != null && edgeCallee.getFieldDesc().getType() == null ) {
-             continue;
-           }
-           if( asDst.getType() != null && edgeCallee.getFieldDesc().getType() != null ) {
-             if( !asDst.getType().equals(edgeCallee.getFieldDesc().getType() ) ) {
-               continue;
-             }
-           }
+         if( !hasMatchingType(edgeCallee, hrnCaller) ) {
+           // prune
+           continue;
          }
 
          // otherwise caller node can match callee edge, so make it
@@ -1427,6 +1434,7 @@ public class OwnershipGraph {
 
          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 {
@@ -1438,7 +1446,6 @@ public class OwnershipGraph {
     }
 
 
-
     // merge the shadow nodes of allocation sites back down to normal capacity
     Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
     while( allocItr.hasNext() ) {
@@ -1508,6 +1515,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) );
   }
@@ -1520,7 +1588,7 @@ public class OwnershipGraph {
   private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
                                          ReachabilitySet rsIn) {
 
-    ReachabilitySet rsOut = new ReachabilitySet(rsIn);
+    ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
 
     Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
     while( allocItr.hasNext() ) {
@@ -1533,198 +1601,165 @@ public class OwnershipGraph {
   }
 
 
-  private void rewriteCallerNodeAlpha(int numParameters,
-                                      Integer paramIndex,
-                                      HeapRegionNode hrn,
-                                      Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH,
-                                      Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
-                                      Hashtable<Integer, TokenTuple> paramIndex2paramToken,
-                                      Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
+  private void rewriteCallerReachability(Integer paramIndex,
+                                        HeapRegionNode hrn,
+                                        ReferenceEdge edge,
+                                        ReachabilitySet rules,
+                                        Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
+                                        Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
+                                        TokenTuple p_i,
+                                        Hashtable<TokenTuple, Integer> paramToken2paramIndex,
+                                        Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
+                                        boolean makeChangeSet,
+                                        Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
+    assert (hrn == null && edge != null) || 
+           (hrn != null && edge == null);
 
-    ReachabilitySet rules = paramIndex2rewriteH.get(paramIndex);
     assert rules != null;
+    assert p_i != null;
 
-    TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
-    assert tokenToRewrite != null;
-
-    ReachabilitySet r0 = new ReachabilitySet().makeCanonical();
-    Iterator<TokenTupleSet> ttsItr = rules.iterator();
-    while( ttsItr.hasNext() ) {
-      TokenTupleSet tts = ttsItr.next();
-      r0 = r0.union(tts.rewriteToken(tokenToRewrite,
-                                     hrn.getAlpha(),
-                                     false,
-                                     null) );
+    ReachabilitySet callerReachabilityCurrent;
+    if( hrn == null ) {
+      callerReachabilityCurrent = edge.getBeta();
+    } else {
+      callerReachabilityCurrent = hrn.getAlpha();
     }
 
-    ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
-    ttsItr = r0.iterator();
-    while( ttsItr.hasNext() ) {
-      TokenTupleSet tts = ttsItr.next();
-      r1 = r1.union(rewriteDpass(numParameters,
-                                 paramIndex,
-                                 tts,
-                                 paramIndex2rewriteD,
-                                 paramIndex2paramToken,
-                                 paramIndex2paramTokenStar) );
-    }
+    ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
 
-    hrn.setAlphaNew(hrn.getAlphaNew().union(r1) );
-  }
+    // for initializing structures in this method
+    TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
 
+    // use this to construct a change set if required; the idea is to
+    // map every partially rewritten token tuple set to the set of 
+    // caller-context token tuple sets that were used to generate it
+    Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
+      new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
+    rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
 
-  private void rewriteCallerEdgeBeta(int numParameters,
-                                     Integer paramIndex,
-                                     ReferenceEdge edge,
-                                     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJorK,
-                                     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
-                                     Hashtable<Integer, TokenTuple> paramIndex2paramToken,
-                                     Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar,
-                                     boolean makeChangeSet,
-                                     Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
 
-    ReachabilitySet rules = paramIndex2rewriteJorK.get(paramIndex);
-    assert rules != null;
+    Iterator<TokenTupleSet> rulesItr = rules.iterator();
+    while(rulesItr.hasNext()) {
+      TokenTupleSet rule = rulesItr.next();
 
-    TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
-    assert tokenToRewrite != null;
+      ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
 
-    ChangeTupleSet cts0 = new ChangeTupleSet().makeCanonical();
+      Iterator<TokenTuple> ruleItr = rule.iterator();
+      while(ruleItr.hasNext()) {
+       TokenTuple ttCallee = ruleItr.next();
 
-    Iterator<TokenTupleSet> ttsItr = rules.iterator();
-    while( ttsItr.hasNext() ) {
-      TokenTupleSet tts = ttsItr.next();
+       // compute the possibilities for rewriting this callee token
+       ReachabilitySet ttCalleeRewrites = null;
+       boolean callerSourceUsed = false;
 
-      Hashtable<TokenTupleSet, TokenTupleSet> forChangeSet =
-        new Hashtable<TokenTupleSet, TokenTupleSet>();
+       if( ttCallee.equals( p_i ) ) {
+         // replace the arity-one token of the current parameter with the reachability
+         // information from the caller edge
+         ttCalleeRewrites = callerReachabilityCurrent;
+         callerSourceUsed = true;
+         
+       } else if( paramToken2paramIndex.containsKey( ttCallee ) ) {
+         // use little d
+         Integer paramIndex_j = paramToken2paramIndex.get( ttCallee );
+         assert paramIndex_j != null;
+         ttCalleeRewrites = paramIndex2rewrite_d.get( paramIndex_j );
+         assert ttCalleeRewrites != null;
 
-      ReachabilitySet rTemp = tts.rewriteToken(tokenToRewrite,
-                                               edge.getBeta(),
-                                               true,
-                                               forChangeSet);
+       } else if( paramTokenPlus2paramIndex.containsKey( ttCallee ) ) {
+         // worse, use big D
+         Integer paramIndex_j = paramTokenPlus2paramIndex.get( ttCallee );
+         assert paramIndex_j != null;
+         ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
+         assert ttCalleeRewrites != null;
 
-      Iterator fcsItr = forChangeSet.entrySet().iterator();
-      while( fcsItr.hasNext() ) {
-       Map.Entry me = (Map.Entry)fcsItr.next();
-       TokenTupleSet ttsMatch = (TokenTupleSet) me.getKey();
-       TokenTupleSet ttsAdd   = (TokenTupleSet) me.getValue();
+       } else {
+         // otherwise there's no need for a rewrite, just pass this one on
+         TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
+         ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
+       }
+       
+       // branch every version of the working rewritten rule with 
+       // the possibilities for rewriting the current callee token
+       ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
+
+       Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
+       while( rewrittenRuleItr.hasNext() ) {
+         TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
+
+         Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
+         while( ttCalleeRewritesItr.hasNext() ) {
+           TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
+
+           TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
+
+           if( makeChangeSet ) {
+             // in order to keep the list of source token tuple sets
+             // start with the sets used to make the partially rewritten
+             // rule up to this point
+             HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
+             assert sourceSets != null;
+
+             // make a shallow copy for possible modification
+             sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
+
+             // if we used something from the caller to rewrite it, remember
+             if( callerSourceUsed ) {
+               sourceSets.add( ttsBranch );
+             }
 
-       ChangeTuple ct = new ChangeTuple(ttsMatch,
-                                        ttsAdd
-                                        ).makeCanonical();
+             // set mapping for the further rewritten rule
+             rewritten2source.put( ttsRewrittenNext, sourceSets );
+           }
+         
+           rewrittenRuleWithTTCallee = 
+             rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
+         }
+       }
 
-       cts0 = cts0.union(ct);
+       // now the rewritten rule's possibilities have been extended by
+       // rewriting the current callee token, remember result
+       rewrittenRule = rewrittenRuleWithTTCallee;
       }
-    }
-
-
-    ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
-    ChangeTupleSet cts1 = new ChangeTupleSet().makeCanonical();
-
-    Iterator<ChangeTuple> ctItr = cts0.iterator();
-    while( ctItr.hasNext() ) {
-      ChangeTuple ct = ctItr.next();
-
-      ReachabilitySet rTemp = rewriteDpass(numParameters,
-                                           paramIndex,
-                                           ct.getSetToAdd(),
-                                           paramIndex2rewriteD,
-                                           paramIndex2paramToken,
-                                           paramIndex2paramTokenStar
-                                           ).makeCanonical();
-      r1 = r1.union(rTemp);
 
-      if( makeChangeSet ) {
-       assert edgePlannedChanges != null;
-
-       Iterator<TokenTupleSet> ttsTempItr = rTemp.iterator();
-       while( ttsTempItr.hasNext() ) {
-         TokenTupleSet tts = ttsTempItr.next();
-
-         ChangeTuple ctFinal = new ChangeTuple(ct.getSetToMatch(),
-                                               tts
-                                               ).makeCanonical();
-
-         cts1 = cts1.union(ctFinal);
-       }
-      }
+      // the rule has been entirely rewritten into the caller context
+      // now, so add it to the new reachability information
+      callerReachabilityNew =
+       callerReachabilityNew.union( rewrittenRule );
     }
 
     if( makeChangeSet ) {
-      edgePlannedChanges.put(edge, cts1);
-    }
-
-    edge.setBetaNew(edge.getBetaNew().union(r1) );
-  }
-
-
-  private ReachabilitySet rewriteDpass(int numParameters,
-                                       Integer paramIndex,
-                                       TokenTupleSet ttsIn,
-                                       Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
-                                       Hashtable<Integer, TokenTuple> paramIndex2paramToken,
-                                       Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
-
-    ReachabilitySet rsOut = new ReachabilitySet().makeCanonical();
-
-    boolean rewritten = false;
-
-    for( int j = 0; j < numParameters; ++j ) {
-      Integer paramIndexJ = new Integer(j);
-      ReachabilitySet D_j = paramIndex2rewriteD.get(paramIndexJ);
-      assert D_j != null;
-
-      if( paramIndexJ != paramIndex ) {
-       TokenTuple tokenToRewriteJ = paramIndex2paramToken.get(paramIndexJ);
-       assert tokenToRewriteJ != null;
-       if( ttsIn.containsTuple(tokenToRewriteJ) ) {
-         ReachabilitySet r = ttsIn.rewriteToken(tokenToRewriteJ,
-                                                D_j,
-                                                false,
-                                                null);
-         Iterator<TokenTupleSet> ttsItr = r.iterator();
-         while( ttsItr.hasNext() ) {
-           TokenTupleSet tts = ttsItr.next();
-           rsOut = rsOut.union(rewriteDpass(numParameters,
-                                            paramIndex,
-                                            tts,
-                                            paramIndex2rewriteD,
-                                            paramIndex2paramToken,
-                                            paramIndex2paramTokenStar) );
-           rewritten = true;
-         }
+      ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
+      
+      // each possibility for the final reachability should have a set of
+      // caller sources mapped to it, use to create the change set
+      Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
+      while( callerReachabilityItr.hasNext() ) {
+       TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
+       HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
+       assert sourceSets != null;
+
+       Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
+       while( sourceSetsItr.hasNext() ) {
+         TokenTupleSet ttsSource = sourceSetsItr.next();      
+
+         callerChangeSet =
+           callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
        }
       }
 
-      TokenTuple tokenStarToRewriteJ = paramIndex2paramTokenStar.get(paramIndexJ);
-      assert tokenStarToRewriteJ != null;
-      if( ttsIn.containsTuple(tokenStarToRewriteJ) ) {
-       ReachabilitySet r = ttsIn.rewriteToken(tokenStarToRewriteJ,
-                                              D_j,
-                                              false,
-                                              null);
-       Iterator<TokenTupleSet> ttsItr = r.iterator();
-       while( ttsItr.hasNext() ) {
-         TokenTupleSet tts = ttsItr.next();
-         rsOut = rsOut.union(rewriteDpass(numParameters,
-                                          paramIndex,
-                                          tts,
-                                          paramIndex2rewriteD,
-                                          paramIndex2paramToken,
-                                          paramIndex2paramTokenStar) );
-         rewritten = true;
-       }
-      }
+      assert edgePlannedChanges != null;
+      edgePlannedChanges.put(edge, callerChangeSet);
     }
 
-    if( !rewritten ) {
-      rsOut = rsOut.union(ttsIn);
+    if( hrn == null ) {
+      edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
+    } else {
+      hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
     }
-
-    return rsOut;
   }
 
 
+
   private HashSet<HeapRegionNode>
   getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
                                       HeapRegionNode hrnCallee,
@@ -2231,9 +2266,13 @@ public class OwnershipGraph {
                                    true,
                                    TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple pPlus1 = new TokenTuple(hrnParam1.getID(),
+                                       true,
+                                       TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
                                        true,
-                                       TokenTuple.ARITY_MANY).makeCanonical();
+                                       TokenTuple.ARITY_ZEROORMORE).makeCanonical();
 
 
     // get tokens for the other parameter
@@ -2248,9 +2287,13 @@ public class OwnershipGraph {
                                    true,
                                    TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple pPlus2 = new TokenTuple(hrnParam2.getID(),
+                                       true,
+                                       TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
                                        true,
-                                       TokenTuple.ARITY_MANY).makeCanonical();
+                                       TokenTuple.ARITY_ZEROORMORE).makeCanonical();
 
 
     // get special label p_q for first parameter
@@ -2268,18 +2311,15 @@ public class OwnershipGraph {
     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;
-    }
+    if( beta1.containsTupleSetWithBoth(p1,     p2    ) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pPlus1, p2    ) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pStar1, p2    ) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(p1,     pPlus2) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pPlus1, pPlus2) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pStar1, pPlus2) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(p1,     pStar2) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pPlus1, pStar2) ) { return true; }
+    if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) { return true; }
 
     return false;
   }
@@ -2300,9 +2340,13 @@ public class OwnershipGraph {
                                   true,
                                   TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple pPlus = new TokenTuple(hrnParam.getID(),
+                                      true,
+                                      TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple pStar = new TokenTuple(hrnParam.getID(),
                                       true,
-                                      TokenTuple.ARITY_MANY).makeCanonical();
+                                      TokenTuple.ARITY_ZEROORMORE).makeCanonical();
 
     // get special label p_q
     TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
@@ -2324,37 +2368,43 @@ public class OwnershipGraph {
                                    true,
                                    TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple gsPlus = new TokenTuple(as.getSummary(),
+                                       true,
+                                       TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple gsStar = new TokenTuple(as.getSummary(),
                                        true,
-                                       TokenTuple.ARITY_MANY).makeCanonical();
+                                       TokenTuple.ARITY_ZEROORMORE).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;
-    }
+
+    if( beta.containsTupleSetWithBoth(p,     gs    ) ) { return true; }
+    if( beta.containsTupleSetWithBoth(pPlus, gs    ) ) { return true; }
+    if( beta.containsTupleSetWithBoth(pStar, gs    ) ) { return true; }
+    if( beta.containsTupleSetWithBoth(p,     gsPlus) ) { return true; }
+    if( beta.containsTupleSetWithBoth(pPlus, gsPlus) ) { return true; }
+    if( beta.containsTupleSetWithBoth(pStar, gsPlus) ) { return true; }
+    if( beta.containsTupleSetWithBoth(p,     gsStar) ) { return true; }
+    if( beta.containsTupleSetWithBoth(pPlus, 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
+      // the other nodes of an allocation site are single, no plus
       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;
-      }
+      TokenTuple giStar = new TokenTuple(as.getIthOldest(i),
+                                        false,
+                                        TokenTuple.ARITY_ZEROORMORE).makeCanonical();
+
+      if( beta.containsTupleSetWithBoth(p,     gi    ) ) { return true; }
+      if( beta.containsTupleSetWithBoth(pPlus, gi    ) ) { return true; }
+      if( beta.containsTupleSetWithBoth(pStar, gi    ) ) { return true; }
+      if( beta.containsTupleSetWithBoth(p,     giStar) ) { return true; }
+      if( beta.containsTupleSetWithBoth(pPlus, giStar) ) { return true; }
+      if( beta.containsTupleSetWithBoth(pStar, giStar) ) { return true; }
     }
 
     return false;
@@ -2368,9 +2418,13 @@ public class OwnershipGraph {
                                     true,
                                     TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple gsPlus1 = new TokenTuple(as1.getSummary(),
+                                        true,
+                                        TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
                                         true,
-                                        TokenTuple.ARITY_MANY).makeCanonical();
+                                        TokenTuple.ARITY_ZEROORMORE).makeCanonical();
 
     // get summary node's alpha
     Integer idSum1 = as1.getSummary();
@@ -2386,9 +2440,13 @@ public class OwnershipGraph {
                                     true,
                                     TokenTuple.ARITY_ONE).makeCanonical();
 
+    TokenTuple gsPlus2 = new TokenTuple(as2.getSummary(),
+                                        true,
+                                        TokenTuple.ARITY_ONEORMORE).makeCanonical();
+
     TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
                                         true,
-                                        TokenTuple.ARITY_MANY).makeCanonical();
+                                        TokenTuple.ARITY_ZEROORMORE).makeCanonical();
 
     // get summary node's alpha
     Integer idSum2 = as2.getSummary();
@@ -2399,21 +2457,15 @@ public class OwnershipGraph {
     assert alphaSum2 != null;
 
     // does either one report reachability from the other tokens?
-    if( alphaSum1.containsTuple(gsStar2) ) {
-      return true;
-    }
-    if( alphaSum2.containsTuple(gsStar1) ) {
-      return true;
-    }
+    if( alphaSum1.containsTuple(gsPlus2) ) { return true; }
+    if( alphaSum1.containsTuple(gsStar2) ) { return true; }
+    if( alphaSum2.containsTuple(gsPlus1) ) { return true; }
+    if( alphaSum2.containsTuple(gsStar1) ) { return true; }
 
-    // only check non-star token if they are different sites
+    // only check ONE token if they are different sites
     if( as1 != as2 ) {
-      if( alphaSum1.containsTuple(gs2) ) {
-       return true;
-      }
-      if( alphaSum2.containsTuple(gs1) ) {
-       return true;
-      }
+      if( alphaSum1.containsTuple(gs2) ) { return true; }
+      if( alphaSum2.containsTuple(gs1) ) { return true; }
     }
 
 
@@ -2431,15 +2483,15 @@ public class OwnershipGraph {
                                       false,
                                       TokenTuple.ARITY_ONE).makeCanonical();
 
-      if( alphaSum2.containsTuple(gi1) ) {
-       return true;
-      }
-      if( alphaI1.containsTuple(gs2) ) {
-       return true;
-      }
-      if( alphaI1.containsTuple(gsStar2) ) {
-       return true;
-      }
+      TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(i),
+                                         false,
+                                         TokenTuple.ARITY_ZEROORMORE).makeCanonical();
+
+      if( alphaSum2.containsTuple(gi1    ) ) { return true; }
+      if( alphaSum2.containsTuple(giStar1) ) { return true; }
+      if(   alphaI1.containsTuple(gs2    ) ) { return true; }
+      if(   alphaI1.containsTuple(gsPlus2) ) { return true; }
+      if(   alphaI1.containsTuple(gsStar2) ) { return true; }
     }
 
     // check sum1 against alloc2 nodes
@@ -2455,21 +2507,21 @@ public class OwnershipGraph {
                                       false,
                                       TokenTuple.ARITY_ONE).makeCanonical();
 
-      if( alphaSum1.containsTuple(gi2) ) {
-       return true;
-      }
-      if( alphaI2.containsTuple(gs1) ) {
-       return true;
-      }
-      if( alphaI2.containsTuple(gsStar1) ) {
-       return true;
-      }
+      TokenTuple giStar2 = new TokenTuple(as2.getIthOldest(i),
+                                         false,
+                                         TokenTuple.ARITY_ZEROORMORE).makeCanonical();
+
+      if( alphaSum1.containsTuple(gi2    ) ) { return true; }
+      if( alphaSum1.containsTuple(giStar2) ) { return true; }
+      if(   alphaI2.containsTuple(gs1    ) ) { return true; }
+      if(   alphaI2.containsTuple(gsPlus1) ) { 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
+       // 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;
@@ -2480,12 +2532,15 @@ public class OwnershipGraph {
        TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
                                        false,
                                        TokenTuple.ARITY_ONE).makeCanonical();
-       if( alphaI2.containsTuple(gi1) ) {
-         return true;
-       }
-       if( alphaI1.containsTuple(gi2) ) {
-         return true;
-       }
+
+       TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(j),
+                                           false,
+                                           TokenTuple.ARITY_ZEROORMORE).makeCanonical();
+
+       if( alphaI2.containsTuple(gi1    ) ) { return true; }
+       if( alphaI2.containsTuple(giStar1) ) { return true; }
+       if( alphaI1.containsTuple(gi2    ) ) { return true; }
+       if( alphaI1.containsTuple(giStar2) ) { return true; }
       }
     }
 
@@ -2499,7 +2554,8 @@ public class OwnershipGraph {
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
     writeGraph(
       methodDesc.getSymbol() +
@@ -2508,7 +2564,8 @@ public class OwnershipGraph {
       writeLabels,
       labelSelect,
       pruneGarbage,
-      writeReferencers
+      writeReferencers,
+      writeParamMappings
       );
   }
 
@@ -2516,14 +2573,16 @@ public class OwnershipGraph {
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
 
     writeGraph(methodDesc+"COMPLETE",
                writeLabels,
                labelSelect,
                pruneGarbage,
-               writeReferencers
+               writeReferencers,
+              writeParamMappings
                );
   }
 
@@ -2532,14 +2591,16 @@ public class OwnershipGraph {
                          boolean writeLabels,
                          boolean labelSelect,
                          boolean pruneGarbage,
-                         boolean writeReferencers
+                         boolean writeReferencers,
+                        boolean writeParamMappings
                          ) throws java.io.IOException {
 
     writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
                writeLabels,
                labelSelect,
                pruneGarbage,
-               writeReferencers
+               writeReferencers,
+              writeParamMappings
                );
   }
 
@@ -2547,7 +2608,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
@@ -2556,43 +2618,48 @@ 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>();
 
     // then visit every heap region node
-    if( !pruneGarbage ) {
-      Set s = id2hrn.entrySet();
-      Iterator i = s.iterator();
-      while( i.hasNext() ) {
-       Map.Entry me  = (Map.Entry)i.next();
-       HeapRegionNode hrn = (HeapRegionNode) me.getValue();
+    Set s = id2hrn.entrySet();
+    Iterator i = s.iterator();
+    while( i.hasNext() ) {
+      Map.Entry me  = (Map.Entry)i.next();
+      HeapRegionNode hrn = (HeapRegionNode) me.getValue();
+      if( !pruneGarbage ||
+         hrn.isFlagged() ||
+         hrn.getDescription().startsWith( "param" )
+       ) {
+       
        if( !visited.contains(hrn) ) {
          traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
-                                 hrn,
-                                 bw,
-                                 null,
-                                 visited,
-                                 writeReferencers);
+                                 hrn,
+                                 bw,
+                                 null,
+                                 visited,
+                                 writeReferencers);
        }
       }
     }
-
+    
     bw.write("  graphTitle[label=\""+graphName+"\",shape=box];\n");
 
-    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");
+    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 ) {
-      Set s = td2ln.entrySet();
-      Iterator i = s.iterator();
+      s = td2ln.entrySet();
+      i = s.iterator();
       while( i.hasNext() ) {
        Map.Entry me = (Map.Entry)i.next();
        LabelNode ln = (LabelNode) me.getValue();
@@ -2607,7 +2674,7 @@ public class OwnershipGraph {
          }
        }
 
-       bw.write(ln.toString() + ";\n");
+       //bw.write("  "+ln.toString() + ";\n");
 
        Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
        while( heapRegionsItr.hasNext() ) {