public HashSet<AllocationSite>
getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
+ checkAnalysisComplete();
return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
}
public AllocationSite getAllocationSiteFromFlatNew(FlatNew fn) {
+ checkAnalysisComplete();
return getAllocationSiteFromFlatNewPRIVATE(fn);
}
public AllocationSite getAllocationSiteFromHeapRegionNodeID(Integer id) {
+ checkAnalysisComplete();
return mapHrnIdToAllocationSite.get(id);
}
public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
int paramIndex1,
int paramIndex2) {
-
+ checkAnalysisComplete();
OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
assert(og != null);
return og.hasPotentialAlias(paramIndex1, paramIndex2);
public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
int paramIndex,
AllocationSite alloc) {
-
+ checkAnalysisComplete();
OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
assert(og != null);
return og.hasPotentialAlias(paramIndex, alloc);
public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
AllocationSite alloc,
int paramIndex) {
-
+ checkAnalysisComplete();
OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
assert(og != null);
return og.hasPotentialAlias(paramIndex, alloc);
public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
AllocationSite alloc1,
AllocationSite alloc2) {
-
+ checkAnalysisComplete();
OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
assert(og != null);
return og.hasPotentialAlias(alloc1, alloc2);
protected OwnershipGraph getGraphOfAllContextsFromDescriptor(Descriptor d) {
+ checkAnalysisComplete();
+
assert d != null;
OwnershipGraph og = new OwnershipGraph( allocationDepth, typeUtil );
}
- public String prettyPrintNodeSet( Set<HeapRegionNode> s ) {
+ public String prettyPrintNodeSet( Set<HeapRegionNode> s ) {
+ checkAnalysisComplete();
+
String out = "{\n";
Iterator<HeapRegionNode> i = s.iterator();
// between task parameters and flagged allocation sites reachable
// from the task
public void writeAllAliases(String outputFile, String timeReport) throws java.io.IOException {
+ checkAnalysisComplete();
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
// this version of writeAllAliases is for Java programs that have no tasks
public void writeAllAliasesJava(String outputFile, String timeReport) throws java.io.IOException {
+ checkAnalysisComplete();
+
assert !state.TASK;
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
//
///////////////////////////////////////////
-
-
+ protected void checkAnalysisComplete() {
+ if( !analysisComplete ) {
+ throw new Error("Warning: public interface method called while analysis is running.");
+ }
+ }
// data from the compiler
- private State state;
- private TypeUtil typeUtil;
- private CallGraph callGraph;
- private int allocationDepth;
+ public State state;
+ public CallGraph callGraph;
+ public TypeUtil typeUtil;
+ public int allocationDepth;
+
+ // for public interface methods to warn that they
+ // are grabbing results during analysis
+ private boolean analysisComplete;
// used to identify HeapRegionNode objects
// A unique ID equates an object in one
// TaskDescriptor and MethodDescriptor are combined
// together, with a common parent class Descriptor
private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToInitialParamAllocGraph;
- private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToCompleteOwnershipGraph;
+ public Hashtable<MethodContext, OwnershipGraph> mapMethodContextToCompleteOwnershipGraph;
private Hashtable<FlatNew, AllocationSite> mapFlatNewToAllocationSite;
private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
private Hashtable<MethodContext, Integer> mapMethodContextToNumUpdates;
boolean writeAllDOTs,
String aliasFile) throws java.io.IOException {
- double timeStartAnalysis = (double) System.nanoTime();
+ analysisComplete = false;
this.state = state;
this.typeUtil = tu;
}
+ double timeStartAnalysis = (double) System.nanoTime();
+
+
if( state.TASK ) {
// initialize methods to visit as the set of all tasks in the
// program and then any method that could be called starting
// as mentioned above, analyze methods one-by-one, possibly revisiting
// a method if the methods that it calls are updated
analyzeMethods();
+ analysisComplete = true;
+
double timeEndAnalysis = (double) System.nanoTime();
double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
}
} else {
- ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee, mc);
+ ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee, mc, null);
}
} else {
}
} else {
- ogCopy.resolveMethodCall(fc, possibleMd.isStatic(), pflatm, ogPotentialCallee, mc);
+ ogCopy.resolveMethodCall(fc, possibleMd.isStatic(), pflatm, ogPotentialCallee, mc, null);
}
ogMergeOfAllPossibleCalleeResults.merge(ogCopy);
return rsOut;
}
+ // detects strong updates to the primary parameter object and
+ // effects the removal of old edges in the calling graph
private void effectCalleeStrongUpdates( Integer paramIndex,
OwnershipGraph ogCallee,
HeapRegionNode hrnCaller
return true;
}
- public void resolveMethodCall(FlatCall fc,
- boolean isStatic,
- FlatMethod fm,
- OwnershipGraph ogCallee,
- MethodContext mc
+ // resolveMethodCall() is used to incorporate a callee graph's effects into
+ // *this* graph, which is the caller. This method can also be used, after
+ // the entire analysis is complete, to perform parameter decomposition for
+ // a given call chain.
+ public void resolveMethodCall(FlatCall fc, // call site in caller method
+ boolean isStatic, // whether it is a static method
+ FlatMethod fm, // the callee method (when virtual, can be many)
+ OwnershipGraph ogCallee, // the callee's current ownership graph
+ MethodContext mc, // the aliasing context for this call
+ ParameterDecomposition pd // if this is not null, we're calling after analysis
) {
+
+ // this debug snippet is harmless for regular use and INVALUABLE at debug time
+ // to see what potentially goes wrong when a specific method calls another
String debugCaller = "foo";
String debugCallee = "bar";
//String debugCaller = "StandardEngine";
}
+
// define rewrite rules and other structures to organize data by parameter/argument index
Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
assert defParamObj.size() <= fm.numParameters();
+ // if we're in parameter decomposition mode, report some results here
+ if( pd != null ) {
+ Iterator mapItr;
+
+ // report primary parameter object mappings
+ mapItr = pi2dr.entrySet().iterator();
+ while( mapItr.hasNext() ) {
+ Map.Entry me = (Map.Entry) mapItr.next();
+ Integer paramIndex = (Integer) me.getKey();
+ Set<HeapRegionNode> hrnAset = (Set<HeapRegionNode>) me.getValue();
+
+ Iterator<HeapRegionNode> hrnItr = hrnAset.iterator();
+ while( hrnItr.hasNext() ) {
+ HeapRegionNode hrnA = hrnItr.next();
+ pd.mapRegionToParamObject( hrnA, paramIndex );
+ }
+ }
+
+ // report parameter-reachable mappings
+ mapItr = pi2r.entrySet().iterator();
+ while( mapItr.hasNext() ) {
+ Map.Entry me = (Map.Entry) mapItr.next();
+ Integer paramIndex = (Integer) me.getKey();
+ Set<HeapRegionNode> hrnRset = (Set<HeapRegionNode>) me.getValue();
+
+ Iterator<HeapRegionNode> hrnItr = hrnRset.iterator();
+ while( hrnItr.hasNext() ) {
+ HeapRegionNode hrnR = hrnItr.next();
+ pd.mapRegionToParamReachable( hrnR, paramIndex );
+ }
+ }
+
+ // and we're done in this method for special param decomp mode
+ return;
+ }
+
// now iterate over reachable nodes to rewrite their alpha, and
// classify edges found for beta rewrite
import IR.Flat.*;
import java.util.*;
-// This class is useful to instantiate from objects out
+// This class must be instantiated from objects out
// of a completed analysis. Given a method's reachability
// graph and a call site, what heap regions might the
// parameter regions be decomposed into?
// flat call one step back in the chain.
public class ParameterDecomposition {
- // used to help user realize when they are
- // asking for results of an invalid call chain
- MethodDescriptor mdCallee;
- MethodDescriptor mdCaller;
- public ParameterDecomposition( MethodDescriptor md,
- FlatCall fc ) {
+ // the ownership analysis results to compute from
+ protected OwnershipAnalysis oa;
+
+ // info needed to use OwnershipGraph.resolveMethodCall()
+ // to do the parameter decomp mapping itself
+ protected FlatCall fcInCaller;
+ protected FlatMethod fmPossible;
+ protected MethodContext mcCallSite;
+ protected OwnershipGraph ogCallee;
+ protected OwnershipGraph ogCaller;
+
+ // computed information:
+ // a IDs are heap regions that map the primary parameter object region
+ // r IDs are regions that map to the gamma parameter region
+ // allocation sites are any that provide the regions a param could map to
+ // type descriptors are any types of any allocation site from above
+ protected Hashtable<Integer, Set<Integer> > pi2a_id;
+ protected Hashtable<Integer, Set<Integer> > pi2r_id;
+ protected Hashtable<Integer, Set<AllocationSite> > pi2a_as;
+ protected Hashtable<Integer, Set<AllocationSite> > pi2r_as;
+ protected Hashtable<Integer, Set<TypeDescriptor> > pi2a_td;
+ protected Hashtable<Integer, Set<TypeDescriptor> > pi2r_td;
+
+
+ public ParameterDecomposition( OwnershipAnalysis oa,
+ FlatCall fc,
+ FlatMethod fm,
+ MethodContext mc,
+ OwnershipGraph cee,
+ OwnershipGraph cer ) {
+ oa.checkAnalysisComplete();
+ this.oa = oa;
+
+ MethodDescriptor md = (MethodDescriptor) mc.getDescriptor();
+ // the call site should be calling the method in question
+ assert fc.getMethod() == md;
+
+ this.fcInCaller = fc;
+ this.fmPossible = fm;
+ this.mcCallSite = mc;
+
+ // make copies of the graphs so that resolveMethodCall can
+ // destroy the graph while calculating the stuff we want
+ this.ogCallee = new OwnershipGraph( oa.allocationDepth, oa.typeUtil );
+ this.ogCallee.merge( cee );
+ this.ogCaller = new OwnershipGraph( oa.allocationDepth, oa.typeUtil );
+ this.ogCaller.merge( cer );
+
+ allocOutputStructs();
+
+ computeDecompositon();
}
+ /*
public ParameterDecomposition( ParameterDecomposition pd,
FlatCall fc ) {
-
+ this.oa = pd.oa;
+
+ // the call site should be calling the caller of
+ // the input parameter decomposition object
+ assert fc.getMethod() == pd.mdCaller;
+
+ mdCallee = pd.mdCaller;
+ mdCaller = getCaller( fc );
+ }
+ */
+
+ protected void allocOutputStructs() {
+ pi2a_id = new Hashtable<Integer, Set<Integer> >();
+ pi2r_id = new Hashtable<Integer, Set<Integer> >();
+ pi2a_as = new Hashtable<Integer, Set<AllocationSite> >();
+ pi2r_as = new Hashtable<Integer, Set<AllocationSite> >();
+ pi2a_td = new Hashtable<Integer, Set<TypeDescriptor> >();
+ pi2r_td = new Hashtable<Integer, Set<TypeDescriptor> >();
+ }
+
+ protected void computeDecompositon() {
+ MethodDescriptor mdCallee = (MethodDescriptor) mcCallSite.getDescriptor();
+
+ ogCaller.resolveMethodCall( fcInCaller,
+ mdCallee.isStatic(),
+ fmPossible,
+ ogCallee,
+ mcCallSite,
+ this );
+ }
+
+ // called by resolveMethodCall in decomp mode
+ // to report mapping results
+ protected void mapRegionToParamObject( HeapRegionNode hrn, Integer paramIndex ) {
+
+ // extract region's intergraph ID
+ Set<Integer> hrnIDs = pi2a_id.get( paramIndex );
+ if( hrnIDs == null ) {
+ hrnIDs = new HashSet<Integer>();
+ }
+ hrnIDs.add( hrn.getID() );
+ pi2a_id.put( paramIndex, hrnIDs );
+
+ // the regions allocation site (if any)
+ AllocationSite as = hrn.getAllocationSite();
+ if( as != null ) {
+ Set<AllocationSite> asSet = pi2a_as.get( paramIndex );
+ if( asSet == null ) {
+ asSet = new HashSet<AllocationSite>();
+ }
+ asSet.add( as );
+ pi2a_as.put( paramIndex, asSet );
+
+ // and if there is an allocation site, grab type
+ Set<TypeDescriptor> tdSet = pi2a_td.get( paramIndex );
+ if( tdSet == null ) {
+ tdSet = new HashSet<TypeDescriptor>();
+ }
+ tdSet.add( as.getType() );
+ pi2a_td.put( paramIndex, tdSet );
+ }
+ }
+
+ protected void mapRegionToParamReachable( HeapRegionNode hrn, Integer paramIndex ) {
+
+ // extract region's intergraph ID
+ Set<Integer> hrnIDs = pi2r_id.get( paramIndex );
+ if( hrnIDs == null ) {
+ hrnIDs = new HashSet<Integer>();
+ }
+ hrnIDs.add( hrn.getID() );
+ pi2r_id.put( paramIndex, hrnIDs );
+
+ // the regions allocation site (if any)
+ AllocationSite as = hrn.getAllocationSite();
+ if( as != null ) {
+ Set<AllocationSite> asSet = pi2r_as.get( paramIndex );
+ if( asSet == null ) {
+ asSet = new HashSet<AllocationSite>();
+ }
+ asSet.add( as );
+ pi2r_as.put( paramIndex, asSet );
+
+ // and if there is an allocation site, grab type
+ Set<TypeDescriptor> tdSet = pi2r_td.get( paramIndex );
+ if( tdSet == null ) {
+ tdSet = new HashSet<TypeDescriptor>();
+ }
+ tdSet.add( as.getType() );
+ pi2r_td.put( paramIndex, tdSet );
+ }
}
+
// this family of "gets" returns, for some
// parameter index, all of the associated data
// that parameter might decompose into
- public Set<Integer>
- getHeapRegionNodeIDs( Integer paramIndex ) {
- return null;
+ public Set<Integer> getParamObject_hrnIDs( Integer paramIndex ) {
+ Set<Integer> hrnIDs = pi2a_id.get( paramIndex );
+ if( hrnIDs == null ) {
+ hrnIDs = new HashSet<Integer>();
+ }
+ return hrnIDs;
}
- public Set<HeapRegionNode>
- getHeapRegionNodes( Integer paramIndex ) {
- return null;
+ public Set<AllocationSite> getParamObject_allocSites( Integer paramIndex ) {
+ Set<AllocationSite> asSet = pi2a_as.get( paramIndex );
+ if( asSet == null ) {
+ asSet = new HashSet<AllocationSite>();
+ }
+ return asSet;
}
- public Set<AllocationSite>
- getAllocationSites( Integer paramIndex ) {
- return null;
+ public Set<TypeDescriptor> getParamObject_TypeDescs( Integer paramIndex ) {
+ Set<TypeDescriptor> tdSet = pi2a_td.get( paramIndex );
+ if( tdSet == null ) {
+ tdSet = new HashSet<TypeDescriptor>();
+ }
+ return tdSet;
}
- public Set<TypeDescriptor>
- getTypeDescriptors( Integer paramIndex ) {
- return null;
+
+ public Set<Integer> getParamReachable_hrnIDs( Integer paramIndex ) {
+ Set<Integer> hrnIDs = pi2r_id.get( paramIndex );
+ if( hrnIDs == null ) {
+ hrnIDs = new HashSet<Integer>();
+ }
+ return hrnIDs;
+ }
+
+ public Set<AllocationSite> getParamReachable_allocSites( Integer paramIndex ) {
+ Set<AllocationSite> asSet = pi2r_as.get( paramIndex );
+ if( asSet == null ) {
+ asSet = new HashSet<AllocationSite>();
+ }
+ return asSet;
}
+ public Set<TypeDescriptor> getParamReachable_TypeDescs( Integer paramIndex ) {
+ Set<TypeDescriptor> tdSet = pi2r_td.get( paramIndex );
+ if( tdSet == null ) {
+ tdSet = new HashSet<TypeDescriptor>();
+ }
+ return tdSet;
+ }
}
--- /dev/null
+PROGRAM1=testSingle
+PROGRAM2=testMulti
+
+SOURCE_FILES=test.java
+
+BUILDSCRIPT=~/research/Robust/src/buildscript
+
+USEMLP= -mlp 8 2 -mlpdebug # use to turn mlp on and off and make sure rest of build not broken
+BSFLAGS= -justanalyze -nooptimize -debug -garbagestats -mainclass Test -ownership -ownwritedots final -ownallocdepth 1 -enable-assertions -ownaliasfile aliases.txt
+
+all: $(PROGRAM2).bin # $(PROGRAM1).bin
+
+$(PROGRAM1).bin: $(SOURCE_FILES)
+ $(BUILDSCRIPT) $(BSFLAGS) -o $(PROGRAM1) $(SOURCE_FILES)
+
+$(PROGRAM2).bin: $(SOURCE_FILES)
+ $(BUILDSCRIPT) $(USEMLP) $(BSFLAGS) -o $(PROGRAM2) $(SOURCE_FILES)
+
+clean:
+ rm -f $(PROGRAM1).bin
+ rm -f $(PROGRAM2).bin
+ rm -fr tmpbuilddirectory
+ rm -f *~
+ rm -f *.dot
+ rm -f *.png
+ rm -f aliases.txt
+ rm -f mlpReport*txt
+ rm -f results*txt
--- /dev/null
+public class Foo {
+ public Foo f;
+ public Bar b;
+ public Foo() {}
+}
+
+public class Bar {
+ public Foo f;
+ public Bar b;
+ public Bar() {}
+}
+
+public class ChildFoo extends Foo {
+ public ChildFoo() {}
+}
+
+public class ChildBar extends Bar {
+ public ChildBar() {}
+}
+
+
+public class Test {
+
+ public static void main( String args[] ) {
+ m0();
+ }
+
+ public static void m0() {
+ Foo f1 = new Foo();
+ f1.b = new Bar();
+ f1.b.b = new ChildBar();
+ if( true ) {
+ f1.b = new Bar();
+ }
+ m1( f1 );
+ }
+
+ public static void m1( Foo f ) {
+ Bar b2 = new Bar();
+ b2.f = f;
+ b2.b = new Bar();
+ Foo f2 = new ChildFoo();
+ if( true ) {
+ f2.b = b2.b;
+ } else if( true ) {
+ f2.b = new ChildBar();
+ } else {
+ f2.b = f.b;
+ }
+ m2( f2, b2 );
+ }
+
+ public static void m2( Foo f, Bar b ) {
+ f.f = new ChildFoo();
+ b.f = new ChildFoo();
+ f.b.f = b.f;
+ }
+}