From: jjenista Date: Tue, 26 Aug 2008 22:46:56 +0000 (+0000) Subject: bug fix: when calculating methods dependent on a new result, only include methods... X-Git-Tag: buildscript^6~78 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=789358672466c333ddb80b8fce0f757243d26944;p=IRC.git bug fix: when calculating methods dependent on a new result, only include methods identified as part of the current analysis --- diff --git a/Robust/src/Analysis/CallGraph/CallGraph.java b/Robust/src/Analysis/CallGraph/CallGraph.java index 3042da3e..393a86be 100644 --- a/Robust/src/Analysis/CallGraph/CallGraph.java +++ b/Robust/src/Analysis/CallGraph/CallGraph.java @@ -100,14 +100,25 @@ public class CallGraph { /** Given a call to MethodDescriptor, lists the methods which could actually be call by that method. */ + public Set getMethodCalls(TaskDescriptor td) { + return getMethodCalls( (Descriptor) td ); + } + public Set getMethodCalls(MethodDescriptor md) { + return getMethodCalls( (Descriptor) md ); + } + + public Set getMethodCalls(Descriptor d) { + assert d instanceof MethodDescriptor || + d instanceof TaskDescriptor; + HashSet ns=new HashSet(); - ns.add(md); - Set s=(Set)mapCaller2CalleeSet.get(md); + ns.add(d); + Set s=(Set)mapCaller2CalleeSet.get(d); if (s!=null) for(Iterator it=s.iterator(); it.hasNext();) { - MethodDescriptor md2=(MethodDescriptor)it.next(); - ns.addAll(getMethodCalls(md2)); + MethodDescriptor md=(MethodDescriptor)it.next(); + ns.addAll(getMethodCalls(md)); } return ns; } @@ -169,66 +180,123 @@ public class CallGraph { } } - public void writeToDot(String graphName) throws java.io.IOException { - // each task or method only needs to be labeled once - // in a dot file + + public void writeVirtual2ImplemToDot(String graphName) throws java.io.IOException { HashSet labeledInDot = new HashSet(); - // write out the call graph using the callees mapping - BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+"byCallees.dot") ); - bw.write("digraph "+graphName+"byCallees {\n"); - Iterator mapItr = mapCallee2CallerSet.entrySet().iterator(); + BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") ); + bw.write("digraph "+graphName+" {\n"); + Iterator mapItr = mapVirtual2ImplementationSet.entrySet().iterator(); while( mapItr.hasNext() ) { - Map.Entry me = (Map.Entry)mapItr.next(); - MethodDescriptor callee = (MethodDescriptor) me.getKey(); - HashSet callerSet = (HashSet) me.getValue(); + Map.Entry me = (Map.Entry) mapItr.next(); + MethodDescriptor virtual = (MethodDescriptor) me.getKey(); + HashSet implemSet = (HashSet) me.getValue(); - if( !labeledInDot.contains(callee) ) { - labeledInDot.add(callee); - bw.write(" " + callee.getNum() + "[label=\"" + callee + "\"];\n"); + if( !labeledInDot.contains(virtual) ) { + labeledInDot.add(virtual); + bw.write(" "+virtual.getNum()+"[label=\""+virtual+"\"];\n"); } - Iterator callerItr = callerSet.iterator(); - while( callerItr.hasNext() ) { - Descriptor caller = (Descriptor) callerItr.next(); + Iterator implemItr = implemSet.iterator(); + while( implemItr.hasNext() ) { + Descriptor implem = (Descriptor) implemItr.next(); - if( !labeledInDot.contains(caller) ) { - labeledInDot.add(caller); - bw.write(" " + caller.getNum() + "[label=\"" + caller + "\"];\n"); + if( !labeledInDot.contains(implem) ) { + labeledInDot.add(implem); + bw.write(" "+implem.getNum()+"[label=\""+implem+"\"];\n"); } - bw.write(" " + callee.getNum() + "->" + caller.getNum() + ";\n"); + bw.write(" "+virtual.getNum()+"->"+implem.getNum()+";\n"); } } bw.write("}\n"); bw.close(); + } + + public void writeCaller2CalleesToDot(String graphName) throws java.io.IOException { // write out the call graph (should be equivalent) by // using the callers mapping - labeledInDot = new HashSet(); - bw = new BufferedWriter(new FileWriter(graphName+"byCallers.dot") ); + HashSet labeledInDot = new HashSet(); + BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+"byCallers.dot") ); bw.write("digraph "+graphName+"byCallers {\n"); - mapItr = mapCaller2CalleeSet.entrySet().iterator(); + Iterator mapItr = mapCaller2CalleeSet.entrySet().iterator(); while( mapItr.hasNext() ) { Map.Entry me = (Map.Entry)mapItr.next(); Descriptor caller = (Descriptor) me.getKey(); HashSet calleeSet = (HashSet) me.getValue(); + String callerString = caller.toString().replaceAll("[\\W]", ""); + + /* if( !labeledInDot.contains(caller) ) { labeledInDot.add(caller); - bw.write(" " + caller.getNum() + "[label=\"" + caller + "\"];\n"); + bw.write(" " + caller.getNum() + "[label=\"" + callerString + "\"];\n"); } + */ Iterator calleeItr = calleeSet.iterator(); while( calleeItr.hasNext() ) { MethodDescriptor callee = (MethodDescriptor) calleeItr.next(); + String calleeString = callee.toString().replaceAll("[\\W]", ""); + + /* if( !labeledInDot.contains(callee) ) { labeledInDot.add(callee); - bw.write(" " + callee.getNum() + "[label=\"" + callee + "\"];\n"); + bw.write(" " + callee.getNum() + "[label=\"" + calleeString + "\"];\n"); } + */ + bw.write(" " + caller.getNum() + "->" + callee.getNum() + ";\n"); + + + //bw.write(" " + callerString + "->" + calleeString + ";\n"); + } + } + bw.write("}\n"); + bw.close(); + } + + + public void writeCallee2CallersToDot(String graphName) throws java.io.IOException { + // each task or method only needs to be labeled once + // in a dot file + HashSet labeledInDot = new HashSet(); + + // write out the call graph using the callees mapping + BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+"byCallees.dot") ); + bw.write("digraph "+graphName+"byCallees {\n"); + Iterator mapItr = mapCallee2CallerSet.entrySet().iterator(); + while( mapItr.hasNext() ) { + Map.Entry me = (Map.Entry)mapItr.next(); + MethodDescriptor callee = (MethodDescriptor) me.getKey(); + HashSet callerSet = (HashSet) me.getValue(); + + String calleeString = callee.toString().replaceAll("[\\W]", ""); + + /* + if( !labeledInDot.contains(callee) ) { + labeledInDot.add(callee); + bw.write(" " + callee.getNum() + "[label=\"" + calleeString + "\"];\n"); + } + */ + + Iterator callerItr = callerSet.iterator(); + while( callerItr.hasNext() ) { + Descriptor caller = (Descriptor) callerItr.next(); + String callerString = caller.toString().replaceAll("[\\W]", ""); + + /* + if( !labeledInDot.contains(caller) ) { + labeledInDot.add(caller); + bw.write(" " + caller.getNum() + "[label=\"" + callerString + "\"];\n"); + } + */ + + bw.write(" " + caller.getNum() + "->" + callee.getNum() + ";\n"); + - bw.write(" " + callee.getNum() + "->" + caller.getNum() + ";\n"); + //bw.write(" " + callerString + "->" + calleeString + ";\n"); } } bw.write("}\n"); diff --git a/Robust/src/Analysis/OwnershipAnalysis/OwnershipAnalysis.java b/Robust/src/Analysis/OwnershipAnalysis/OwnershipAnalysis.java index a67ac4e3..1c246e2a 100644 --- a/Robust/src/Analysis/OwnershipAnalysis/OwnershipAnalysis.java +++ b/Robust/src/Analysis/OwnershipAnalysis/OwnershipAnalysis.java @@ -175,7 +175,6 @@ public class OwnershipAnalysis { // processing all methods in the program, and by methods // TaskDescriptor and MethodDescriptor are combined // together, with a common parent class Descriptor - private HashSet descriptorsToVisit; private Hashtable mapDescriptorToCompleteOwnershipGraph; private Hashtable mapFlatNewToAllocationSite; private Hashtable > mapDescriptorToAllocationSiteSet; @@ -186,6 +185,18 @@ public class OwnershipAnalysis { private Hashtable mapFlatNodeToOwnershipGraph; private HashSet returnNodesToCombineForCompleteOwnershipGraph; + // descriptorsToAnalyze identifies the set of tasks and methods + // that are reachable from the program tasks, this set is initialized + // and then remains static + private HashSet descriptorsToAnalyze; + + // descriptorsToVisit is initialized to descriptorsToAnalyze and is + // reduced by visiting a descriptor during analysis. When dependents + // must be scheduled, only those contained in descriptorsToAnalyze + // should be re-added to this set + private HashSet descriptorsToVisit; + + // this analysis generates an ownership graph for every task // in the program @@ -197,7 +208,7 @@ public class OwnershipAnalysis { this.allocationDepth = allocationDepth; - descriptorsToVisit = new HashSet(); + descriptorsToAnalyze = new HashSet(); mapDescriptorToCompleteOwnershipGraph = new Hashtable(); @@ -208,10 +219,6 @@ public class OwnershipAnalysis { mapDescriptorToAllocationSiteSet = new Hashtable >(); - // use this set to prevent infinite recursion when - // traversing the call graph - HashSet calleesScheduled = new HashSet(); - // initialize methods to visit as the set of all tasks in the // program and then any method that could be called starting @@ -219,16 +226,13 @@ public class OwnershipAnalysis { Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator(); while( taskItr.hasNext() ) { Descriptor d = (Descriptor) taskItr.next(); - descriptorsToVisit.add(d); - - // recursively find all callees from this task - scheduleAllCallees(calleesScheduled, d); + scheduleAllCallees(d); } // before beginning analysis, initialize every scheduled method // with an ownership graph that has populated parameter index tables // by analyzing the first node which is always a FlatMethod node - Iterator dItr = calleesScheduled.iterator(); + Iterator dItr = descriptorsToAnalyze.iterator(); while( dItr.hasNext() ) { Descriptor d = dItr.next(); OwnershipGraph og = new OwnershipGraph(allocationDepth); @@ -252,25 +256,27 @@ public class OwnershipAnalysis { // called from the constructor to help initialize the set // of methods that needs to be analyzed by ownership analysis - private void scheduleAllCallees(HashSet calleesScheduled, - Descriptor d) { - if( calleesScheduled.contains(d) ) { + private void scheduleAllCallees(Descriptor d) { + if( descriptorsToAnalyze.contains(d) ) { return; } - calleesScheduled.add(d); + descriptorsToAnalyze.add(d); - Set callees = callGraph.getCalleeSet(d); - if( callees == null ) { - return; + // start with all method calls to further schedule + Set moreMethodsToCheck = moreMethodsToCheck = callGraph.getMethodCalls( d ); + + if( d instanceof MethodDescriptor ) { + // see if this method has virtual dispatch + Set virtualMethods = callGraph.getMethods( (MethodDescriptor)d ); + moreMethodsToCheck.addAll( virtualMethods ); } - Iterator methItr = callees.iterator(); + // keep following any further methods identified in + // the call chain + Iterator methItr = moreMethodsToCheck.iterator(); while( methItr.hasNext() ) { - MethodDescriptor md = (MethodDescriptor) methItr.next(); - descriptorsToVisit.add(md); - - // recursively find all callees from this task - scheduleAllCallees(calleesScheduled, md); + Descriptor m = (Descriptor) methItr.next(); + scheduleAllCallees(m); } } @@ -279,6 +285,8 @@ public class OwnershipAnalysis { // and be sure to reschedule tasks/methods when the methods // they call are updated private void analyzeMethods() throws java.io.IOException { + + descriptorsToVisit = (HashSet)descriptorsToAnalyze.clone(); while( !descriptorsToVisit.isEmpty() ) { Descriptor d = (Descriptor) descriptorsToVisit.iterator().next(); @@ -313,7 +321,7 @@ public class OwnershipAnalysis { boolean pruneGarbage, boolean writeReferencers */ - og.writeGraph(d, true, true, true, false); + og.writeGraph(d, true, true, false, false); // only methods have dependents, tasks cannot // be invoked by any user program calls @@ -321,7 +329,13 @@ public class OwnershipAnalysis { MethodDescriptor md = (MethodDescriptor) d; Set dependents = callGraph.getCallerSet(md); if( dependents != null ) { - descriptorsToVisit.addAll(dependents); + Iterator depItr = dependents.iterator(); + while( depItr.hasNext() ) { + Descriptor dependent = (Descriptor) depItr.next(); + if( descriptorsToAnalyze.contains( dependent ) ) { + descriptorsToVisit.add(dependent); + } + } } } } @@ -330,9 +344,6 @@ public class OwnershipAnalysis { } - int x = 0; - - // keep passing the Descriptor of the method along for debugging // and dot file writing private OwnershipGraph @@ -386,16 +397,6 @@ public class OwnershipAnalysis { if( !og.equals(ogPrev) ) { setGraphForFlatNode(fn, og); - - - x++; - if( x > 0 ) { - String s = String.format("debug%04d", x); - //og.writeGraph( s, true, true, true, false ); - } - - - for( int i = 0; i < fn.numNext(); i++ ) { FlatNode nn = fn.getNext(i); flatNodesToVisit.add(nn); @@ -483,55 +484,32 @@ public class OwnershipAnalysis { break; case FKind.FlatCall: - FlatCall fc = (FlatCall) fn; - MethodDescriptor md = fc.getMethod(); - FlatMethod flatm = state.getMethodFlat(md); - //HashSet allocSiteSet = getAllocationSiteSet( md ); - OwnershipGraph ogAllPossibleCallees = new OwnershipGraph(allocationDepth); + FlatCall fc = (FlatCall) fn; + MethodDescriptor md = fc.getMethod(); + FlatMethod flatm = state.getMethodFlat(md); + OwnershipGraph ogAllPossibleCallees = new OwnershipGraph(allocationDepth); if( md.isStatic() ) { // a static method is simply always the same, makes life easy OwnershipGraph onlyPossibleCallee = mapDescriptorToCompleteOwnershipGraph.get(md); ogAllPossibleCallees.merge(onlyPossibleCallee); - /* - if( onlyPossibleCallee != null ) { - onlyPossibleCallee.writeGraph( "only", false, false ); - System.out.println( "There was only one possible callee, "+md ); - } - */ - } else { // if the method descriptor is virtual, then there could be a // set of possible methods that will actually be invoked, so // find all of them and merge all of their graphs together - TypeDescriptor typeDesc = fc.getThis().getType(); + TypeDescriptor typeDesc = fc.getThis().getType(); Set possibleCallees = callGraph.getMethods(md, typeDesc); - //int j = 0; - Iterator i = possibleCallees.iterator(); while( i.hasNext() ) { MethodDescriptor possibleMd = (MethodDescriptor) i.next(); - //allocSiteSet.addAll( getAllocationSiteSet( possibleMd ) ); OwnershipGraph ogPotentialCallee = mapDescriptorToCompleteOwnershipGraph.get(possibleMd); - - /* - if( ogPotentialCallee != null ) { - ogPotentialCallee.writeGraph( "potential"+j, false, false ); - ++j; - } - */ - ogAllPossibleCallees.merge(ogPotentialCallee); } - - //System.out.println( "There were "+j+" potential callees merged together." ); } - - //System.out.println( "AllocationSiteSet has "+allocSiteSet.size()+" items." ); - - // now we should have the following information to resolve this method call: + + // Now we should have the following information to resolve this method call: // // 1. A FlatCall fc to query for the caller's context (argument labels, etc) // @@ -545,9 +523,6 @@ public class OwnershipAnalysis { // 4. The OwnershipGraph ogAllPossibleCallees is a merge of every ownership graph of all the possible // methods to capture any possible references made. // - // 5. The Set of AllocationSite objects, allocSiteSet that is the set of allocation sites from - // every possible method we might have chosen - // og.resolveMethodCall(fc, md.isStatic(), flatm, ogAllPossibleCallees); break; diff --git a/Robust/src/Tests/OwnershipAnalysisTest/test02/makefile b/Robust/src/Tests/OwnershipAnalysisTest/test02/makefile index 65cc0bbd..4281e17d 100644 --- a/Robust/src/Tests/OwnershipAnalysisTest/test02/makefile +++ b/Robust/src/Tests/OwnershipAnalysisTest/test02/makefile @@ -1,4 +1,4 @@ -PROGRAM=test01 +PROGRAM=test02 SOURCE_FILES=$(PROGRAM).java diff --git a/Robust/src/Tests/OwnershipAnalysisTest/test02/test02.java b/Robust/src/Tests/OwnershipAnalysisTest/test02/test02.java index 03aedb9b..7aad47c1 100644 --- a/Robust/src/Tests/OwnershipAnalysisTest/test02/test02.java +++ b/Robust/src/Tests/OwnershipAnalysisTest/test02/test02.java @@ -18,6 +18,46 @@ public class Penguin { public void bar() { x = 1; } } +public class Voo { + flag f; int x; Baw b; Baw bb; + + public Voo() {} +} + +public class Baw { + int y; + Foo f; + + public Baw() {} + + public void doTheBaw( Voo v ) { v = new Voo(); } +} + +public class Foo { + flag f; + + public Foo() {} + + public Foo x; + public Foo y; + public Foo z; + + public void ruinSomeFoos( Foo a, Foo b ) { + a.x = b.x; + } + + static public void aStaticMethod( Foo p0, Foo p1 ) { + Foo f0 = new Foo(); + Foo f1 = new Foo(); + Foo f2 = new Foo(); + + f0.x = f1; + p0.x = f0; + p1.x = f1; + p1.x = f2; + } +} + task Startup( StartupObject s{ initialstate } ) { /* diff --git a/Robust/src/Tests/OwnershipAnalysisTest/test03/makefile b/Robust/src/Tests/OwnershipAnalysisTest/test03/makefile index 65cc0bbd..78e3c5bd 100644 --- a/Robust/src/Tests/OwnershipAnalysisTest/test03/makefile +++ b/Robust/src/Tests/OwnershipAnalysisTest/test03/makefile @@ -1,4 +1,4 @@ -PROGRAM=test01 +PROGRAM=test03 SOURCE_FILES=$(PROGRAM).java