1 package Analysis.Disjoint;
11 public class DefiniteReachState {
15 // Maps two variables to an edge (x, y, e) to an unused value when the
16 // object of x is already reachable from the object of y, and the
17 // set of edges conservatively gives the path.
18 // NOTE: Use EdgeKey instead of edges because this analysis's
19 // scope is beyond the scope of a single reach graph.
20 private static MultiViewMapBuilder<Object> RBuilder;
21 private static BitSet viewRfull;
22 private static BitSet viewR0;
23 private static BitSet viewR1;
24 private static BitSet viewR2;
25 private static BitSet viewR01;
26 private MultiViewMap<Object> R;
30 // Tracks whether the analysis must know the definite reachability
31 // information of a given variable.
32 private enum DefReachKnown {
36 private Map<TempDescriptor, DefReachKnown> Rs;
39 // Fu (field upstream)
41 // Maps a variable that points to object o0 to the
42 // set of variables that point to objects o1...oN
43 // that have a reference to o0.
44 //private static MultiViewMapBuilder<Object> FuBuilder;
45 //private static BitSet viewFu0;
46 //private static BitSet viewFu1;
47 //private MultiViewMap<Object> Fu;
50 // Fd (field downstream)
52 // Entries <x, f, y> mean x.f points directly at what
54 public class FdEntry {
58 public FdEntry( TempDescriptor y,
66 private static MultiViewMapBuilder<Object> FdBuilder;
67 private static BitSet viewFd0;
68 private static BitSet viewFd2;
69 private MultiViewMap<Object> Fd;
75 // call before instantiating this class
76 static public void initBuilders() {
78 new MultiViewMapBuilder<Object>( new Class[] {
83 viewRfull = RBuilder.getFullView();
84 viewR0 = RBuilder.addPartialView( 0 );
85 viewR1 = RBuilder.addPartialView( 1 );
86 viewR2 = RBuilder.addPartialView( 2 );
87 viewR01 = RBuilder.addPartialView( 0, 1 );
88 RBuilder.setCheckTypes( true );
89 RBuilder.setCheckConsistency( true );
92 // new MultiViewMapBuilder<Object>( new Class[] {
93 // TempDescriptor.class,
94 // DefReachFuVal.class},
96 //viewFu0 = FuBuilder.addPartialView( 0 );
97 //viewFu1 = FuBuilder.addPartialView( 1 );
98 //FuBuilder.setCheckTypes( true );
99 //FuBuilder.setCheckConsistency( true );
102 new MultiViewMapBuilder<Object>( new Class[] {
103 TempDescriptor.class,
104 FieldDescriptor.class,
105 TempDescriptor.class},
107 viewFd0 = FdBuilder.addPartialView( 0 );
108 viewFd2 = FdBuilder.addPartialView( 2 );
109 FdBuilder.setCheckTypes( true );
110 FdBuilder.setCheckConsistency( true );
115 public DefiniteReachState( DefiniteReachState toCopy ) {
116 this.R = toCopy.R.clone( RBuilder );
117 this.Rs = new HashMap<TempDescriptor, DefReachKnown>( toCopy.Rs );
118 this.Fd = toCopy.Fd.clone( FdBuilder );
122 public DefiniteReachState() {
123 R = RBuilder.build();
124 Rs = new HashMap<TempDescriptor, DefReachKnown>();
125 //Fu = FuBuilder.build();
126 Fd = FdBuilder.build();
131 public boolean isAlreadyReachable( TempDescriptor a,
133 return !R.get( viewR01, MultiKey.factory( a, b ) ).isEmpty();
137 public Set<FdEntry> edgesToElidePropagation( TempDescriptor x,
139 // return the set of edges that definite reach analysis tells
140 // us we can elide propagating reach info across during the
143 Set<FdEntry> out = new HashSet<FdEntry>();
145 // we have to know something about y
146 DefReachKnown known = Rs.get( y );
147 if( known == null || known == DefReachKnown.UNKNOWN ) {
151 // find all 'y points at' entries in Fd
152 MultiKey keyY = MultiKey.factory( y );
153 Map<MultiKey, Object> mapY0 = Fd.get( viewFd0, keyY );
155 for( MultiKey fullKeyY : mapY0.keySet() ) {
156 // if y.f0 points at z, and z is already reachable from x,
157 // include the edge y.f0->z
158 FieldDescriptor f0 = (FieldDescriptor) fullKeyY.get( 1 );
159 TempDescriptor z = (TempDescriptor) fullKeyY.get( 2 );
161 if( isAlreadyReachable( z, x ) ) {
162 out.add( new FdEntry( y, f0, z ) );
172 public void methodEntry( Set<TempDescriptor> parameters ) {
173 methodEntryR ( parameters );
174 methodEntryRs( parameters );
175 methodEntryFd( parameters );
178 public void copy( TempDescriptor x,
184 // Fu' := (Fu - <x, *> - <*, x>) U
185 // {<x,v> | <y,v> in Fu} U
186 // {<v,x> | <v,y> in Fu} U
187 // {<z, unknown> | <z,<x>> in Fu}
188 //Fu.remove( viewFu0, MultiKey.factory( x ) );
189 //Fu.remove( viewFu1, MultiKey.factory( x ) );
190 //for( MultiKey key : Fu.get( viewFu0, MultiKey.factory( y ) ).keySet() ) {
191 // DefReachFuVal val = (DefReachFuVal) key.get( 1 );
192 // Fu.put( MultiKey.factory( x, val ), dummy );
194 //for( MultiKey key : Fu.get( viewFu1, MultiKey.factory( y ) ).keySet() ) {
195 // TempDescriptor v = (TempDescriptor) key.get( 0 );
196 // Fu.put( MultiKey.factory( v, DefReachFuVal.factory( x ) ), dummy );
198 //for( MultiKey key :
200 // MultiKey.factory( DefReachFuVal.factory( DefReachFuVal.Val.UNKNOWN ) )
203 // TempDescriptor z = (TempDescriptor) key.get( 0 );
204 // Fu.put( MultiKey.factory( z, DefReachFuVal.factory( x ) ), dummy );
208 public void load( TempDescriptor x,
211 Set<EdgeKey> edgeKeysForLoad ) {
213 loadR ( x, y, f, edgeKeysForLoad );
214 loadRs( x, y, f, edgeKeysForLoad );
215 loadFd( x, y, f, edgeKeysForLoad );
218 public void store( TempDescriptor x,
221 Set<EdgeKey> edgeKeysRemoved,
222 Set<EdgeKey> edgeKeysAdded ) {
224 storeR ( x, f, y, edgeKeysRemoved, edgeKeysAdded );
225 storeRs( x, f, y, edgeKeysRemoved, edgeKeysAdded );
226 storeFd( x, f, y, edgeKeysRemoved, edgeKeysAdded );
229 public void newObject( TempDescriptor x ) {
235 public void methodCall( TempDescriptor retVal ) {
236 methodCallR ( retVal );
237 methodCallRs( retVal );
238 methodCallFd( retVal );
241 public void merge( DefiniteReachState that ) {
252 public void methodEntryR( Set<TempDescriptor> parameters ) {
256 public void copyR( TempDescriptor x,
258 // consider that x and y can be the same, so do the
259 // parts of the update in the right order:
261 // first get all info for update
262 MultiKey keyY = MultiKey.factory( y );
263 Map<MultiKey, Object> mapY0 = R.get( viewR0, keyY );
264 Map<MultiKey, Object> mapY1 = R.get( viewR1, keyY );
266 // then remove anything
267 MultiKey keyX = MultiKey.factory( x );
268 R.remove( viewR0, keyX );
269 R.remove( viewR1, keyX );
271 // then insert new stuff
272 for( MultiKey fullKeyY : mapY0.keySet() ) {
273 MultiKey fullKeyX = MultiKey.factory( x,
276 R.put( fullKeyX, MultiViewMap.dummyValue );
278 for( MultiKey fullKeyY : mapY1.keySet() ) {
279 MultiKey fullKeyX = MultiKey.factory( fullKeyY.get( 0 ),
282 R.put( fullKeyX, MultiViewMap.dummyValue );
286 public void loadR( TempDescriptor x,
289 Set<EdgeKey> edgeKeysForLoad ) {
290 // consider that x and y can be the same, so do the
291 // parts of the update in the right order:
293 // first get all info for update
294 MultiKey keyY = MultiKey.factory( y );
295 Map<MultiKey, Object> mapY0 = R.get( viewR0, keyY );
297 // then remove anything
298 MultiKey keyX = MultiKey.factory( x );
299 R.remove( viewR0, keyX );
300 R.remove( viewR1, keyX );
302 // then insert new stuff
303 for( EdgeKey e : edgeKeysForLoad ) {
304 R.put( MultiKey.factory( x, y, e ), MultiViewMap.dummyValue );
306 for( MultiKey fullKeyY : mapY0.keySet() ) {
307 R.put( MultiKey.factory( x,
310 MultiViewMap.dummyValue );
312 R.put( MultiKey.factory( x,
315 MultiViewMap.dummyValue );
320 public void storeR( TempDescriptor x,
323 Set<EdgeKey> edgeKeysRemoved,
324 Set<EdgeKey> edgeKeysAdded ) {
326 for( EdgeKey edgeKeyWZ : edgeKeysRemoved ) {
327 R.remove( viewR2, MultiKey.factory( edgeKeyWZ ) );
330 for( EdgeKey edgeKeyXY : edgeKeysAdded ) {
331 R.put( MultiKey.factory( y, x, edgeKeyXY ), MultiViewMap.dummyValue );
335 public void newObjectR( TempDescriptor x ) {
336 MultiKey keyX = MultiKey.factory( x );
337 R.remove( viewR0, keyX );
338 R.remove( viewR1, keyX );
341 public void methodCallR( TempDescriptor retVal ) {
342 MultiKey keyRetVal = MultiKey.factory( retVal );
343 R.remove( viewR0, keyRetVal );
344 R.remove( viewR1, keyRetVal );
347 public void mergeR( DefiniteReachState that ) {
348 for( MultiKey key : this.R.get().keySet() ) {
349 if( that.R.get( viewRfull, key ).isEmpty() ) {
350 this.R.remove( viewRfull, key );
362 public void methodEntryRs( Set<TempDescriptor> parameters ) {
364 for( TempDescriptor p : parameters ) {
365 Rs.put( p, DefReachKnown.UNKNOWN );
369 public void copyRs( TempDescriptor x,
371 DefReachKnown valRs = Rs.get( y );
372 assert( valRs != null );
376 public void loadRs( TempDescriptor x,
379 Set<EdgeKey> edgeKeysForLoad ) {
380 Rs.put( x, DefReachKnown.UNKNOWN );
383 public void storeRs( TempDescriptor x,
386 Set<EdgeKey> edgeKeysRemoved,
387 Set<EdgeKey> edgeKeysAdded ) {
390 public void newObjectRs( TempDescriptor x ) {
391 Rs.put( x, DefReachKnown.KNOWN );
394 public void methodCallRs( TempDescriptor retVal ) {
395 Rs.put( retVal, DefReachKnown.UNKNOWN );
398 ///////////////////////////////////////////////////////////
402 // It definitely tests the current R as well as Rs
404 // but also be careful what null means, is it actually
405 // equivalent to UNKOWN? I'd rather put nothing, meaning
406 // we have to do an analysis pass over all the incoming edges
407 // before there is a sensical answer. I think...
408 private void mergeRs( DefiniteReachState that ) {
409 Set<TempDescriptor> allVars = new HashSet<TempDescriptor>();
410 allVars.addAll( this.Rs.keySet() );
411 allVars.addAll( that.Rs.keySet() );
412 for( TempDescriptor x : allVars ) {
413 DefReachKnown vThis = this.Rs.get( x );
414 DefReachKnown vThat = that.Rs.get( x );
415 if( vThis != null && vThis.equals( DefReachKnown.KNOWN ) &&
416 vThat != null && vThat.equals( DefReachKnown.KNOWN ) ) {
417 this.Rs.put( x, DefReachKnown.KNOWN );
419 this.Rs.put( x, DefReachKnown.UNKNOWN );
430 public void methodEntryFd( Set<TempDescriptor> parameters ) {
434 public void copyFd( TempDescriptor x,
436 // consider that x and y can be the same, so do the
437 // parts of the update in the right order:
439 // first get all info for update
440 MultiKey keyY = MultiKey.factory( y );
441 Map<MultiKey, Object> mapY0 = Fd.get( viewFd0, keyY );
442 Map<MultiKey, Object> mapY2 = Fd.get( viewFd2, keyY );
444 // then remove anything
445 MultiKey keyX = MultiKey.factory( x );
446 Fd.remove( viewFd0, keyX );
447 Fd.remove( viewFd2, keyX );
449 // then insert new stuff
450 for( MultiKey fullKeyY : mapY0.keySet() ) {
451 MultiKey fullKeyX = MultiKey.factory( x,
454 Fd.put( fullKeyX, MultiViewMap.dummyValue );
456 for( MultiKey fullKeyY : mapY2.keySet() ) {
457 MultiKey fullKeyX = MultiKey.factory( fullKeyY.get( 0 ),
460 Fd.put( fullKeyX, MultiViewMap.dummyValue );
464 public void loadFd( TempDescriptor x,
467 Set<EdgeKey> edgeKeysForLoad ) {
469 MultiKey keyX = MultiKey.factory( x );
470 Fd.remove( viewFd0, keyX );
471 Fd.remove( viewFd2, keyX );
474 public void storeFd( TempDescriptor x,
477 Set<EdgeKey> edgeKeysFdemoved,
478 Set<EdgeKey> edgeKeysAdded ) {
479 Fd.put( MultiKey.factory( x, f, y ),
480 MultiViewMap.dummyValue );
483 public void newObjectFd( TempDescriptor x ) {
484 MultiKey keyX = MultiKey.factory( x );
485 Fd.remove( viewFd0, keyX );
486 Fd.remove( viewFd2, keyX );
489 public void methodCallFd( TempDescriptor retVal ) {
490 MultiKey keyRetVal = MultiKey.factory( retVal );
491 Fd.remove( viewFd0, keyRetVal );
492 Fd.remove( viewFd2, keyRetVal );
495 public void mergeFd( DefiniteReachState that ) {
496 this.Fd.merge( that.Fd );
510 public boolean equals( Object o ) {
517 if( !(o instanceof DefiniteReachState) ) {
520 DefiniteReachState that = (DefiniteReachState) o;
527 public int hashCode() {
533 public void writeState( String outputName ) {
535 BufferedWriter bw = new BufferedWriter( new FileWriter( "defReach-"+outputName+".txt" ) );
536 bw.write( this.toString() );
538 } catch( IOException e ) {
539 System.out.println( "ERROR writing definite reachability state:\n "+e );
544 public String toString() {
545 StringBuilder s = new StringBuilder();
547 s.append( "R = {\n" );
548 s.append( R.toString( 2 ) );
551 s.append( "Rs = {\n" );
552 for( TempDescriptor x : Rs.keySet() ) {
553 s.append( " "+x+"->"+Rs.get( x )+"\n" );
557 s.append( "Fd = {\n" );
558 s.append( Fd.toString( 2 ) );