bug fix: do dynamic tracking when a variable's source transitions from static OR...
authorjjenista <jjenista>
Wed, 20 Jan 2010 23:42:40 +0000 (23:42 +0000)
committerjjenista <jjenista>
Wed, 20 Jan 2010 23:42:40 +0000 (23:42 +0000)
Robust/src/Analysis/Disjoint/DisjointAnalysis.java
Robust/src/Analysis/Disjoint/ExistPred.java [new file with mode: 0644]
Robust/src/Analysis/Disjoint/ExistPredSet.java [new file with mode: 0644]
Robust/src/Analysis/Disjoint/ReachGraph.java
Robust/src/Analysis/MLP/MLPAnalysis.java
Robust/src/Analysis/MLP/VarSrcTokTable.java
Robust/src/IR/Flat/FlatWriteDynamicVarNode.java

index 9274dc2add2dbcaa9c2e3f43cbbf10881c3672ea..b29e15d63da2e3e6b6743de894afb12c10b14278 100644 (file)
@@ -439,11 +439,13 @@ public class DisjointAnalysis {
         rg.merge_diffMethodContext( rgContrib );
       }
       
+      /*
       FlatMethod fm = (FlatMethod) fn;      
       for( int i = 0; i < fm.numParameters(); ++i ) {
         TempDescriptor tdParam = fm.getParameter( i );
-        //assert rg.hasVariable( tdParam );
+        assert rg.hasVariable( tdParam );
       }
+      */
     } break;
       
     case FKind.FlatOpNode:
diff --git a/Robust/src/Analysis/Disjoint/ExistPred.java b/Robust/src/Analysis/Disjoint/ExistPred.java
new file mode 100644 (file)
index 0000000..689e508
--- /dev/null
@@ -0,0 +1,21 @@
+package Analysis.Disjoint;
+
+import IR.*;
+import IR.Flat.*;
+import java.util.*;
+import java.io.*;
+
+// these existence predicates on elements of
+// a callee graph allow a caller to prune the
+// pieces of the graph that don't apply when
+// predicates are not satisfied in the
+// caller's context
+
+public class ExistPred extends Canonical {
+
+  
+
+  public boolean isSatisfiedBy( ReachGraph rg ) {    
+    return true;
+  }
+}
diff --git a/Robust/src/Analysis/Disjoint/ExistPredSet.java b/Robust/src/Analysis/Disjoint/ExistPredSet.java
new file mode 100644 (file)
index 0000000..29ab305
--- /dev/null
@@ -0,0 +1,17 @@
+package Analysis.Disjoint;
+
+import IR.*;
+import IR.Flat.*;
+import java.util.*;
+import java.io.*;
+
+// a set of existence predicates that are
+// OR'ed terms, if any predicate is true
+// then the set evaluates to true
+
+public class ExistPredSet extends Canonical {
+
+  private HashSet<ExistPred> preds;
+
+  public 
+}
index a2ee11f6bd0aedf0cee2c5c7bd5fd8bf97882a17..5f688e4aabccfb6c50977791222e0549b22ebee0 100644 (file)
@@ -7,49 +7,40 @@ import java.util.*;
 import java.io.*;
 
 public class ReachGraph {
+
+  // use to disable improvements for comparison
+  protected static final boolean DISABLE_STRONG_UPDATES = false;
+  protected static final boolean DISABLE_GLOBAL_SWEEP   = true;
                   
-  protected static final TempDescriptor tdReturn    = new TempDescriptor( "_Return___" );
+  // a special out-of-scope temp
+  protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
                   
   // some frequently used reachability constants
   protected static final ReachState rstateEmpty        = new ReachState().makeCanonical();
   protected static final ReachSet   rsetEmpty          = new ReachSet().makeCanonical();
   protected static final ReachSet   rsetWithEmptyState = new ReachSet( rstateEmpty ).makeCanonical();
 
-  public Hashtable<Integer,        HeapRegionNode> id2hrn;
-  public Hashtable<TempDescriptor, VariableNode  > td2vn;
-
-  public HashSet<AllocSite> allocSites;
-
-  // this is kept to allow edges created from variables (a src and dst)
-  // to know the access paths that allowed it, to prune edges when
-  // mapping them back into the caller--an access path must appear
-  public Hashtable< TempDescriptor, Set<AccessPath> > temp2accessPaths;
-  
-
-  // use to disable improvements for comparison
-  protected static final boolean DISABLE_STRONG_UPDATES = false;
-  protected static final boolean DISABLE_GLOBAL_SWEEP   = true;
-
+  // from DisjointAnalysis for convenience
   protected static int      allocationDepth   = -1;
   protected static TypeUtil typeUtil          = null;
-  protected static boolean  debugCallMap      = false;
-  protected static int      debugCallMapCount = 0;
-  protected static String   debugCallee       = null;
-  protected static String   debugCaller       = null;
 
 
-  public ReachGraph() {
-    id2hrn = new Hashtable<Integer,        HeapRegionNode>();
-    td2vn  = new Hashtable<TempDescriptor, VariableNode  >();
+  // variable and heap region nodes indexed by unique ID
+  public Hashtable<Integer,        HeapRegionNode> id2hrn;
+  public Hashtable<TempDescriptor, VariableNode  > td2vn;
 
-    allocSites = new HashSet<AllocSite>();
+  // convenient set of alloc sites for all heap regions
+  // present in the graph without having to search
+  public HashSet<AllocSite> allocSites;  
 
-    temp2accessPaths = 
-      new Hashtable< TempDescriptor, Set<AccessPath> >();
+  public ReachGraph() {
+    id2hrn     = new Hashtable<Integer,        HeapRegionNode>();
+    td2vn      = new Hashtable<TempDescriptor, VariableNode  >();
+    allocSites = new HashSet<AllocSite>();
   }
 
   
-  // temp descriptors are globally unique and maps to
+  // temp descriptors are globally unique and map to
   // exactly one variable node, easy
   protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
     assert td != null;
@@ -72,17 +63,17 @@ public class ReachGraph {
   // in the merge() operation) or to create new heap
   // regions with a new unique ID
   protected HeapRegionNode
-    createNewHeapRegionNode( Integer id,
-                            boolean isSingleObject,
-                            boolean isNewSummary,
-                            boolean isFlagged,
-                             boolean isClean,
-                             boolean isOutOfContext,
+    createNewHeapRegionNode( Integer        id,
+                            boolean        isSingleObject,
+                            boolean        isNewSummary,
+                            boolean        isFlagged,
+                             boolean        isClean,
+                             boolean        isOutOfContext,
                             TypeDescriptor type,
-                            AllocSite allocSite,
-                             ReachSet inherent,
-                            ReachSet alpha,
-                            String description
+                            AllocSite      allocSite,
+                             ReachSet       inherent,
+                            ReachSet       alpha,
+                            String         description
                              ) {
 
     boolean markForAnalysis = isFlagged;
@@ -252,36 +243,6 @@ public class ReachGraph {
   //
   ////////////////////////////////////////////////////
 
-  public void nullifyDeadVars( Set<TempDescriptor> liveIn ) {
-    // THIS IS BUGGGY
-
-    /*
-    // make a set of the temps that are out of scope, don't
-    // consider them when nullifying dead in-scope variables
-    Set<TempDescriptor> outOfScope = new HashSet<TempDescriptor>();
-    outOfScope.add( tdReturn );
-    outOfScope.add( tdAliasBlob );
-    outOfScope.addAll( paramIndex2tdQ.values() );
-    outOfScope.addAll( paramIndex2tdR.values() );    
-    
-    Iterator varItr = td2vn.entrySet().iterator();
-    while( varItr.hasNext() ) {
-      Map.Entry      me = (Map.Entry)      varItr.next();
-      TempDescriptor td = (TempDescriptor) me.getKey();
-      VariableNode      ln = (VariableNode)      me.getValue();
-
-      // if this variable is not out-of-scope or live
-      // in graph, nullify its references to anything
-      if( !outOfScope.contains( td ) &&
-         !liveIn.contains( td ) 
-         ) {
-       clearRefEdgesFrom( ln, null, null, true );
-      }
-    }
-    */
-  }
-
-
   public void assignTempXEqualToTempY( TempDescriptor x,
                                       TempDescriptor y ) {
     assignTempXEqualToCastedTempY( x, y, null );
@@ -714,19 +675,7 @@ public class ReachGraph {
 
 
     // after tokens have been aged, reset newest node's reachability
-    if( hrn0.isFlagged() ) {
-      hrn0.setAlpha( new ReachSet(
-                       new ReachState(
-                         new ReachTuple( hrn0 ).makeCanonical()
-                       ).makeCanonical()
-                     ).makeCanonical()
-                   );
-    } else {
-      hrn0.setAlpha( new ReachSet(
-                       new ReachState().makeCanonical()
-                     ).makeCanonical()
-                   );
-    }
+    hrn0.setAlpha( hrn0.getInherent() );
   }
 
 
@@ -845,7 +794,8 @@ public class ReachGraph {
   }
 
 
-  protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
+  protected void mergeIntoSummary( HeapRegionNode hrn, 
+                                   HeapRegionNode hrnSummary ) {
     assert hrnSummary.isNewSummary();
 
     // transfer references _from_ hrn over to hrnSummary
@@ -853,22 +803,24 @@ public class ReachGraph {
     while( itrReferencee.hasNext() ) {
       RefEdge edge       = itrReferencee.next();
       RefEdge edgeMerged = edge.copy();
-      edgeMerged.setSrc(hrnSummary);
+      edgeMerged.setSrc( hrnSummary );
 
       HeapRegionNode hrnReferencee = edge.getDst();
-      RefEdge edgeSummary   = hrnSummary.getReferenceTo(hrnReferencee, 
-                                                             edge.getType(),
-                                                             edge.getField() );
-
+      RefEdge        edgeSummary   = 
+        hrnSummary.getReferenceTo( hrnReferencee, 
+                                   edge.getType(),
+                                   edge.getField() 
+                                   );
+      
       if( edgeSummary == null ) {
        // the merge is trivial, nothing to be done
       } else {
        // otherwise an edge from the referencer to hrnSummary exists already
        // and the edge referencer->hrn should be merged with it
-       edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
+       edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
       }
 
-      addRefEdge(hrnSummary, hrnReferencee, edgeMerged);
+      addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
     }
 
     // next transfer references _to_ hrn over to hrnSummary
@@ -876,75 +828,79 @@ public class ReachGraph {
     while( itrReferencer.hasNext() ) {
       RefEdge edge         = itrReferencer.next();
       RefEdge edgeMerged   = edge.copy();
-      edgeMerged.setDst(hrnSummary);
+      edgeMerged.setDst( hrnSummary );
 
       RefSrcNode onReferencer = edge.getSrc();
-      RefEdge edgeSummary  = onReferencer.getReferenceTo(hrnSummary, 
-                                                              edge.getType(),
-                                                              edge.getField() );
+      RefEdge    edgeSummary  =
+        onReferencer.getReferenceTo( hrnSummary, 
+                                     edge.getType(),
+                                     edge.getField() 
+                                     );
 
       if( edgeSummary == null ) {
        // the merge is trivial, nothing to be done
       } else {
        // otherwise an edge from the referencer to alpha_S exists already
        // and the edge referencer->alpha_K should be merged with it
-       edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
+       edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
       }
 
-      addRefEdge(onReferencer, hrnSummary, edgeMerged);
+      addRefEdge( onReferencer, hrnSummary, edgeMerged );
     }
 
     // then merge hrn reachability into hrnSummary
-    hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
+    hrnSummary.setAlpha( hrnSummary.getAlpha().union( hrn.getAlpha() ) );
   }
 
 
-  protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
+  protected void transferOnto( HeapRegionNode hrnA, 
+                               HeapRegionNode hrnB ) {
 
     // clear references in and out of node b
-    clearRefEdgesFrom(hrnB, null, null, true);
-    clearRefEdgesTo(hrnB, null, null, true);
+    clearRefEdgesFrom( hrnB, null, null, true );
+    clearRefEdgesTo  ( hrnB, null, null, true );
 
     // copy each edge in and out of A to B
     Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
     while( itrReferencee.hasNext() ) {
-      RefEdge edge          = itrReferencee.next();
+      RefEdge        edge          = itrReferencee.next();
       HeapRegionNode hrnReferencee = edge.getDst();
-      RefEdge edgeNew       = edge.copy();
-      edgeNew.setSrc(hrnB);
+      RefEdge        edgeNew       = edge.copy();
+      edgeNew.setSrc( hrnB );
 
-      addRefEdge(hrnB, hrnReferencee, edgeNew);
+      addRefEdge( hrnB, hrnReferencee, edgeNew );
     }
 
     Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
     while( itrReferencer.hasNext() ) {
-      RefEdge edge         = itrReferencer.next();
+      RefEdge    edge         = itrReferencer.next();
       RefSrcNode onReferencer = edge.getSrc();
-      RefEdge edgeNew      = edge.copy();
-      edgeNew.setDst(hrnB);
+      RefEdge    edgeNew      = edge.copy();
+      edgeNew.setDst( hrnB );
 
-      addRefEdge(onReferencer, hrnB, edgeNew);
+      addRefEdge( onReferencer, hrnB, edgeNew );
     }
 
     // replace hrnB reachability with hrnA's
-    hrnB.setAlpha(hrnA.getAlpha() );
+    hrnB.setAlpha( hrnA.getAlpha() );
   }
 
 
-  protected void ageTokens(AllocSite as, RefEdge edge) {
-    edge.setBeta(edge.getBeta().ageTokens(as) );
+  protected void ageTokens( AllocSite as, RefEdge edge ) {
+    edge.setBeta( edge.getBeta().ageTokens( as ) );
   }
 
-  protected void ageTokens(AllocSite as, HeapRegionNode hrn) {
-    hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
+  protected void ageTokens( AllocSite as, HeapRegionNode hrn ) {
+    hrn.setAlpha( hrn.getAlpha().ageTokens( as ) );
   }
 
 
 
-  protected void propagateTokensOverNodes(HeapRegionNode nPrime,
-                                          ChangeSet c0,
-                                          HashSet<HeapRegionNode> nodesWithNewAlpha,
-                                          HashSet<RefEdge>  edgesWithNewBeta) {
+  protected void propagateTokensOverNodes(
+    HeapRegionNode          nPrime,
+    ChangeSet               c0,
+    HashSet<HeapRegionNode> nodesWithNewAlpha,
+    HashSet<RefEdge>        edgesWithNewBeta ) {
 
     HashSet<HeapRegionNode> todoNodes
       = new HashSet<HeapRegionNode>();
@@ -1034,9 +990,9 @@ public class ReachGraph {
 
 
   protected void propagateTokensOverEdges(
-    HashSet<RefEdge>                   todoEdges,
+    HashSet  <RefEdge>            todoEdges,
     Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
-    HashSet<RefEdge>                   edgesWithNewBeta) {
+    HashSet  <RefEdge>            edgesWithNewBeta ) {
 
     // first propagate all change tuples everywhere they can go
     while( !todoEdges.isEmpty() ) {
@@ -1173,7 +1129,8 @@ public class ReachGraph {
           // not have been created already
           assert rsnCaller instanceof HeapRegionNode;          
 
-          HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
+          HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;          
+
           if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
             rsnCallee = 
               rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
@@ -1308,7 +1265,7 @@ public class ReachGraph {
       }
     }    
 
-    /*
+
     try {
       rg.writeGraph( "calleeview", true, true, true, false, true, true );
     } catch( IOException e ) {}
@@ -1316,7 +1273,7 @@ public class ReachGraph {
     if( fc.getMethod().getSymbol().equals( "f1" ) ) {
       System.exit( 0 );
     }
-    */
+
 
     return rg;
   }  
@@ -1325,7 +1282,79 @@ public class ReachGraph {
                                  FlatMethod fm,        
                                  ReachGraph rgCallee
                                  ) {
-    
+    /*
+    // to map the callee effects into the caller graph,
+    // traverse the callee and categorize each element as,
+    // Callee elements:
+    // 1) new node (not in caller)
+    // 2) old node, clean (not modified in callee)
+    // 3) old node, dirty
+    // 4) new edge,
+    // 5) old edge, clean
+    // 6) old edge, dirty
+    // 7) out-of-context nodes
+    // 8) edge that crosses out-of-context to in-
+
+    Iterator hrnItr = rgCallee.id2hrn.entrySet().iterator();
+    while( hrnItr.hasNext() ) {
+      Map.Entry      me        = (Map.Entry)      hrnItr.next();
+      Integer        id        = (Integer)        me.getKey();
+      HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
+      
+      if( hrnCallee.isOutOfContext() ) {
+        // 7) out-of-context nodes aren't altered by callee
+        // analysis, they just help calculate changes to other
+        // elements, so do nothing for this node
+
+      } else {
+        // node is in the callee context...
+       
+        if( !this.id2hrn.containsKey( id ) ) {
+          // 1) this is a new node in the callee
+          assert !hrnCallee.isClean();
+
+          // bring this node into caller as-is, and do the
+          // unshadow of tokens in-place
+          this.createNewHeapRegionNode( id,
+                                        hrnCallee.isSingleObject(),
+                                        hrnCallee.isNewSummary(),
+                                        hrnCallee.isFlagged(),
+                                        false, // clean?
+                                        false, // out-of-context?
+                                        hrnCallee.getType(),
+                                        hrnCallee.getAllocSite(),
+                                        unShadowTokens( rgCallee, hrnCallee.getInherent() ),
+                                        unShadowTokens( rgCallee, hrnCallee.getAlpha() ),
+                                        hrnCallee.getDescription()
+                                        );
+          
+        } else {
+          // otherwise, both graphs have this node, so...
+
+          if( hrnCallee.isClean() ) {
+            // 2) this node was not modified by callee, 
+            // just leave it alone in caller
+            
+          } else {
+            // 3) this node is already in caller, was modified
+            // by the callee, so update caller node in-place
+            hrnCaller = this.id2hrn.get( id );
+            
+            assert hrnCaller.getInherent().equals( 
+                                                  unShadowTokens( rgCallee, hrnCallee.getInherent() )                                                  
+                                                   );
+            hrnCaller.setAlpha( 
+                               unShadowTokens( rgCallee, hrnCallee.getAlpha() )
+                                );
+            
+            hrnCaller.setClean( false );
+          }
+        }      
+      }
+    } // end visiting callee nodes
+
+    // what else?
+    */
   } 
 
   
@@ -1656,10 +1685,9 @@ public class ReachGraph {
       return;
     }
 
-    mergeNodes      ( rg );
-    mergeRefEdges   ( rg );
-    mergeAllocSites ( rg );
-    mergeAccessPaths( rg );
+    mergeNodes     ( rg );
+    mergeRefEdges  ( rg );
+    mergeAllocSites( rg );
   }
   
   protected void mergeNodes( ReachGraph rg ) {
@@ -1838,11 +1866,6 @@ public class ReachGraph {
     allocSites.addAll( rg.allocSites );
   }
 
-  protected void mergeAccessPaths( ReachGraph rg ) {
-    UtilAlgorithms.mergeHashtablesWithHashSetValues( temp2accessPaths,
-                                                     rg.temp2accessPaths );
-  }
-
 
   // it is necessary in the equals() member functions
   // to "check both ways" when comparing the data
@@ -1872,10 +1895,6 @@ public class ReachGraph {
       return false;
     }
 
-    if( !areAccessPathsEqual( rg ) ) {
-      return false;
-    }
-
     // if everything is equal up to this point,
     // assert that allocSites is also equal--
     // this data is redundant but kept for efficiency
@@ -2067,11 +2086,6 @@ public class ReachGraph {
   }
 
 
-  protected boolean areAccessPathsEqual( ReachGraph rg ) {
-    return temp2accessPaths.equals( rg.temp2accessPaths );
-  }
-
-
 
   // this analysis no longer has the "match anything"
   // type which was represented by null
index ec34713f6a5725e2e2dbda82d2e459290f175707..44629657bcac3a18c1df13dd7d16e44fc0888484 100644 (file)
@@ -3412,14 +3412,14 @@ public class MLPAnalysis {
       // completely outside of the root SESE scope
       if( nextVstTable != null && nextLiveIn != null ) {
 
-       Hashtable<TempDescriptor, VariableSourceToken> static2dynamicSet = 
-         thisVstTable.getStatic2DynamicSet( nextVstTable, 
-                                            nextLiveIn,
-                                            currentSESE,
-                                            currentSESE.getParent() 
+       Hashtable<TempDescriptor, VariableSourceToken> readyOrStatic2dynamicSet = 
+         thisVstTable.getReadyOrStatic2DynamicSet( nextVstTable, 
+                                                    nextLiveIn,
+                                                    currentSESE,
+                                                    currentSESE.getParent() 
                                           );
        
-       if( !static2dynamicSet.isEmpty() ) {
+       if( !readyOrStatic2dynamicSet.isEmpty() ) {
 
          // either add these results to partial fixed-point result
          // or make a new one if we haven't made any here yet
@@ -3429,12 +3429,12 @@ public class MLPAnalysis {
          if( fwdvn == null ) {
            fwdvn = new FlatWriteDynamicVarNode( fn, 
                                                 nn,
-                                                static2dynamicSet,
+                                                readyOrStatic2dynamicSet,
                                                 currentSESE
                                                 );
            wdvNodesToSpliceIn.put( fe, fwdvn );
          } else {
-           fwdvn.addMoreVar2Src( static2dynamicSet );
+           fwdvn.addMoreVar2Src( readyOrStatic2dynamicSet );
          }
        }
       }
@@ -3564,7 +3564,8 @@ public class MLPAnalysis {
          bw.write( "    (ready)  "+inVar+"\n" );
        }
        if( fsen.getStaticInVarSet().contains( inVar ) ) {
-         bw.write( "    (static) "+inVar+"\n" );
+         bw.write( "    (static) "+inVar+" from "+
+                    fsen.getStaticInVarSrc( inVar )+"\n" );
        } 
        if( fsen.getDynamicInVarSet().contains( inVar ) ) {
          bw.write( "    (dynamic)"+inVar+"\n" );
index aca674770245ea3e9ef032c9b7d778b5846de8cf..84c7cca829133374e69b5365a876716cf46d85d1 100644 (file)
@@ -556,11 +556,11 @@ public class VarSrcTokTable {
   // which variables are going from a static source to a
   // dynamic source and return them
   public Hashtable<TempDescriptor, VariableSourceToken> 
-    getStatic2DynamicSet( VarSrcTokTable nextTable,
-                         Set<TempDescriptor> nextLiveIn,
-                         FlatSESEEnterNode current,
-                         FlatSESEEnterNode parent
-                       ) {
+    getReadyOrStatic2DynamicSet( VarSrcTokTable nextTable,
+                                 Set<TempDescriptor> nextLiveIn,
+                                 FlatSESEEnterNode current,
+                                 FlatSESEEnterNode parent
+                                 ) {
     
     Hashtable<TempDescriptor, VariableSourceToken> out = 
       new Hashtable<TempDescriptor, VariableSourceToken>();
@@ -574,7 +574,9 @@ public class VarSrcTokTable {
       // only worth tracking if live
       if( nextLiveIn.contains( var ) ) {
 
-       if(      this.getRefVarSrcType( var, current, parent ) == SrcType_STATIC  &&
+       if( (    this.getRefVarSrcType( var, current, parent ) == SrcType_READY ||
+                 this.getRefVarSrcType( var, current, parent ) == SrcType_STATIC  )
+            &&
            nextTable.getRefVarSrcType( var, current, parent ) == SrcType_DYNAMIC
          ) {
          // remember the variable and a static source
index 53b746d3047d3c56e99192e7946fdf306971c32e..ec85959b7fe41be3753199d1cc9026266c6481d0 100644 (file)
@@ -50,7 +50,7 @@ public class FlatWriteDynamicVarNode extends FlatNode {
   }
 
   public String toString() {
-    return "writeDynVars "+var2src.keySet();
+    return "writeDynVars "+var2src;
   }
 
   public int kind() {