Committing a stable version of global sweep that works for simple strong updates...
authorjjenista <jjenista>
Wed, 8 Oct 2008 18:30:48 +0000 (18:30 +0000)
committerjjenista <jjenista>
Wed, 8 Oct 2008 18:30:48 +0000 (18:30 +0000)
Robust/src/Analysis/OwnershipAnalysis/OwnershipGraph.java
Robust/src/Analysis/OwnershipAnalysis/ReachabilitySet.java
Robust/src/Analysis/OwnershipAnalysis/TokenTupleSet.java
Robust/src/Tests/OwnershipAnalysisTest/test01/test01.java

index cd46e70888af017ae340a798f48d33044c8759c4..126f288615cf607b560daa1f28afd958fbdec132 100644 (file)
@@ -412,6 +412,8 @@ public class OwnershipGraph {
     HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
     HashSet<ReferenceEdge>  edgesWithNewBeta  = new HashSet<ReferenceEdge>();
 
+    boolean strongUpdate = false;
+
     Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
     while( itrXhrn.hasNext() ) {
       ReferenceEdge edgeX = itrXhrn.next();
@@ -456,29 +458,36 @@ public class OwnershipGraph {
        // if edgeY's beta was updated, use that to calculate beta for new edge
        // otherwise the edgeY didn't change and it is the source for the calc
        ReachabilitySet sourceBetaForNewEdge;
-       if( edgesWithNewBeta.contains( edgeY ) ) {
+       //if( edgesWithNewBeta.contains( edgeY ) ) {
+       if( !edgeY.getBetaNew().equals( new ReachabilitySet().makeCanonical() ) ) {
          sourceBetaForNewEdge = edgeY.getBetaNew();
        } else {
          sourceBetaForNewEdge = edgeY.getBeta();
        }
 
+       ReachabilitySet sourceAlphaForPrune;
+       if( !hrnX.getAlphaNew().equals( new ReachabilitySet().makeCanonical() ) ) {
+         sourceAlphaForPrune = hrnX.getAlphaNew();
+       } else {
+         sourceAlphaForPrune = hrnX.getAlpha();
+       }       
+
        // prepare the new reference edge hrnX.f -> hrnY
        ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
                                                  hrnY,
                                                  f,
                                                  false,
-                                                 sourceBetaForNewEdge.pruneBy(hrnX.getAlpha() )
+                                                 sourceBetaForNewEdge.pruneBy( sourceAlphaForPrune )
                                                  );
 
        // we can do a strong update here if one of two cases holds     
-       boolean strongUpdate = false;
        if( f != null &&
            (   (hrnX.getNumReferencers() == 1)                           ||
                ( lnX.getNumReferencees() == 1 && hrnX.isSingleObject() )
            )
          ) {
          strongUpdate = true;
-         //clearReferenceEdgesFrom( hrnX, f, false );
+         clearReferenceEdgesFrom( hrnX, f, false );
        }
 
        // look to see if an edge with same field exists
@@ -495,12 +504,6 @@ public class OwnershipGraph {
        } else {
          addReferenceEdge( hrnX, hrnY, edgeNew );
        }
-
-       // if it was a strong update, make sure to improve
-       // reachability with a global sweep
-       if( strongUpdate ) {
-         globalSweep();
-       }       
       }
     }
 
@@ -513,6 +516,16 @@ public class OwnershipGraph {
     while( edgeItr.hasNext() ) {
       edgeItr.next().applyBetaNew();
     }
+
+    // if it was a strong update, make sure to improve
+    // reachability with a global sweep
+    if( strongUpdate ) {      
+      //try {
+      //writeGraph( "testBefore", true, true, true, false, false );
+       globalSweep();
+       //writeGraph( "testPost", true, true, true, false, false );
+       //} catch( Exception e ) {}
+    }  
   }
 
 
@@ -1810,7 +1823,196 @@ public class OwnershipGraph {
   //
   ////////////////////////////////////////////////////
   protected void globalSweep() {
-    
+
+    // a work set for performing the sweep
+    Hashtable<HeapRegionNode, HashSet<TokenTupleSet> > workSet = 
+      new Hashtable<HeapRegionNode, HashSet<TokenTupleSet> >();
+
+    // first initialize every alphaNew for a flagged region to
+    // a set with just that token
+    Set hrns = id2hrn.entrySet();
+    Iterator itrHrns = hrns.iterator();
+    while( itrHrns.hasNext() ) {
+      Map.Entry me = (Map.Entry)itrHrns.next();
+      Integer token = (Integer) me.getKey();
+      HeapRegionNode hrn = (HeapRegionNode) me.getValue();
+
+      // assert that this node and incoming edges have clean alphaNew
+      // and betaNew sets, respectively
+      ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
+      //System.out.println( "hrn="+hrn );
+      //System.out.println( "alphaNew="+hrn.getAlphaNew() );
+      assert rsEmpty.equals( hrn.getAlphaNew() );
+
+      Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
+      while( itrRes.hasNext() ) {
+       ReferenceEdge edge = itrRes.next();
+       assert rsEmpty.equals( edge.getBetaNew() );
+      }      
+      
+      TokenTuple tt     = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONE        ).makeCanonical();
+      TokenTuple ttPlus = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONEORMORE  ).makeCanonical();
+      TokenTuple ttStar = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
+
+      TokenTupleSet tts      = new TokenTupleSet( tt     ).makeCanonical();
+      TokenTupleSet ttsPlus  = new TokenTupleSet( ttPlus ).makeCanonical();
+      TokenTupleSet ttsStar  = new TokenTupleSet( ttStar ).makeCanonical();
+      TokenTupleSet ttsEmpty = new TokenTupleSet(        ).makeCanonical();
+
+      if( hrn.isFlagged() ) {
+       HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
+       subWorkSet.add( tts     );
+       subWorkSet.add( ttsPlus );
+       subWorkSet.add( ttsStar );
+       workSet.put( hrn, subWorkSet );
+       
+       hrn.setAlphaNew( new ReachabilitySet( tts ).makeCanonical() );
+      } else {
+       hrn.setAlphaNew( new ReachabilitySet( ttsEmpty ).makeCanonical() );
+      }
+    }
+
+    // then propagate tokens forward one step at a time
+    while( !workSet.isEmpty() ) {
+      HeapRegionNode hrn = workSet.keySet().iterator().next();
+
+      HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
+      assert subWorkSet != null;
+      
+      if( subWorkSet.isEmpty() ) {
+       // we're currently done with sub work at this heap region, although
+       // more work may get queued up later, but remove it for now and continue
+       workSet.remove( hrn );
+       continue;
+      }
+      
+      TokenTupleSet tts = subWorkSet.iterator().next();
+      subWorkSet.remove( tts );
+
+      // try to push this TokenTupleSet over all outgoing edges
+      Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencees();
+      while( itrRes.hasNext() ) {
+       ReferenceEdge edge = itrRes.next();
+       if( edge.getBeta().containsSuperSet( tts ) ) {
+         HeapRegionNode dst = edge.getDst();
+
+         // make a set of possible contributions this token
+         // might have on the alpha set here
+         HashSet<TokenTupleSet> ttsNewSet = new HashSet<TokenTupleSet>();
+         //ttsNewSet.add( tts );
+
+         Iterator<TokenTupleSet> itrDstAlphaNew = dst.getAlphaNew().iterator();
+         while( itrDstAlphaNew.hasNext() ) {
+           TokenTupleSet ttsDstAlphaNew = itrDstAlphaNew.next();
+           ttsNewSet.add( tts.unionUpArity( ttsDstAlphaNew ) );
+         }
+
+         // only add this to the dst alpha new if it is in the beta of
+         // the edge we crossed to get here, and then only continue the
+         // propagation if it isn't already in the dst alpha new
+         Iterator<TokenTupleSet> itrNewSet = ttsNewSet.iterator();
+         while( itrNewSet.hasNext() ) {
+           TokenTupleSet ttsNew = itrNewSet.next();
+
+           if( edge.getBeta().containsSuperSet( ttsNew ) &&
+               !dst.getAlphaNew().contains( ttsNew ) ) {
+             
+             // okay, this is a valid propagation, and add to the
+             // work set to further propagate it
+             dst.setAlphaNew( dst.getAlphaNew().union( ttsNew ) );
+                     
+             HashSet<TokenTupleSet> subWorkSetDst = workSet.get( dst );
+             if( subWorkSetDst == null ) {
+               subWorkSetDst = new HashSet<TokenTupleSet>();         
+             }
+
+             subWorkSetDst.add( ttsNew );
+             workSet.put( dst, subWorkSetDst );
+           }
+         }
+       }
+      }
+    }
+
+    // now prepare work sets to propagate token sets backwards
+    // from heap regions across all edges
+    assert workSet.isEmpty();
+    hrns = id2hrn.entrySet();
+    itrHrns = hrns.iterator();
+    while( itrHrns.hasNext() ) {
+      Map.Entry me = (Map.Entry)itrHrns.next();
+      HeapRegionNode hrn = (HeapRegionNode) me.getValue();
+
+      HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
+
+      Iterator<TokenTupleSet> itrAlphaNewSets = hrn.getAlphaNew().iterator();
+      while( itrAlphaNewSets.hasNext() ) {
+       TokenTupleSet tts = itrAlphaNewSets.next();
+       subWorkSet.add( tts );
+      }
+
+      workSet.put( hrn, subWorkSet );
+    }
+
+    // propagate token sets backwards across edges one step at a time
+    while( !workSet.isEmpty() ) {
+      HeapRegionNode hrn = workSet.keySet().iterator().next();
+
+      HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
+      assert subWorkSet != null;
+      
+      if( subWorkSet.isEmpty() ) {
+       // we're currently done with sub work at this heap region, although
+       // more work may get queued up later, but remove it for now and continue
+       workSet.remove( hrn );
+       continue;
+      }
+      
+      TokenTupleSet tts = subWorkSet.iterator().next();
+      subWorkSet.remove( tts );
+
+      // try to push this TokenTupleSet back up incoming edges
+      Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
+      while( itrRes.hasNext() ) {
+       ReferenceEdge edge = itrRes.next();
+       if( edge.getBeta().containsWithZeroes( tts ) && 
+           !edge.getBetaNew().contains( tts ) ) {
+         // okay, this is a valid propagation, and add to the
+         // work set to further propagate it
+         edge.setBetaNew( edge.getBetaNew().union( tts ) );
+                     
+         OwnershipNode src = edge.getSrc();
+         if( src instanceof HeapRegionNode ) {
+
+           HashSet<TokenTupleSet> subWorkSetSrc = workSet.get( (HeapRegionNode) src );
+           if( subWorkSetSrc == null ) {
+             subWorkSetSrc = new HashSet<TokenTupleSet>();           
+           }
+           
+           subWorkSetSrc.add( tts );
+           workSet.put( (HeapRegionNode) src, subWorkSetSrc );
+         }       
+       }         
+      }
+    }    
+
+    // apply alphaNew and betaNew to all nodes and edges
+    HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
+
+    Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
+    while( nodeItr.hasNext() ) {
+      HeapRegionNode hrn = nodeItr.next();
+      hrn.applyAlphaNew();
+      Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
+      while( itrRes.hasNext() ) {
+       res.add( itrRes.next() );
+      }
+    }
+
+    Iterator<ReferenceEdge> edgeItr = res.iterator();
+    while( edgeItr.hasNext() ) {
+      edgeItr.next().applyBetaNew();
+    }
   }  
 
 
index 391e2758b6443cab1133db36e346997317398806..830c6f87a771c3be1973c2862896295f1ed53736 100644 (file)
@@ -60,6 +60,43 @@ public class ReachabilitySet extends Canonical {
     return possibleReachabilities.contains(tts);
   }
 
+  public boolean containsWithZeroes(TokenTupleSet tts) {
+    assert tts != null;
+
+    if( possibleReachabilities.contains(tts) ) {
+      return true;
+    }
+
+    Iterator itr = iterator();
+    while( itr.hasNext() ) {
+      TokenTupleSet ttsThis = (TokenTupleSet) itr.next();
+      if( ttsThis.containsWithZeroes(tts) ) {
+       return true;
+      }
+    }
+
+    return false;    
+  }
+
+  public boolean containsSuperSet(TokenTupleSet tts) {
+    assert tts != null;
+
+    if( possibleReachabilities.contains(tts) ) {
+      return true;
+    }
+
+    Iterator itr = iterator();
+    while( itr.hasNext() ) {
+      TokenTupleSet ttsThis = (TokenTupleSet) itr.next();
+      if( tts.isSubset(ttsThis) ) {
+       return true;
+      }
+    }
+
+    return false;    
+  }
+
+
   public boolean containsTuple(TokenTuple tt) {
     Iterator itr = iterator();
     while( itr.hasNext() ) {
index f1ec73cf530db080343bb960867719da7465d43c..e1c603cbf3c3f24dd5b4c67a300dbe596cb6fb1b 100644 (file)
@@ -50,6 +50,37 @@ public class TokenTupleSet extends Canonical {
     return tokenTuples.contains(tt);
   }
 
+  public boolean containsWithZeroes(TokenTupleSet tts) {
+    assert tts != null;
+
+    // first establish that every token tuple from tts is
+    // also in this set
+    Iterator<TokenTuple> ttItrIn = tts.iterator();
+    while( ttItrIn.hasNext() ) {
+      TokenTuple ttIn   = ttItrIn.next();
+      TokenTuple ttThis = this.containsToken(ttIn.getToken() );
+
+      if( ttThis == null ) {
+       return false;
+      }
+    }    
+    
+    // then establish that anything in this set that is
+    // not in tts is a zero-arity token tuple, which is okay    
+    Iterator<TokenTuple> ttItrThis = this.iterator();
+    while( ttItrThis.hasNext() ) {
+      TokenTuple ttThis = ttItrThis.next();
+      TokenTuple ttIn   = tts.containsToken(ttThis.getToken() );
+
+      if( ttIn == null && 
+         ttThis.getArity() != TokenTuple.ARITY_ZEROORMORE ) {
+       return false;
+      }
+    }    
+
+    // if so this set contains tts with zeroes
+    return true;
+  }
 
   public TokenTupleSet union(TokenTuple ttIn) {
     assert ttIn != null;
index 5b56727f7c50da8e4df9e3b9476e8163828b6b3a..3787b57f232686162a46c6658d9a5b309bd65aec 100644 (file)
@@ -1,12 +1,12 @@
 
 public class Parameter {
   flag w;
-  //int a;
-  //int b;
-  //Parameter f;
-  //Parameter g;
-  //Penguin p;
-  //Foo h;
+  int a;
+  int b;
+  Parameter f;
+  Parameter g;
+  Penguin p;
+  Foo h;
   
   public Parameter() {}
   
@@ -28,7 +28,7 @@ public class Fooz {
   public Fooz x;
 }
 
-/*
+
 public class Penguin {
   int x;
   int y;
@@ -188,7 +188,7 @@ public class Foo {
     p1.y = g0;
   }
 }
-*/
+
 
 
 // this empty task should still create a non-empty
@@ -327,7 +327,7 @@ task SummaryNodeTokens( Foo p0{ f } ) {
 
     taskexit( p0{ !f } );
 }
-
+*/
 
 task strongUpdates( Foo p0{ f } ) {
 
@@ -335,12 +335,13 @@ task strongUpdates( Foo p0{ f } ) {
 
     Foo a = new Foo();
     if( false ) {
-       a.x = new Foo();
-       a.y = new Foo();
+      a.x = new Foo();
+      a.y = new Foo();
     } else if( false ) {
-       a.x = new Foo();
-       a.y = new Foo();
+      a.x = new Foo();
+      a.y = new Foo();
     }
+    
 
     // this should effect a strong update
     a.x = b;
@@ -357,10 +358,12 @@ task strongUpdates( Foo p0{ f } ) {
     // p0 points to a multiple-object heap region
     // so this should not make a strong update
     p0.x = b;
-    
+
+
     taskexit( p0{ !f } );
 }
 
+/*
 
 task ObjectChainByMethodCalls( Foo a{ f } ) {