import IR.Flat.FlatNode;
import IR.Flat.FlatCall;
import IR.Flat.FKind;
-import java.util.*;
+import IR.Descriptor;
import IR.ClassDescriptor;
import IR.MethodDescriptor;
+import IR.TaskDescriptor;
import IR.TypeDescriptor;
+import java.util.*;
+import java.io.*;
public class CallGraph {
- State state;
- Hashtable methods;
- Hashtable methodmap;
+ private State state;
+
+ // MethodDescriptor maps to HashSet<MethodDescriptor>
+ private Hashtable mapVirtual2ImplementationSet;
+
+ // MethodDescriptor or TaskDescriptor maps to HashSet<MethodDescriptor>
+ private Hashtable mapCaller2CalleeSet;
+
+ // MethodDescriptor maps to HashSet<MethodDescriptor or TaskDescriptor>
+ private Hashtable mapCallee2CallerSet;
public CallGraph(State state) {
this.state=state;
- methods=new Hashtable();
- methodmap=new Hashtable();
- buildMethodTable();
+ mapVirtual2ImplementationSet = new Hashtable();
+ mapCaller2CalleeSet = new Hashtable();
+ mapCallee2CallerSet = new Hashtable();
+ buildVirtualMap();
buildGraph();
}
- private void buildMethodTable() {
+ // build a mapping of virtual methods to all
+ // possible implementations of that method
+ private void buildVirtualMap() {
//Iterator through classes
Iterator it=state.getClassSymbolTable().getDescriptorsIterator();
while(it.hasNext()) {
for(Iterator matchit=possiblematches.iterator();matchit.hasNext();) {
MethodDescriptor matchmd=(MethodDescriptor)matchit.next();
if (md.matches(matchmd)) {
- if (!methods.containsKey(matchmd))
- methods.put(matchmd,new HashSet());
- ((HashSet)methods.get(matchmd)).add(md);
+ if (!mapVirtual2ImplementationSet.containsKey(matchmd))
+ mapVirtual2ImplementationSet.put(matchmd,new HashSet());
+ ((HashSet)mapVirtual2ImplementationSet.get(matchmd)).add(md);
break;
}
}
}
}
-
public Set getMethods(MethodDescriptor md, TypeDescriptor type) {
return getMethods(md);
}
public Set getMethods(MethodDescriptor md) {
HashSet ns=new HashSet();
ns.add(md);
- Set s=(Set)methods.get(md);
+ Set s=(Set)mapVirtual2ImplementationSet.get(md);
if (s!=null)
for(Iterator it=s.iterator();it.hasNext();) {
MethodDescriptor md2=(MethodDescriptor)it.next();
public Set getMethodCalls(MethodDescriptor md) {
HashSet ns=new HashSet();
ns.add(md);
- Set s=(Set)methodmap.get(md);
+ Set s=(Set)mapCaller2CalleeSet.get(md);
if (s!=null)
for(Iterator it=s.iterator();it.hasNext();) {
MethodDescriptor md2=(MethodDescriptor)it.next();
//Iterator through methods
while(methodit.hasNext()) {
MethodDescriptor md=(MethodDescriptor)methodit.next();
- analyzeMethod(md);
+ analyzeMethod( (Object)md, state.getMethodFlat(md) );
}
}
+ it=state.getTaskSymbolTable().getDescriptorsIterator();
+ while(it.hasNext()) {
+ TaskDescriptor td=(TaskDescriptor)it.next();
+ analyzeMethod( (Object)td, state.getMethodFlat(td) );
+ }
}
- private void analyzeMethod(MethodDescriptor md) {
- FlatMethod fm=state.getMethodFlat(md);
+ private void analyzeMethod(Object caller, FlatMethod fm) {
HashSet toexplore=new HashSet();
toexplore.add(fm);
HashSet explored=new HashSet();
MethodDescriptor calledmethod=fc.getMethod();
Set methodsthatcouldbecalled=fc.getThis()==null?getMethods(calledmethod):
getMethods(calledmethod, fc.getThis().getType());
- if (!methodmap.containsKey(md))
- methodmap.put(md,new HashSet());
- ((HashSet)methodmap.get(md)).addAll(methodsthatcouldbecalled);
+
+ // add caller -> callee maps
+ if( !mapCaller2CalleeSet.containsKey( caller ) ) {
+ mapCaller2CalleeSet.put( caller, new HashSet() );
+ }
+ ((HashSet)mapCaller2CalleeSet.get( caller )).addAll( methodsthatcouldbecalled );
+
+ // add callee -> caller maps
+ Iterator calleeItr = methodsthatcouldbecalled.iterator();
+ while( calleeItr.hasNext() ) {
+ MethodDescriptor callee = (MethodDescriptor) calleeItr.next();
+ if( !mapCallee2CallerSet.containsKey( callee ) ) {
+ mapCallee2CallerSet.put( callee, new HashSet() );
+ }
+ ((HashSet)mapCallee2CallerSet.get( callee )).add( caller );
+ }
+ }
+ }
+ }
+
+ public void writeToDot( 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();
+
+ if( !labeledInDot.contains( callee ) ) {
+ labeledInDot.add( callee );
+ bw.write( " " + callee.getNum() + "[label=\"" + callee + "\"];\n" );
+ }
+
+ Iterator callerItr = callerSet.iterator();
+ while( callerItr.hasNext() ) {
+ Descriptor caller = (Descriptor) callerItr.next();
+
+ if( !labeledInDot.contains( caller ) ) {
+ labeledInDot.add( caller );
+ bw.write( " " + caller.getNum() + "[label=\"" + caller + "\"];\n" );
+ }
+
+ bw.write( " " + callee.getNum() + "->" + caller.getNum() + ";\n" );
+ }
+ }
+ bw.write( "}\n" );
+ bw.close();
+
+ // write out the call graph (should be equivalent) by
+ // using the callers mapping
+ labeledInDot = new HashSet();
+ bw = new BufferedWriter( new FileWriter( graphName+"byCallers.dot" ) );
+ bw.write( "digraph "+graphName+"byCallers {\n" );
+ mapItr = mapCaller2CalleeSet.entrySet().iterator();
+ while( mapItr.hasNext() ) {
+ Map.Entry me = (Map.Entry) mapItr.next();
+ Descriptor caller = (Descriptor) me.getKey();
+ HashSet calleeSet = (HashSet) me.getValue();
+
+ if( !labeledInDot.contains( caller ) ) {
+ labeledInDot.add( caller );
+ bw.write( " " + caller.getNum() + "[label=\"" + caller + "\"];\n" );
+ }
+
+ Iterator calleeItr = calleeSet.iterator();
+ while( calleeItr.hasNext() ) {
+ MethodDescriptor callee = (MethodDescriptor) calleeItr.next();
+
+ if( !labeledInDot.contains( callee ) ) {
+ labeledInDot.add( callee );
+ bw.write( " " + callee.getNum() + "[label=\"" + callee + "\"];\n" );
+ }
+
+ bw.write( " " + callee.getNum() + "->" + caller.getNum() + ";\n" );
}
}
+ bw.write( "}\n" );
+ bw.close();
}
}