// retrieve the summary node, or make it
// from scratch
- HeapRegionNode hrnSummary = getSummaryNode( as );
+ HeapRegionNode hrnSummary = getSummaryNode( as, false );
mergeIntoSummary( hrnK, hrnSummary );
}
// to and from i-1 to node i.
for( int i = allocationDepth - 1; i > 0; --i ) {
+ /*
// if the target (ith) node exists, clobber it
// whether the i-1 node exists or not
Integer idIth = as.getIthOldest( i );
// clear all references in and out
wipeOut( hrnI );
}
+ */
// only do the transfer if the i-1 node exists
Integer idImin1th = as.getIthOldest( i - 1 );
if( id2hrn.containsKey( idImin1th ) ) {
HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
+ if( hrnImin1.isWiped() ) {
+ // there is no info on this node, just skip
+ continue;
+ }
// either retrieve or make target of transfer
- HeapRegionNode hrnI = getIthNode( as, i );
+ HeapRegionNode hrnI = getIthNode( as, i, false );
transferOnto( hrnImin1, hrnI );
}
// as stated above, the newest node should have had its
// references moved over to the second oldest, so we wipe newest
// in preparation for being the new object to assign something to
- HeapRegionNode hrn0 = getIthNode( as, 0 );
+ HeapRegionNode hrn0 = getIthNode( as, 0, false );
wipeOut( hrn0 );
// now tokens in reachability sets need to "age" also
// either retrieve or create the needed heap region node
- protected HeapRegionNode getSummaryNode( AllocSite as ) {
+ protected HeapRegionNode getSummaryNode( AllocSite as,
+ boolean shadow ) {
+
+ Integer idSummary;
+ if( shadow ) {
+ idSummary = as.getSummaryShadow();
+ } else {
+ idSummary = as.getSummary();
+ }
- Integer idSummary = as.getSummary();
HeapRegionNode hrnSummary = id2hrn.get( idSummary );
if( hrnSummary == null ) {
}
String strDesc = as.toStringForDOT()+"\\nsummary";
+ if( shadow ) {
+ strDesc += " shadow";
+ }
+
hrnSummary =
createNewHeapRegionNode( idSummary, // id or null to generate a new one
false, // single object?
}
// either retrieve or create the needed heap region node
- protected HeapRegionNode getIthNode( AllocSite as, Integer i ) {
+ protected HeapRegionNode getIthNode( AllocSite as,
+ Integer i,
+ boolean shadow ) {
- Integer idIth = as.getIthOldest( i );
+ Integer idIth;
+ if( shadow ) {
+ idIth = as.getIthOldestShadow( i );
+ } else {
+ idIth = as.getIthOldest( i );
+ }
+
HeapRegionNode hrnIth = id2hrn.get( idIth );
if( hrnIth == null ) {
}
String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
+ if( shadow ) {
+ strDesc += " shadow";
+ }
+
hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
true, // single object?
false, // summary?
}
+ // used to assert that the given node object
+ // belongs to THIS graph instance, some gross bugs
+ // have popped up where a node from one graph works
+ // itself into another
+ public boolean belongsToThis( HeapRegionNode hrn ) {
+ return this.id2hrn.get( hrn.getID() ) == hrn;
+ }
protected void mergeIntoSummary( HeapRegionNode hrn,
HeapRegionNode hrnSummary ) {
assert hrnSummary.isNewSummary();
+ // assert that these nodes belong to THIS graph
+ assert belongsToThis( hrn );
+ assert belongsToThis( hrnSummary );
+
// transfer references _from_ hrn over to hrnSummary
Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
while( itrReferencee.hasNext() ) {
hrn.getAlpha()
)
);
+
+ // and afterward, this node is gone
+ wipeOut( hrn );
}
protected void transferOnto( HeapRegionNode hrnA,
HeapRegionNode hrnB ) {
- // don't allow a heap region from one graph to
- // get transferred onto a region from another
- // graph!! Do the transfer on the equivalent
- // elements!
- assert id2hrn.get( hrnA.getID() ) == hrnA;
- assert id2hrn.get( hrnB.getID() ) == hrnB;
+ assert belongsToThis( hrnA );
+ assert belongsToThis( hrnB );
// clear references in and out of node b
- wipeOut( hrnB );
+ assert hrnB.isWiped();
// copy each edge in and out of A to B
Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
// replace hrnB reachability and preds with hrnA's
hrnB.setAlpha( hrnA.getAlpha() );
hrnB.setPreds( hrnA.getPreds() );
+
+ // after transfer, wipe out source
+ wipeOut( hrnA );
}
// not mechanically connected or have any reach or predicate
// information on it anymore--lots of ops can use this
protected void wipeOut( HeapRegionNode hrn ) {
+
+ assert belongsToThis( hrn );
+
clearRefEdgesFrom( hrn, null, null, true );
clearRefEdgesTo ( hrn, null, null, true );
hrn.setAlpha( rsetEmpty );
// would start with reaching from its arguments in
// this reach graph
public ReachGraph
- makeCalleeView( FlatCall fc,
- FlatMethod fm,
- Set<HeapRegionNode> callerNodesCopiedToCallee,
- Set<RefEdge> callerEdgesCopiedToCallee,
- boolean writeDebugDOTs
+ makeCalleeView( FlatCall fc,
+ FlatMethod fm,
+ Set<Integer> callerNodeIDsCopiedToCallee,
+ boolean writeDebugDOTs
) {
// the callee view is a new graph: DON'T MODIFY
// nodes and edges more than once (which the per-param
// "visit" sets won't show) and we only want to create
// an element in the new callee view one time
- //Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
- //Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
// a conservative starting point is to take the
HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
hrnSrcID = hrnSrcCaller.getID();
- if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
+ if( !callerNodeIDsCopiedToCallee.contains( hrnSrcID ) ) {
ExistPred pred =
ExistPred.factory( hrnSrcID, null );
preds,
hrnSrcCaller.getDescription()
);
- callerNodesCopiedToCallee.add( (HeapRegionNode) rsnCaller );
+
+ callerNodeIDsCopiedToCallee.add( hrnSrcID );
} else {
rsnCallee = rg.id2hrn.get( hrnSrcID );
// THIRD - setup destination ends of edges
Integer hrnDstID = hrnCaller.getID();
- if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
+ if( !callerNodeIDsCopiedToCallee.contains( hrnDstID ) ) {
ExistPred pred =
ExistPred.factory( hrnDstID, null );
ExistPredSet.factory( pred );
hrnCallee =
- rg.createNewHeapRegionNode( hrnCaller.getID(),
+ rg.createNewHeapRegionNode( hrnDstID,
hrnCaller.isSingleObject(),
hrnCaller.isNewSummary(),
hrnCaller.isFlagged(),
preds,
hrnCaller.getDescription()
);
- callerNodesCopiedToCallee.add( hrnCaller );
+
+ callerNodeIDsCopiedToCallee.add( hrnDstID );
+
} else {
hrnCallee = rg.id2hrn.get( hrnDstID );
}
// FOURTH - copy edge over if needed
- if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
+ RefEdge reCallee = rsnCallee.getReferenceTo( hrnCallee,
+ reCaller.getType(),
+ reCaller.getField()
+ );
+ if( reCallee == null ) {
ExistPred pred =
ExistPred.factory( tdSrc,
preds
)
);
- callerEdgesCopiedToCallee.add( reCaller );
}
// keep traversing nodes reachable from param i
// out-of-context (not in nodes copied) and have a
// destination in context (one of nodes copied) as
// a starting point for building out-of-context nodes
- Iterator<HeapRegionNode> itrInContext =
- callerNodesCopiedToCallee.iterator();
+ Iterator<Integer> itrInContext =
+ callerNodeIDsCopiedToCallee.iterator();
while( itrInContext.hasNext() ) {
- HeapRegionNode hrnCallerAndInContext = itrInContext.next();
+ Integer hrnID = itrInContext.next();
+ HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
Iterator<RefEdge> itrMightCross =
hrnCallerAndInContext.iteratorToReferencers();
RefEdge edgeMightCross = itrMightCross.next();
// we're only interested in edges with a source
- // 1) out-of-context and 2) is a heap region
- if( callerNodesCopiedToCallee.contains( edgeMightCross.getSrc() ) ||
- !(edgeMightCross.getSrc() instanceof HeapRegionNode)
- ) {
+ // 1) is a heap region and...
+ if( !(edgeMightCross.getSrc() instanceof HeapRegionNode) ) {
// then just skip
continue;
}
HeapRegionNode hrnCallerAndOutContext =
(HeapRegionNode) edgeMightCross.getSrc();
+ // ... 2) is out of context
+ if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() )
+ ) {
+ continue;
+ }
+
+
// we found a reference that crosses from out-of-context
// to in-context, so build a special out-of-context node
// for the callee IHM and its reference edge
public void
- resolveMethodCall( FlatCall fc,
- FlatMethod fm,
- ReachGraph rgCallee,
- Set<HeapRegionNode> callerNodesCopiedToCallee,
- Set<RefEdge> callerEdgesCopiedToCallee,
- boolean writeDebugDOTs
+ resolveMethodCall( FlatCall fc,
+ FlatMethod fm,
+ ReachGraph rgCallee,
+ Set<Integer> callerNodeIDsCopiedToCallee,
+ boolean writeDebugDOTs
) {
if( writeDebugDOTs ) {
try {
- this.writeGraph( "caller", true, false, false, false, true, true,
- callerNodesCopiedToCallee, callerEdgesCopiedToCallee );
- rgCallee.writeGraph( "callee", true, false, false, false, true, true );
+ this.writeGraph( "caller",
+ true, false, false, false, true, true,
+ callerNodeIDsCopiedToCallee );
+ rgCallee.writeGraph( "callee",
+ true, false, false, false, true, true );
} catch( IOException e ) {}
}
ExistPredSet predsIfSatis =
hrnCallee.getPreds().isSatisfiedBy( this,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee
+ callerNodeIDsCopiedToCallee
);
if( predsIfSatis != null ) {
calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
ExistPredSet ifDst =
reCallee.getDst().getPreds().isSatisfiedBy( this,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee
+ callerNodeIDsCopiedToCallee
);
if( ifDst == null ) {
continue;
predsIfSatis =
reCallee.getPreds().isSatisfiedBy( this,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee
+ callerNodeIDsCopiedToCallee
);
if( predsIfSatis != null ) {
calleeEdgesSatisfied.put( reCallee, predsIfSatis );
ExistPredSet ifDst =
reCallee.getDst().getPreds().isSatisfiedBy( this,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee
+ callerNodeIDsCopiedToCallee
);
if( ifDst == null ) {
continue;
ExistPredSet predsIfSatis =
reCallee.getPreds().isSatisfiedBy( this,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee
+ callerNodeIDsCopiedToCallee
);
if( predsIfSatis != null ) {
calleeEdgesSatisfied.put( reCallee, predsIfSatis );
// 2. predicates tested, ok to wipe out caller part
- Iterator<HeapRegionNode> hrnItr = callerNodesCopiedToCallee.iterator();
+ Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
while( hrnItr.hasNext() ) {
- HeapRegionNode hrnCaller = hrnItr.next();
+ Integer hrnID = hrnItr.next();
+ HeapRegionNode hrnCaller = id2hrn.get( hrnID );
+ assert hrnCaller != null;
wipeOut( hrnCaller );
}
+ if( writeDebugDOTs ) {
+ try {
+ writeGraph( "callerWiped",
+ true, false, false, false, true, true );
+ } catch( IOException e ) {}
+ }
+
+
// 3. callee elements with satisfied preds come in, note that
// the mapping of elements satisfied to preds is like this:
continue;
}
- HeapRegionNode hrnCaller = id2hrn.get( hrnCallee.getID() );
+ AllocSite as = hrnCallee.getAllocSite();
+ allocSites.add( as );
+
+ Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
+
+ HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
if( hrnCaller == null ) {
hrnCaller =
- createNewHeapRegionNode( hrnCallee.getID(), // id or null to generate a new one
+ createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
hrnCallee.isSingleObject(), // single object?
hrnCallee.isNewSummary(), // summary?
hrnCallee.isFlagged(), // flagged?
hrnCallee.getAllocSite(), // allocation site
hrnCallee.getInherent(), // inherent reach
null, // current reach
- preds, // predicates
+ predsEmpty, // predicates
hrnCallee.getDescription() // description
);
+ } else {
+ assert hrnCaller.isWiped();
}
// TODO: alpha should be some rewritten version of callee in caller context
hrnCaller.setAlpha( rsetEmpty );
+
+ hrnCaller.setPreds( preds );
}
} else {
HeapRegionNode hrnSrcCallee = (HeapRegionNode) reCallee.getSrc();
- rsnCaller = id2hrn.get( hrnSrcCallee.getID() );
+
+ AllocSite asSrc = hrnSrcCallee.getAllocSite();
+ allocSites.add( asSrc );
+
+ Integer hrnIDSrcShadow = asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
+ rsnCaller = id2hrn.get( hrnIDSrcShadow );
}
assert rsnCaller != null;
HeapRegionNode hrnDstCallee = reCallee.getDst();
- HeapRegionNode hrnDstCaller = id2hrn.get( hrnDstCallee.getID() );
+
+ AllocSite asDst = hrnDstCallee.getAllocSite();
+ allocSites.add( asDst );
+
+ Integer hrnIDDstShadow = asDst.getShadowIDfromID( hrnDstCallee.getID() );
+
+ HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
assert hrnDstCaller != null;
// TODO: beta rewrites
preds
);
-
// look to see if an edge with same field exists
// and merge with it, otherwise just add the edge
RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
// 3.c) resolve out-of-context -> callee edges
+
+ if( writeDebugDOTs ) {
+ try {
+ writeGraph( "callerBeforeCollapseShadow",
+ true, false, false, false, true, true );
+ } catch( IOException e ) {}
+ }
+
+ // 3.d) merge shadow nodes so alloc sites are back to k
+ Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
+ while( asItr.hasNext() ) {
+ // for each allocation site do the following to merge
+ // shadow nodes (newest from callee) with any existing
+ // look for the newest normal and newest shadow "slot"
+ // not being used, transfer normal to shadow. Keep
+ // doing this until there are no more normal nodes, or
+ // no empty shadow slots: then merge all remaining normal
+ // nodes into the shadow summary. Finally, convert all
+ // shadow to their normal versions.
+ AllocSite as = asItr.next();
+ int ageNorm = 0;
+ int ageShad = 0;
+ while( ageNorm < allocationDepth &&
+ ageShad < allocationDepth ) {
+
+ // first, are there any normal nodes left?
+ Integer idNorm = as.getIthOldest( ageNorm );
+ HeapRegionNode hrnNorm = id2hrn.get( idNorm );
+ if( hrnNorm == null ) {
+ // no, this age of normal node not in the caller graph
+ ageNorm++;
+ continue;
+ }
+
+ // yes, a normal node exists, is there an empty shadow
+ // "slot" to transfer it onto?
+ HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
+ if( !hrnShad.isWiped() ) {
+ // no, this age of shadow node is not empty
+ ageShad++;
+ continue;
+ }
+
+ // yes, this shadow node is empty
+ transferOnto( hrnNorm, hrnShad );
+ ageNorm++;
+ ageShad++;
+ }
+
+ // now, while there are still normal nodes but no shadow
+ // slots, merge normal nodes into the shadow summary
+ while( ageNorm < allocationDepth ) {
+
+ // first, are there any normal nodes left?
+ Integer idNorm = as.getIthOldest( ageNorm );
+ HeapRegionNode hrnNorm = id2hrn.get( idNorm );
+ if( hrnNorm == null ) {
+ // no, this age of normal node not in the caller graph
+ ageNorm++;
+ continue;
+ }
+
+ // yes, a normal node exists, so get the shadow summary
+ HeapRegionNode summShad = getSummaryNode( as, true );
+ mergeIntoSummary( hrnNorm, summShad );
+ ageNorm++;
+ }
+
+ // if there is a normal summary, merge it into shadow summary
+ Integer idNorm = as.getSummary();
+ HeapRegionNode summNorm = id2hrn.get( idNorm );
+ if( summNorm != null ) {
+ HeapRegionNode summShad = getSummaryNode( as, true );
+ mergeIntoSummary( summNorm, summShad );
+ }
+
+ // finally, flip all existing shadow nodes onto the normal
+ for( int i = 0; i < allocationDepth; ++i ) {
+ Integer idShad = as.getIthOldestShadow( i );
+ HeapRegionNode hrnShad = id2hrn.get( idShad );
+ if( hrnShad != null ) {
+ // flip it
+ HeapRegionNode hrnNorm = getIthNode( as, i, false );
+ assert hrnNorm.isWiped();
+ transferOnto( hrnShad, hrnNorm );
+ }
+ }
+
+ Integer idShad = as.getSummaryShadow();
+ HeapRegionNode summShad = id2hrn.get( idShad );
+ if( summShad != null ) {
+ summNorm = getSummaryNode( as, false );
+ transferOnto( summNorm, summShad );
+ }
+ }
+
+
// 4.
globalSweep();
if( writeDebugDOTs ) {
try {
writeGraph( "callerAfterTransfer",
- true, false, false, false, true, true,
- null, null );
+ true, false, false, false, true, true );
} catch( IOException e ) {}
}
}
writeReferencers,
hideSubsetReachability,
hideEdgeTaints,
- null,
null );
}
- public void writeGraph( String graphName,
- boolean writeLabels,
- boolean labelSelect,
- boolean pruneGarbage,
- boolean writeReferencers,
- boolean hideSubsetReachability,
- boolean hideEdgeTaints,
- Set<HeapRegionNode> callerNodesCopiedToCallee,
- Set<RefEdge> callerEdgesCopiedToCallee
+ public void writeGraph( String graphName,
+ boolean writeLabels,
+ boolean labelSelect,
+ boolean pruneGarbage,
+ boolean writeReferencers,
+ boolean hideSubsetReachability,
+ boolean hideEdgeTaints,
+ Set<Integer> callerNodeIDsCopiedToCallee
) throws java.io.IOException {
// remove all non-word characters from the graph name so
// this is an optional step to form the callee-reachable
// "cut-out" into a DOT cluster for visualization
- if( callerNodesCopiedToCallee != null ) {
+ if( callerNodeIDsCopiedToCallee != null ) {
bw.write( " subgraph cluster0 {\n" );
bw.write( " color=blue;\n" );
Map.Entry me = (Map.Entry) i.next();
HeapRegionNode hrn = (HeapRegionNode) me.getValue();
- if( callerNodesCopiedToCallee.contains( hrn ) ) {
+ if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
bw.write( " "+hrn.toString()+
hrn.toStringDOT( hideSubsetReachability )+
";\n" );
writeReferencers,
hideSubsetReachability,
hideEdgeTaints,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee );
+ callerNodeIDsCopiedToCallee );
}
}
}
writeReferencers,
hideSubsetReachability,
hideEdgeTaints,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee );
+ callerNodeIDsCopiedToCallee );
}
bw.write( " "+vn.toString()+
boolean writeReferencers,
boolean hideSubsetReachability,
boolean hideEdgeTaints,
- Set<HeapRegionNode> callerNodesCopiedToCallee,
- Set<RefEdge> callerEdgesCopiedToCallee
+ Set<Integer> callerNodeIDsCopiedToCallee
) throws java.io.IOException {
if( visited.contains( hrn ) ) {
// if we're drawing the callee-view subgraph, only
// write out the node info if it hasn't already been
// written
- if( callerNodesCopiedToCallee == null ||
- !callerNodesCopiedToCallee.contains( hrn )
+ if( callerNodeIDsCopiedToCallee == null ||
+ !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
) {
bw.write( " "+hrn.toString()+
hrn.toStringDOT( hideSubsetReachability )+
RefEdge edge = childRegionsItr.next();
HeapRegionNode hrnChild = edge.getDst();
- if( callerEdgesCopiedToCallee != null &&
- callerEdgesCopiedToCallee.contains( hrn )
- ) {
- bw.write( " "+hrn.toString()+
- " -> "+hrnChild.toString()+
- edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
- ";\n");
+ if( callerNodeIDsCopiedToCallee != null &&
+ (edge.getSrc() instanceof HeapRegionNode) ) {
+ HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
+ if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
+ callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
+ ) {
+ bw.write( " "+hrn.toString()+
+ " -> "+hrnChild.toString()+
+ edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
+ ";\n");
+ } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
+ callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
+ ) {
+ bw.write( " "+hrn.toString()+
+ " -> "+hrnChild.toString()+
+ edge.toStringDOT( hideSubsetReachability, ",color=blue,style=dashed" )+
+ ";\n");
+ } else {
+ bw.write( " "+hrn.toString()+
+ " -> "+hrnChild.toString()+
+ edge.toStringDOT( hideSubsetReachability, "" )+
+ ";\n");
+ }
} else {
bw.write( " "+hrn.toString()+
" -> "+hrnChild.toString()+
writeReferencers,
hideSubsetReachability,
hideEdgeTaints,
- callerNodesCopiedToCallee,
- callerEdgesCopiedToCallee );
+ callerNodeIDsCopiedToCallee );
}
}