Altered ownership graph to dot file by removing label nodes, marking allocation
[IRC.git] / Robust / src / Analysis / OwnershipAnalysis / OwnershipAnalysis.java
index 314b9d0c014390b1a4dca46bcf690b656923c583..894674ec8c3c05ecfe0fd021dafb298debbd8f8f 100644 (file)
@@ -1,5 +1,6 @@
 package Analysis.OwnershipAnalysis;
 
+import Analysis.CallGraph.*;
 import IR.*;
 import IR.Flat.*;
 import java.util.*;
@@ -8,205 +9,442 @@ import java.io.*;
 
 public class OwnershipAnalysis {
 
-    
-    private State state;
-    private HashSet<FlatNode> visited;
-    private HashSet<FlatNode> toVisit;
+    // from the compiler
+    private State     state;
+    private CallGraph callGraph;
+    private int       allocationDepth;
 
-    private int labelindex;
-    private Hashtable<FlatNode, Integer> flatnodetolabel;
 
-    private Hashtable<FlatNode, OwnershipGraph> flatNodeToOwnershipGraph;
+    // used to identify HeapRegionNode objects
+    // A unique ID equates an object in one
+    // ownership graph with an object in another
+    // graph that logically represents the same
+    // heap region
+    static private int uniqueIDcount = 0;
+
+
+    // Use these data structures to track progress of 
+    // processing all methods in the program, and by methods
+    // TaskDescriptor and MethodDescriptor are combined 
+    // together, with a common parent class Descriptor
+    private HashSet  <Descriptor>                           descriptorsToVisit;
+    private Hashtable<Descriptor, OwnershipGraph>           mapDescriptorToCompleteOwnershipGraph;
+    private Hashtable<FlatNew,    AllocationSite>           mapFlatNewToAllocationSite;
+    private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
+
+    // Use these data structures to track progress of one pass of
+    // processing the FlatNodes of a particular method
+    private HashSet  <FlatNode>                 flatNodesToVisit;
+    private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;    
+    private HashSet  <FlatReturnNode>           returnNodesToCombineForCompleteOwnershipGraph;
 
-    private int newDepthK;
 
     // this analysis generates an ownership graph for every task
     // in the program
-    public OwnershipAnalysis( State state ) throws java.io.IOException {
-       this.state=state;      
-       this.newDepthK = 3;
-       analyzeTasks();
+    public OwnershipAnalysis( State     state,
+                             CallGraph callGraph, 
+                             int       allocationDepth ) throws java.io.IOException {
+       this.state           = state;      
+       this.callGraph       = callGraph;
+       this.allocationDepth = allocationDepth;
+
+       descriptorsToVisit = new HashSet<Descriptor>();
+
+       mapDescriptorToCompleteOwnershipGraph =
+           new Hashtable<Descriptor, OwnershipGraph>();
+
+       mapFlatNewToAllocationSite =
+           new Hashtable<FlatNew, AllocationSite>();
+
+       mapDescriptorToAllocationSiteSet =
+           new Hashtable<Descriptor, HashSet<AllocationSite> >();
+
+       // use this set to prevent infinite recursion when
+       // traversing the call graph
+       HashSet<Descriptor> calleesScheduled = new HashSet<Descriptor>();
+
+       // initialize methods to visit as the set of all tasks in the
+       // program and then any method that could be called starting
+       // from those tasks
+       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 );
+       }
+       
+       // as mentioned above, analyze methods one-by-one, possibly revisiting
+       // a method if the methods that it calls are updated
+       analyzeMethods();
     }
 
+    // called from the constructor to help initialize the set
+    // of methods that needs to be analyzed by ownership analysis
+    private void scheduleAllCallees( HashSet<Descriptor> calleesScheduled,
+                                    Descriptor d ) {
+       if( calleesScheduled.contains( d ) ) {
+           return;
+       }
+       calleesScheduled.add( d );
 
-    public void analyzeTasks() throws java.io.IOException {
-       for( Iterator it_tasks=state.getTaskSymbolTable().getDescriptorsIterator();
-            it_tasks.hasNext();
-            ) {
-
-           // initialize the mapping of flat nodes to ownership graphs
-           // every flat node in the IR graph has its own ownership graph
-           flatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
-
-           TaskDescriptor td = (TaskDescriptor) it_tasks.next();
-           FlatMethod     fm = state.getMethodFlat( td );
+       Set callees = callGraph.getCalleeSet( d );
+       if( callees == null ) {
+           return;
+       }
 
-           // give every node in the flat IR graph a unique label
-           // so a human being can inspect the graph and verify
-           // correctness
-           flatnodetolabel = new Hashtable<FlatNode, Integer>();
-           visited         = new HashSet<FlatNode>();
-           labelindex      = 0;
-           labelFlatNodes( fm );
+       Iterator methItr = callees.iterator();
+       while( methItr.hasNext() ) {
+           MethodDescriptor md = (MethodDescriptor) methItr.next();
+           descriptorsToVisit.add( md );
 
-           String taskname = td.getSymbol();
-           analyzeFlatIRGraph( fm, taskname );
-       }       
+           // recursively find all callees from this task
+           scheduleAllCallees( calleesScheduled, md );
+       }
     }
 
-    private void labelFlatNodes( FlatNode fn ) {
-       visited.add( fn );
-       flatnodetolabel.put( fn, new Integer( labelindex++ ) );
-       for( int i = 0; i < fn.numNext(); i++ ) {
-           FlatNode nn = fn.getNext( i );
-           if( !visited.contains( nn ) ) {
-               labelFlatNodes( nn );
+
+    // manage the set of tasks and methods to be analyzed
+    // and be sure to reschedule tasks/methods when the methods
+    // they call are updated
+    private void analyzeMethods() throws java.io.IOException {
+       
+       while( !descriptorsToVisit.isEmpty() ) {
+           Descriptor d = (Descriptor) descriptorsToVisit.iterator().next();
+           descriptorsToVisit.remove( d );
+
+           // because the task or method descriptor just extracted
+           // was in the "to visit" set it either hasn't been analyzed
+           // yet, or some method that it depends on has been
+           // updated.  Recompute a complete ownership graph for
+           // this task/method and compare it to any previous result.
+           // If there is a change detected, add any methods/tasks
+           // that depend on this one to the "to visit" set.
+
+           System.out.println( "Analyzing " + d );
+
+           FlatMethod fm;
+           if( d instanceof MethodDescriptor ) {
+               fm = state.getMethodFlat( (MethodDescriptor) d );
+           } else {
+               assert d instanceof TaskDescriptor;
+               fm = state.getMethodFlat( (TaskDescriptor) d );
+           }
+           
+           OwnershipGraph og     = analyzeFlatMethod( d, fm );
+           OwnershipGraph ogPrev = mapDescriptorToCompleteOwnershipGraph.get( d );
+
+           if( !og.equals( ogPrev ) ) {
+               mapDescriptorToCompleteOwnershipGraph.put( d, og );
+
+               og.writeGraph( d );
+
+               // only methods have dependents, tasks cannot
+               // be invoked by any user program calls
+               if( d instanceof MethodDescriptor ) {
+                   MethodDescriptor md = (MethodDescriptor) d;
+                   Set dependents = callGraph.getCallerSet( md );
+                   if( dependents != null ) {
+                       descriptorsToVisit.addAll( dependents );
+                   }
+               }
            }
        }
+
     }
 
-    private OwnershipGraph getGraphFromFlat( FlatNode fn ) {
-       if( !flatNodeToOwnershipGraph.containsKey( fn ) ) {
-           flatNodeToOwnershipGraph.put( fn, new OwnershipGraph( newDepthK ) );
-       }
 
-       return flatNodeToOwnershipGraph.get( fn );
-    }
+    // keep passing the Descriptor of the method along for debugging
+    // and dot file writing
+    private OwnershipGraph
+       analyzeFlatMethod( Descriptor mDesc,
+                          FlatMethod flatm ) throws java.io.IOException {
 
-    private void setGraphForFlat( FlatNode fn, OwnershipGraph og ) {
-       flatNodeToOwnershipGraph.put( fn, og );
-    }
+       // initialize flat nodes to visit as the flat method
+       // because all other nodes in this flat method are 
+       // decendents of the flat method itself
+       flatNodesToVisit = new HashSet<FlatNode>();
+       flatNodesToVisit.add( flatm );
 
-    private void analyzeFlatIRGraph( FlatMethod flatm, String taskname ) throws java.io.IOException {
-       visited=new HashSet<FlatNode>();
-       toVisit=new HashSet<FlatNode>();
-       toVisit.add( flatm );
+       // initilize the mapping of flat nodes in this flat method to
+       // ownership graph results to an empty mapping
+       mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
 
-       while( !toVisit.isEmpty() ) {
-           FlatNode fn = (FlatNode)toVisit.iterator().next();
-           toVisit.remove( fn );
-           visited.add( fn );
+       // initialize the set of return nodes that will be combined as
+       // the final ownership graph result to return as an empty set
+       returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
+
+       while( !flatNodesToVisit.isEmpty() ) {
+           FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
+           flatNodesToVisit.remove( fn );
 
            // perform this node's contributions to the ownership
            // graph on a new copy, then compare it to the old graph
            // at this node to see if anything was updated.
-           OwnershipGraph og = new OwnershipGraph( newDepthK );
+           OwnershipGraph og = new OwnershipGraph( allocationDepth );
 
-           // start by merging all incoming node's graphs
+           // start by merging all node's parents' graphs
            for( int i = 0; i < fn.numPrev(); ++i ) {
                FlatNode       pn       = fn.getPrev( i );
-               OwnershipGraph ogParent = getGraphFromFlat( pn );
+               OwnershipGraph ogParent = getGraphFromFlatNode( pn );
                og.merge( ogParent );
            }
            
-           TempDescriptor  src;
-           TempDescriptor  dst;
-           FieldDescriptor fld;
-           String nodeDescription = "No description";
-           boolean writeGraph = false;
-
-           // use node type to decide what alterations to make
-           // to the ownership graph       
-           switch( fn.kind() ) {
-               
-           case FKind.FlatMethod:
-               FlatMethod fm = (FlatMethod) fn;
-
-               // add method parameters to the list of heap regions
-               // and remember names for analysis
-               for( int i = 0; i < fm.numParameters(); ++i ) {
-                   TempDescriptor tdParam = fm.getParameter( i );
-                   og.parameterAllocation( tdParam );
-                   og.addAnalysisRegion( tdParam );
-               }
-
-               nodeDescription = "Method";
-               writeGraph = true;
-               break;
-
-           case FKind.FlatOpNode:
-               FlatOpNode fon = (FlatOpNode) fn;
-               if( fon.getOp().getOp() == Operation.ASSIGN ) {
-                   src = fon.getLeft();
-                   dst = fon.getDest();
-                   og.assignTempToTemp( src, dst );
-                   nodeDescription = "Op";
-                   writeGraph = true;
-               }
-               break;
-
-           case FKind.FlatFieldNode:
-               FlatFieldNode ffn = (FlatFieldNode) fn;
-               src = ffn.getSrc();
-               dst = ffn.getDst();
-               fld = ffn.getField();
-               if( !fld.getType().isPrimitive() ) {
-                   og.assignTempToField( src, dst, fld );
-                   nodeDescription = "Field";
-                   writeGraph = true;
-               }
-               break;
-
-           case FKind.FlatSetFieldNode:
-               FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
-               src = fsfn.getSrc();
-               dst = fsfn.getDst();
-               fld = fsfn.getField();
-               og.assignFieldToTemp( src, dst, fld );
-               nodeDescription = "SetField";
-               writeGraph = true;
-               break;
-
-           case FKind.FlatNew:
-               FlatNew fnn = (FlatNew) fn;
-               dst = fnn.getDst();
-               og.assignTempToNewAllocation( dst, fnn );
-
-               // !!!!!!!!!!!!!!
-               // do this if the new object is a flagged type
-               //og.addAnalysisRegion( tdParam );
-
-               nodeDescription = "New";
-               writeGraph = true;
-               break;
-
-           case FKind.FlatReturnNode:
-               nodeDescription = "Return";
-               writeGraph = true;
-               og.writeCondensedAnalysis( makeCondensedAnalysisName( taskname, flatnodetolabel.get(fn) ) );
-               break;
-           }
-
-           if( writeGraph ) {
-               og.writeGraph( makeNodeName( taskname, 
-                                            flatnodetolabel.get( fn ), 
-                                            nodeDescription ) );
-           }
+           // apply the analysis of the flat node to the
+           // ownership graph made from the merge of the
+           // parent graphs
+           analyzeFlatNode( mDesc,
+                            fn, 
+                            returnNodesToCombineForCompleteOwnershipGraph,
+                            og );
            
            // if the results of the new graph are different from
            // the current graph at this node, replace the graph
            // with the update and enqueue the children for
            // processing
-           OwnershipGraph ogOld = getGraphFromFlat( fn );
+           OwnershipGraph ogPrev = getGraphFromFlatNode( fn );
 
-           if( !og.equals( ogOld ) ) {
-               setGraphForFlat( fn, og );
+           if( !og.equals( ogPrev ) ) {
+               setGraphForFlatNode( fn, og );
 
                for( int i = 0; i < fn.numNext(); i++ ) {
-                   FlatNode nn = fn.getNext( i );
-                   visited.remove( nn );
-                   toVisit.add( nn );
+                   FlatNode nn = fn.getNext( i );                
+                   flatNodesToVisit.add( nn );
                }
            }
        }
+
+       // end by merging all return nodes into a complete
+       // ownership graph that represents all possible heap
+       // states after the flat method returns
+       OwnershipGraph completeGraph = new OwnershipGraph( allocationDepth );
+       Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
+       while( retItr.hasNext() ) {
+           FlatReturnNode frn = (FlatReturnNode) retItr.next();
+           OwnershipGraph ogr = getGraphFromFlatNode( frn );
+           completeGraph.merge( ogr );
+       }
+       return completeGraph;
     }
 
-    private String makeNodeName( String taskname, Integer id, String type ) {
-       String s = String.format( "%05d", id );
-       return "task"+taskname+"_FN"+s+"_"+type;
+
+    private void 
+       analyzeFlatNode( Descriptor              methodDesc,
+                        FlatNode                fn,
+                        HashSet<FlatReturnNode> setRetNodes,
+                        OwnershipGraph          og ) throws java.io.IOException {
+
+       TempDescriptor  src;
+       TempDescriptor  dst;
+       FieldDescriptor fld;
+
+       // use node type to decide what alterations to make
+       // to the ownership graph           
+       switch( fn.kind() ) {
+           
+       case FKind.FlatMethod:
+           FlatMethod fm = (FlatMethod) fn;
+
+           // there should only be one FlatMethod node as the
+           // parent of all other FlatNode objects, so take
+           // the opportunity to construct the initial graph by
+           // adding parameters labels to new heap regions
+           for( int i = 0; i < fm.numParameters(); ++i ) {
+               TempDescriptor tdParam = fm.getParameter( i );
+               og.assignTempToParameterAllocation( methodDesc instanceof TaskDescriptor,
+                                                   tdParam,
+                                                   new Integer( i ) );
+               //og.writeGraph( methodDesc, fn );
+           }
+
+           break;
+
+       case FKind.FlatOpNode:
+           FlatOpNode fon = (FlatOpNode) fn;
+           if( fon.getOp().getOp() == Operation.ASSIGN ) {
+               src = fon.getLeft();
+               dst = fon.getDest();
+               og.assignTempToTemp( src, dst );
+               //og.writeGraph( methodDesc, fn );
+           }
+           break;
+           
+       case FKind.FlatFieldNode:
+           FlatFieldNode ffn = (FlatFieldNode) fn;
+           src = ffn.getSrc();
+           dst = ffn.getDst();
+           fld = ffn.getField();
+           if( !fld.getType().isPrimitive() ) {
+               og.assignTempToField( src, dst, fld );
+               //og.writeGraph( methodDesc, fn );
+           }
+           break;
+           
+       case FKind.FlatSetFieldNode:
+           FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
+           src = fsfn.getSrc();
+           dst = fsfn.getDst();
+           fld = fsfn.getField();
+           og.assignFieldToTemp( src, dst, fld );
+           //og.writeGraph( methodDesc, fn );
+           break;
+           
+       case FKind.FlatNew:
+           FlatNew fnn = (FlatNew) fn;
+            dst = fnn.getDst();
+           AllocationSite as = getAllocationSiteFromFlatNew( fnn );
+
+           og.assignTempToNewAllocation( dst, as );
+           break;
+
+       case FKind.FlatCall:
+           FlatCall                fc           = (FlatCall) fn;
+           MethodDescriptor        md           = fc.getMethod();
+           FlatMethod              flatm        = state.getMethodFlat( md );
+           HashSet<AllocationSite> allocSiteSet = getAllocationSiteSet( 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 );
+
+           } 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();
+               Set            possibleCallees = callGraph.getMethods( md, typeDesc );
+
+               Iterator i = possibleCallees.iterator();
+               while( i.hasNext() ) {
+                   MethodDescriptor possibleMd = (MethodDescriptor) i.next();
+                   allocSiteSet.addAll( getAllocationSiteSet( possibleMd ) );
+                   OwnershipGraph ogPotentialCallee = mapDescriptorToCompleteOwnershipGraph.get( possibleMd );
+                   ogAllPossibleCallees.merge( ogPotentialCallee );
+               }
+           }
+
+           // 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)
+           //
+           // 2. Whether the method is static; if not we need to deal with the "this" pointer
+           //
+           // *******************************************************************************************
+           // 3. The original FlatMethod flatm to query for callee's context (paramter labels)
+           //   NOTE!  I assume FlatMethod before virtual dispatch accurately describes all possible methods!
+           // *******************************************************************************************
+           //
+           // 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, allocSiteSet );
+
+           //og.writeGraph( methodDesc, fn );
+           break;
+
+       case FKind.FlatReturnNode:
+           FlatReturnNode frn = (FlatReturnNode) fn;
+           setRetNodes.add( frn );
+           //og.writeGraph( methodDesc, fn );
+           break;
+       }
+    }
+
+
+    static public Integer generateUniqueHeapRegionNodeID() {
+       ++uniqueIDcount;
+       return new Integer( uniqueIDcount );
+    }    
+
+
+    private OwnershipGraph getGraphFromFlatNode( FlatNode fn ) {
+       if( !mapFlatNodeToOwnershipGraph.containsKey( fn ) ) {
+           mapFlatNodeToOwnershipGraph.put( fn, new OwnershipGraph( allocationDepth ) );
+       }
+
+       return mapFlatNodeToOwnershipGraph.get( fn );
+    }
+
+    private void setGraphForFlatNode( FlatNode fn, OwnershipGraph og ) {
+       mapFlatNodeToOwnershipGraph.put( fn, og );
+    }
+
+
+    // return just the allocation site associated with one FlatNew node
+    private AllocationSite getAllocationSiteFromFlatNew( FlatNew fn ) {
+       if( !mapFlatNewToAllocationSite.containsKey( fn ) ) {
+           AllocationSite as = new AllocationSite( allocationDepth, fn.getType() );
+
+           // the newest nodes are single objects
+           for( int i = 0; i < allocationDepth; ++i ) {
+               Integer id = generateUniqueHeapRegionNodeID();
+               as.setIthOldest( i, id );
+           }
+
+           // the oldest node is a summary node
+           Integer idSummary = generateUniqueHeapRegionNodeID();
+           as.setSummary( idSummary );
+
+           mapFlatNewToAllocationSite.put( fn, as );
+       }
+
+       return mapFlatNewToAllocationSite.get( fn );
+    }
+
+
+    // return all allocation sites in the method (there is one allocation
+    // site per FlatNew node in a method)
+    private HashSet<AllocationSite> getAllocationSiteSet( Descriptor d ) {
+       if( !mapDescriptorToAllocationSiteSet.containsKey( d ) ) {
+           buildAllocationSiteSet( d );   
+       }
+
+       return mapDescriptorToAllocationSiteSet.get( d );
+
     }
 
-    private String makeCondensedAnalysisName( String taskname, Integer id ) {
-       return "task"+taskname+"_Ownership_from"+id;
+    private void buildAllocationSiteSet( Descriptor d ) {
+       HashSet<AllocationSite> s = new HashSet<AllocationSite>();
+
+       FlatMethod fm;
+       if( d instanceof MethodDescriptor ) {
+           fm = state.getMethodFlat( (MethodDescriptor) d );
+       } else {
+           assert d instanceof TaskDescriptor;
+           fm = state.getMethodFlat( (TaskDescriptor) d );
+       }
+
+       // visit every node in this FlatMethod's IR graph
+       // and make a set of the allocation sites from the
+       // FlatNew node's visited
+       HashSet<FlatNode> visited = new HashSet<FlatNode>();
+       HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
+       toVisit.add( fm );
+
+       while( !toVisit.isEmpty() ) {
+           FlatNode n = toVisit.iterator().next();
+
+           if( n instanceof FlatNew ) {
+               s.add( getAllocationSiteFromFlatNew( (FlatNew) n ) );
+           }
+
+           toVisit.remove( n );
+           visited.add( n );
+
+           for( int i = 0; i < n.numNext(); ++i ) {
+               FlatNode child = n.getNext( i );
+               if( !visited.contains( child ) ) {
+                   toVisit.add( child );
+               }
+           }
+       }
+
+       mapDescriptorToAllocationSiteSet.put( d, s );
     }
 }