3 import Analysis.CallGraph.*;
4 import Analysis.OwnershipAnalysis.*;
11 public class MLPAnalysis {
13 // data from the compiler
15 private TypeUtil typeUtil;
16 private CallGraph callGraph;
17 private OwnershipAnalysis ownAnalysis;
20 private Stack<FlatSESEEnterNode> seseStack;
21 private Set<FlatSESEEnterNode> seseRoots;
23 private Hashtable< FlatNode, Set<VariableSourceToken> > pointResults;
26 public MLPAnalysis( State state,
29 OwnershipAnalysis ownAnalysis
32 double timeStartAnalysis = (double) System.nanoTime();
36 this.callGraph = callGraph;
37 this.ownAnalysis = ownAnalysis;
39 // initialize analysis data structures
40 seseStack = new Stack <FlatSESEEnterNode>();
41 seseRoots = new HashSet<FlatSESEEnterNode>();
43 pointResults = new Hashtable< FlatNode, Set<VariableSourceToken> >();
46 // run analysis on each method that is actually called
47 // reachability analysis already computed this so reuse
48 Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
49 while( methItr.hasNext() ) {
50 Descriptor d = methItr.next();
53 if( d instanceof MethodDescriptor ) {
54 fm = state.getMethodFlat( (MethodDescriptor) d);
56 assert d instanceof TaskDescriptor;
57 fm = state.getMethodFlat( (TaskDescriptor) d);
60 // find every SESE from methods that may be called
61 // and organize them into roots and children
62 buildForestForward( fm );
65 Iterator<FlatSESEEnterNode> seseItr = seseRoots.iterator();
66 while( seseItr.hasNext() ) {
67 FlatSESEEnterNode fsen = seseItr.next();
69 // do a post-order traversal of the forest so that
70 // a child is analyzed before a parent. Start from
71 // SESE's exit and do a backward data-flow analysis
72 // for the source of variables
73 computeReadAndWriteSetBackward( fsen );
76 double timeEndAnalysis = (double) System.nanoTime();
77 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
78 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
79 System.out.println( treport );
83 private void buildForestForward( FlatMethod fm ) {
85 // start from flat method top, visit every node in
86 // method exactly once, find SESEs and remember
87 // roots and child relationships
88 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
89 flatNodesToVisit.add( fm );
91 Set<FlatNode> visited = new HashSet<FlatNode>();
93 while( !flatNodesToVisit.isEmpty() ) {
94 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
95 FlatNode fn = fnItr.next();
97 System.out.println( " considering "+fn );
99 // only analyze sese exit nodes when all the nodes between
100 // it and its matching enter have been analyzed
101 if( !seseStack.empty() &&
102 fn.equals( seseStack.peek().getFlatExit() ) &&
103 flatNodesToVisit.size() != 1 ) {
104 // not ready for this exit node yet, just grab another
108 flatNodesToVisit.remove( fn );
111 System.out.println( " visiting "+fn );
113 analyzeFlatNode( fn, true, null, null );
115 // initialize for backward computation in next step
116 pointResults.put( fn, new HashSet<VariableSourceToken>() );
118 for( int i = 0; i < fn.numNext(); i++ ) {
119 FlatNode nn = fn.getNext( i );
121 if( !visited.contains( nn ) ) {
122 flatNodesToVisit.add( nn );
129 private void computeReadAndWriteSetBackward( FlatSESEEnterNode fsen ) {
131 // start from an SESE exit, visit nodes in reverse up to
132 // SESE enter in a fixed-point scheme, where children SESEs
133 // should already be analyzed and therefore can be skipped
134 // because child SESE enter node has all necessary info
135 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
136 flatNodesToVisit.add( fsen.getFlatExit() );
138 while( !flatNodesToVisit.isEmpty() ) {
139 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
140 flatNodesToVisit.remove( fn );
142 Set<VariableSourceToken> prev = pointResults.get( fn );
144 // merge sets from control flow joins
145 Set<VariableSourceToken> merge = new HashSet<VariableSourceToken>();
146 for( int i = 0; i < fn.numNext(); i++ ) {
147 FlatNode nn = fn.getNext( i );
148 merge = mergeVSTsets( merge, pointResults.get( nn ) );
151 Set<VariableSourceToken> curr = analyzeFlatNode( fn, false, merge, fsen );
153 // if a new result, schedule backward nodes for analysis
154 if( !prev.equals( curr ) ) {
156 System.out.println( " "+fn+":" );
157 System.out.println( " prev ="+prev );
158 System.out.println( " merge="+merge );
159 System.out.println( " curr ="+curr );
160 System.out.println( "" );
162 pointResults.put( fn, curr );
164 // don't flow backwards past SESE enter
165 if( !fn.equals( fsen ) ) {
166 for( int i = 0; i < fn.numPrev(); i++ ) {
167 FlatNode nn = fn.getPrev( i );
168 flatNodesToVisit.add( nn );
174 if( state.MLPDEBUG ) {
175 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
176 Iterator<VariableSourceToken> tItr = pointResults.get( fsen ).iterator();
177 while( tItr.hasNext() ) {
178 System.out.println( " "+tItr.next() );
184 private Set<VariableSourceToken> analyzeFlatNode( FlatNode fn,
186 Set<VariableSourceToken> vstSet,
187 FlatSESEEnterNode currentSESE ) {
189 // use node type to decide what alterations to make
190 // to the ownership graph
191 switch( fn.kind() ) {
193 case FKind.FlatSESEEnterNode: {
194 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
197 if( seseStack.empty() ) {
198 seseRoots.add( fsen );
200 seseStack.peek().addChild( fsen );
202 seseStack.push( fsen );
203 System.out.println( " pushed "+fsen );
207 case FKind.FlatSESEExitNode: {
208 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
211 assert !seseStack.empty();
212 FlatSESEEnterNode fsen = seseStack.pop();
213 System.out.println( " popped "+fsen );
216 //FlatSESEEnterNode fsen = fsexn.getFlatEnter();
217 //assert fsen == seseStack.pop();
218 //seseStack.peek().addInVarSet ( fsen.getInVarSet() );
219 //seseStack.peek().addOutVarSet( fsen.getOutVarSet() );
223 case FKind.FlatMethod: {
224 FlatMethod fm = (FlatMethod) fn;
228 case FKind.FlatOpNode:
229 case FKind.FlatCastNode:
230 case FKind.FlatFieldNode:
231 case FKind.FlatSetFieldNode:
232 case FKind.FlatElementNode:
233 case FKind.FlatSetElementNode: {
235 // handle effects of statement in reverse, writes then reads
236 TempDescriptor [] writeTemps = fn.writesTemps();
237 for( int i = 0; i < writeTemps.length; ++i ) {
238 vstSet = killTemp( vstSet, writeTemps[i] );
241 TempDescriptor [] readTemps = fn.readsTemps();
242 for( int i = 0; i < readTemps.length; ++i ) {
243 Set<VariableSourceToken> vstNew = new HashSet<VariableSourceToken>();
244 vstNew.add( new VariableSourceToken( currentSESE,
246 new Integer( 0 ) ) );
247 vstSet = mergeVSTsets( vstSet, vstNew );
253 case FKind.FlatNew: {
254 FlatNew fnn = (FlatNew) fn;
256 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
257 //AllocationSite as = getAllocationSiteFromFlatNewPRIVATE( fnn );
263 case FKind.FlatCall: {
264 FlatCall fc = (FlatCall) fn;
265 MethodDescriptor md = fc.getMethod();
266 FlatMethod flatm = state.getMethodFlat( md );
269 if( md.isStatic() ) {
272 // if the method descriptor is virtual, then there could be a
273 // set of possible methods that will actually be invoked, so
274 // find all of them and merge all of their results together
275 TypeDescriptor typeDesc = fc.getThis().getType();
276 Set possibleCallees = callGraph.getMethods( md, typeDesc );
278 Iterator i = possibleCallees.iterator();
279 while( i.hasNext() ) {
280 MethodDescriptor possibleMd = (MethodDescriptor) i.next();
281 FlatMethod pflatm = state.getMethodFlat( possibleMd );
289 case FKind.FlatReturnNode: {
290 FlatReturnNode frn = (FlatReturnNode) fn;
291 if( buildForest && !seseStack.empty() ) {
292 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
303 private Set<VariableSourceToken> killTemp( Set<VariableSourceToken> s,
305 Set<VariableSourceToken> out = new HashSet<VariableSourceToken>();
307 Iterator<VariableSourceToken> vstitr = s.iterator();
308 while( vstitr.hasNext() ) {
309 VariableSourceToken vst = vstitr.next();
311 if( !vst.getVar().equals( t ) ) {
320 private Set<VariableSourceToken> mergeVSTsets( Set<VariableSourceToken> s1,
321 Set<VariableSourceToken> s2 ) {
323 Set<VariableSourceToken> out = new HashSet<VariableSourceToken>();
325 Iterator<VariableSourceToken> vst1itr = s1.iterator();
326 while( vst1itr.hasNext() ) {
327 VariableSourceToken vst1 = vst1itr.next();
331 Iterator<VariableSourceToken> vst2itr = s2.iterator();
332 while( vst2itr.hasNext() ) {
333 VariableSourceToken vst2 = vst2itr.next();
335 if( vst1.getSESE().equals( vst2.getSESE() ) &&
336 vst1.getVar() .equals( vst2.getVar() ) ) {
337 changeAge = vst1.getAge();
338 int a = vst2.getAge();
339 if( a < changeAge ) {
346 if( changeAge < 0 ) {
349 out.add( new VariableSourceToken( vst1.getSESE(),
351 new Integer( changeAge ) ) );
356 Iterator<VariableSourceToken> vst2itr = s2.iterator();
357 while( vst2itr.hasNext() ) {
358 VariableSourceToken vst2 = vst2itr.next();
360 boolean matchSESEandVar = false;
362 vst1itr = s1.iterator();
363 while( vst1itr.hasNext() ) {
364 VariableSourceToken vst1 = vst1itr.next();
366 if( vst1.getSESE().equals( vst2.getSESE() ) &&
367 vst1.getVar() .equals( vst2.getVar() ) ) {
368 matchSESEandVar = true;
373 if( !matchSESEandVar ) {