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;
31 // Tracks whether the analysis must know the definite reachability
32 // information of a given variable.
33 private enum DefReachKnown {
37 private Map<TempDescriptor, DefReachKnown> Rs;
40 // Fu (field upstream)
42 // Maps a variable that points to object o0 to the
43 // set of variables that point to objects o1...oN
44 // that have a reference to o0.
45 private class FuSource {
46 DefReachKnown isKnown;
47 TempDescriptor knownSrc;
49 this.isKnown = DefReachKnown.UNKNOWN;
52 public FuSource( TempDescriptor src ) {
53 assert( src != null );
54 this.isKnown = DefReachKnown.KNOWN;
57 public boolean equals( Object o ) {
58 if( !(o instanceof FuSource) ) {
61 FuSource fus = (FuSource)o;
63 this.isKnown == fus.isKnown &&
64 this.knownSrc == fus.knownSrc;
66 public int hashCode() {
68 if( isKnown == DefReachKnown.KNOWN ) {
71 if( knownSrc != null ) {
72 hash ^= knownSrc.hashCode();
76 public String toString() {
77 if( isKnown == DefReachKnown.UNKNOWN ) {
80 return knownSrc.toString();
83 private static MultiViewMapBuilder<Object> FuBuilder;
84 private static BitSet viewFufull;
85 private static BitSet viewFu0;
86 private static BitSet viewFu1;
87 private MultiViewMap<Object> Fu;
90 // Fd (field downstream)
92 // Entries <x, f, y> mean x.f points directly at what
94 public class FdEntry {
98 public FdEntry( TempDescriptor y,
106 private static MultiViewMapBuilder<Object> FdBuilder;
107 private static BitSet viewFd0;
108 private static BitSet viewFd2;
109 private MultiViewMap<Object> Fd;
115 // call before instantiating this class
116 static public void initBuilders() {
119 new MultiViewMapBuilder<Object>( new Class[] {
120 TempDescriptor.class,
121 TempDescriptor.class,
124 viewRfull = RBuilder.getFullView();
125 viewR0 = RBuilder.addPartialView( 0 );
126 viewR1 = RBuilder.addPartialView( 1 );
127 viewR2 = RBuilder.addPartialView( 2 );
128 viewR01 = RBuilder.addPartialView( 0, 1 );
129 RBuilder.setCheckTypes( true );
130 RBuilder.setCheckConsistency( true );
134 new MultiViewMapBuilder<Object>( new Class[] {
135 TempDescriptor.class,
138 viewFufull = FuBuilder.getFullView();
139 viewFu0 = FuBuilder.addPartialView( 0 );
140 viewFu1 = FuBuilder.addPartialView( 1 );
141 FuBuilder.setCheckTypes( true );
142 FuBuilder.setCheckConsistency( true );
146 new MultiViewMapBuilder<Object>( new Class[] {
147 TempDescriptor.class,
148 FieldDescriptor.class,
149 TempDescriptor.class},
151 viewFd0 = FdBuilder.addPartialView( 0 );
152 viewFd2 = FdBuilder.addPartialView( 2 );
153 FdBuilder.setCheckTypes( true );
154 FdBuilder.setCheckConsistency( true );
159 public DefiniteReachState( DefiniteReachState toCopy ) {
160 this.R = toCopy.R.clone( RBuilder );
161 this.Rs = new HashMap<TempDescriptor, DefReachKnown>( toCopy.Rs );
162 this.Fu = toCopy.Fu.clone( FuBuilder );
163 this.Fd = toCopy.Fd.clone( FdBuilder );
167 public DefiniteReachState() {
168 R = RBuilder.build();
169 Rs = new HashMap<TempDescriptor, DefReachKnown>();
170 Fu = FuBuilder.build();
171 Fd = FdBuilder.build();
177 public boolean isAlreadyReachable( TempDescriptor a,
180 boolean case1 = !R.get( viewR01, MultiKey.factory( a, b ) ).isEmpty();
182 boolean case3 = false;
183 if( Rs.get( b ) != null &&
184 Rs.get( b ) == DefReachKnown.KNOWN &&
185 Fu.get( viewFufull, MultiKey.factory( b, new FuSource() ) ).isEmpty()
187 boolean allEntriesOk = true;
188 for( MultiKey fullKeyB : Fu.get( viewFu0,
189 MultiKey.factory( b ) ).keySet()
193 ((FuSource)fullKeyB.get( 1 )).knownSrc
196 allEntriesOk = false;
200 case3 = allEntriesOk;
203 return case1 || case3;
208 public Set<FdEntry> edgesToElidePropagation( TempDescriptor x,
210 // return the set of edges that definite reach analysis tells
211 // us we can elide propagating reach info across during the
214 Set<FdEntry> out = new HashSet<FdEntry>();
216 // we have to know something about y
217 DefReachKnown known = Rs.get( y );
218 if( known == null || known == DefReachKnown.UNKNOWN ) {
222 // find all 'y points at' entries in Fd
223 MultiKey keyY = MultiKey.factory( y );
224 Map<MultiKey, Object> mapY0 = Fd.get( viewFd0, keyY );
226 for( MultiKey fullKeyY : mapY0.keySet() ) {
227 // if y.f0 points at z, and z is already reachable from x,
228 // include the edge y.f0->z
229 FieldDescriptor f0 = (FieldDescriptor) fullKeyY.get( 1 );
230 TempDescriptor z = (TempDescriptor) fullKeyY.get( 2 );
232 if( isAlreadyReachable( z, x ) ) {
233 out.add( new FdEntry( y, f0, z ) );
243 public void methodEntry( Set<TempDescriptor> parameters ) {
244 methodEntryR ( parameters );
245 methodEntryRs( parameters );
246 methodEntryFu( parameters );
247 methodEntryFd( parameters );
250 public void copy( TempDescriptor x,
258 public void load( TempDescriptor x,
261 Set<EdgeKey> edgeKeysForLoad ) {
263 loadR ( x, y, f, edgeKeysForLoad );
264 loadRs( x, y, f, edgeKeysForLoad );
265 loadFu( x, y, f, edgeKeysForLoad );
266 loadFd( x, y, f, edgeKeysForLoad );
269 public void store( TempDescriptor x,
272 Set<EdgeKey> edgeKeysRemoved,
273 Set<EdgeKey> edgeKeysAdded ) {
275 storeR ( x, f, y, edgeKeysRemoved, edgeKeysAdded );
276 storeRs( x, f, y, edgeKeysRemoved, edgeKeysAdded );
277 storeFu( x, f, y, edgeKeysRemoved, edgeKeysAdded );
278 storeFd( x, f, y, edgeKeysRemoved, edgeKeysAdded );
281 public void newObject( TempDescriptor x ) {
288 public void methodCall( TempDescriptor retVal ) {
289 methodCallR ( retVal );
290 methodCallRs( retVal );
291 methodCallFu( retVal );
292 methodCallFd( retVal );
295 public void merge( DefiniteReachState that ) {
307 public void methodEntryR( Set<TempDescriptor> parameters ) {
311 public void copyR( TempDescriptor x,
313 // consider that x and y can be the same, so do the
314 // parts of the update in the right order:
316 // first get all info for update
317 MultiKey keyY = MultiKey.factory( y );
318 Map<MultiKey, Object> mapY0 = R.get( viewR0, keyY );
319 Map<MultiKey, Object> mapY1 = R.get( viewR1, keyY );
321 // then remove anything
322 MultiKey keyX = MultiKey.factory( x );
323 R.remove( viewR0, keyX );
324 R.remove( viewR1, keyX );
326 // then insert new stuff
327 for( MultiKey fullKeyY : mapY0.keySet() ) {
328 MultiKey fullKeyX = MultiKey.factory( x,
331 R.put( fullKeyX, MultiViewMap.dummyValue );
333 for( MultiKey fullKeyY : mapY1.keySet() ) {
334 MultiKey fullKeyX = MultiKey.factory( fullKeyY.get( 0 ),
337 R.put( fullKeyX, MultiViewMap.dummyValue );
341 public void loadR( TempDescriptor x,
344 Set<EdgeKey> edgeKeysForLoad ) {
345 // consider that x and y can be the same, so do the
346 // parts of the update in the right order:
348 // first get all info for update
349 MultiKey keyY = MultiKey.factory( y );
350 Map<MultiKey, Object> mapY0 = R.get( viewR0, keyY );
352 // then remove anything
353 MultiKey keyX = MultiKey.factory( x );
354 R.remove( viewR0, keyX );
355 R.remove( viewR1, keyX );
357 // then insert new stuff
358 for( EdgeKey e : edgeKeysForLoad ) {
359 R.put( MultiKey.factory( x, y, e ), MultiViewMap.dummyValue );
361 for( MultiKey fullKeyY : mapY0.keySet() ) {
362 R.put( MultiKey.factory( x,
365 MultiViewMap.dummyValue );
367 R.put( MultiKey.factory( x,
370 MultiViewMap.dummyValue );
375 public void storeR( TempDescriptor x,
378 Set<EdgeKey> edgeKeysRemoved,
379 Set<EdgeKey> edgeKeysAdded ) {
381 for( EdgeKey edgeKeyWZ : edgeKeysRemoved ) {
382 R.remove( viewR2, MultiKey.factory( edgeKeyWZ ) );
385 for( EdgeKey edgeKeyXY : edgeKeysAdded ) {
386 R.put( MultiKey.factory( y, x, edgeKeyXY ), MultiViewMap.dummyValue );
390 public void newObjectR( TempDescriptor x ) {
391 MultiKey keyX = MultiKey.factory( x );
392 R.remove( viewR0, keyX );
393 R.remove( viewR1, keyX );
396 public void methodCallR( TempDescriptor retVal ) {
397 MultiKey keyRetVal = MultiKey.factory( retVal );
398 R.remove( viewR0, keyRetVal );
399 R.remove( viewR1, keyRetVal );
402 public void mergeR( DefiniteReachState that ) {
403 for( MultiKey key : this.R.get().keySet() ) {
404 if( that.R.get( viewRfull, key ).isEmpty() ) {
405 this.R.remove( viewRfull, key );
417 public void methodEntryRs( Set<TempDescriptor> parameters ) {
419 for( TempDescriptor p : parameters ) {
420 Rs.put( p, DefReachKnown.UNKNOWN );
424 public void copyRs( TempDescriptor x,
426 DefReachKnown valRs = Rs.get( y );
427 if( valRs != null ) {
432 public void loadRs( TempDescriptor x,
435 Set<EdgeKey> edgeKeysForLoad ) {
436 Rs.put( x, DefReachKnown.UNKNOWN );
439 public void storeRs( TempDescriptor x,
442 Set<EdgeKey> edgeKeysRemoved,
443 Set<EdgeKey> edgeKeysAdded ) {
446 public void newObjectRs( TempDescriptor x ) {
447 Rs.put( x, DefReachKnown.KNOWN );
450 public void methodCallRs( TempDescriptor retVal ) {
451 Rs.put( retVal, DefReachKnown.UNKNOWN );
454 private void mergeRs( DefiniteReachState that ) {
455 Set<TempDescriptor> allVars = new HashSet<TempDescriptor>();
456 allVars.addAll( this.Rs.keySet() );
457 allVars.addAll( that.Rs.keySet() );
458 for( TempDescriptor x : allVars ) {
459 DefReachKnown vThis = this.Rs.get( x );
460 DefReachKnown vThat = that.Rs.get( x );
461 if( vThis != null && vThis.equals( DefReachKnown.KNOWN ) &&
462 vThat != null && vThat.equals( DefReachKnown.KNOWN ) ) {
463 this.Rs.put( x, DefReachKnown.KNOWN );
465 this.Rs.put( x, DefReachKnown.UNKNOWN );
477 public void methodEntryFu( Set<TempDescriptor> parameters ) {
481 public void copyFu( TempDescriptor x,
483 // consider that x and y can be the same, so do the
484 // parts of the update in the right order:
486 // first get all info for update
487 MultiKey keyY = MultiKey.factory( y );
488 MultiKey keyYsrc = MultiKey.factory( new FuSource( y ) );
489 Map<MultiKey, Object> mapY0 = Fu.get( viewFu0, keyY );
490 Map<MultiKey, Object> mapY1 = Fu.get( viewFu1, keyYsrc );
492 MultiKey keyXsrc = MultiKey.factory( new FuSource( x ) );
493 Map<MultiKey, Object> mapX1 = Fu.get( viewFu1, keyXsrc );
495 // then remove anything
496 MultiKey keyX = MultiKey.factory( x );
497 Fu.remove( viewFu0, keyX );
498 Fu.remove( viewFu1, keyXsrc );
500 // then insert new stuff
501 for( MultiKey fullKeyY : mapY0.keySet() ) {
502 MultiKey fullKeyX = MultiKey.factory( x,
504 Fu.put( fullKeyX, MultiViewMap.dummyValue );
506 for( MultiKey fullKeyY : mapY1.keySet() ) {
507 MultiKey fullKeyX = MultiKey.factory( fullKeyY.get( 0 ),
509 Fu.put( fullKeyX, MultiViewMap.dummyValue );
511 for( MultiKey fullKeyXsrc : mapX1.keySet() ) {
512 Fu.put( MultiKey.factory( fullKeyXsrc.get( 0 ),
514 MultiViewMap.dummyValue );
518 public void loadFu( TempDescriptor x,
521 Set<EdgeKey> edgeKeysForLoad ) {
523 // first get all info for update
524 MultiKey keyXsrc = MultiKey.factory( new FuSource( x ) );
525 Map<MultiKey, Object> mapX1 = Fu.get( viewFu1, keyXsrc );
527 MultiKey keyX = MultiKey.factory( x );
528 // then remove anything
529 Fu.remove( viewFu0, keyX );
530 Fu.remove( viewFu1, keyXsrc );
532 // then insert new stuff
533 for( MultiKey fullKeyXsrc : mapX1.keySet() ) {
534 Fu.put( MultiKey.factory( fullKeyXsrc.get( 0 ),
536 MultiViewMap.dummyValue );
540 public void storeFu( TempDescriptor x,
543 Set<EdgeKey> edgeKeysRemoved,
544 Set<EdgeKey> edgeKeysAdded ) {
546 Fu.put( MultiKey.factory( y, new FuSource( x ) ),
547 MultiViewMap.dummyValue );
550 public void newObjectFu( TempDescriptor x ) {
551 MultiKey keyXsrc = MultiKey.factory( new FuSource( x ) );
552 Map<MultiKey, Object> mapX1 = Fu.get( viewFu1, keyXsrc );
554 MultiKey keyX = MultiKey.factory( x );
555 Fu.remove( viewFu0, keyX );
556 Fu.remove( viewFu1, keyXsrc );
558 for( MultiKey fullKeyXsrc : mapX1.keySet() ) {
559 Fu.put( MultiKey.factory( fullKeyXsrc.get( 0 ),
561 MultiViewMap.dummyValue );
565 public void methodCallFu( TempDescriptor retVal ) {
566 MultiKey keyRetValsrc = MultiKey.factory( new FuSource( retVal ) );
567 Map<MultiKey, Object> mapRetVal1 = Fu.get( viewFu1, keyRetValsrc );
569 MultiKey keyRetVal = MultiKey.factory( retVal );
570 Fu.remove( viewFu0, keyRetVal );
571 Fu.remove( viewFu1, keyRetValsrc );
573 for( MultiKey fullKeyRetValsrc : mapRetVal1.keySet() ) {
574 Fu.put( MultiKey.factory( fullKeyRetValsrc.get( 0 ),
576 MultiViewMap.dummyValue );
580 public void mergeFu( DefiniteReachState that ) {
581 this.Fu.merge( that.Fu );
589 public void methodEntryFd( Set<TempDescriptor> parameters ) {
593 public void copyFd( TempDescriptor x,
595 // consider that x and y can be the same, so do the
596 // parts of the update in the right order:
598 // first get all info for update
599 MultiKey keyY = MultiKey.factory( y );
600 Map<MultiKey, Object> mapY0 = Fd.get( viewFd0, keyY );
601 Map<MultiKey, Object> mapY2 = Fd.get( viewFd2, keyY );
603 // then remove anything
604 MultiKey keyX = MultiKey.factory( x );
605 Fd.remove( viewFd0, keyX );
606 Fd.remove( viewFd2, keyX );
608 // then insert new stuff
609 for( MultiKey fullKeyY : mapY0.keySet() ) {
610 MultiKey fullKeyX = MultiKey.factory( x,
613 Fd.put( fullKeyX, MultiViewMap.dummyValue );
615 for( MultiKey fullKeyY : mapY2.keySet() ) {
616 MultiKey fullKeyX = MultiKey.factory( fullKeyY.get( 0 ),
619 Fd.put( fullKeyX, MultiViewMap.dummyValue );
623 public void loadFd( TempDescriptor x,
626 Set<EdgeKey> edgeKeysForLoad ) {
628 MultiKey keyX = MultiKey.factory( x );
629 Fd.remove( viewFd0, keyX );
630 Fd.remove( viewFd2, keyX );
633 public void storeFd( TempDescriptor x,
636 Set<EdgeKey> edgeKeysFdemoved,
637 Set<EdgeKey> edgeKeysAdded ) {
638 Fd.put( MultiKey.factory( x, f, y ),
639 MultiViewMap.dummyValue );
642 public void newObjectFd( TempDescriptor x ) {
643 MultiKey keyX = MultiKey.factory( x );
644 Fd.remove( viewFd0, keyX );
645 Fd.remove( viewFd2, keyX );
648 public void methodCallFd( TempDescriptor retVal ) {
649 MultiKey keyRetVal = MultiKey.factory( retVal );
650 Fd.remove( viewFd0, keyRetVal );
651 Fd.remove( viewFd2, keyRetVal );
654 public void mergeFd( DefiniteReachState that ) {
655 this.Fd.merge( that.Fd );
669 public boolean equals( Object o ) {
676 if( !(o instanceof DefiniteReachState) ) {
679 DefiniteReachState that = (DefiniteReachState) o;
686 public int hashCode() {
692 public void writeState( String outputName ) {
694 BufferedWriter bw = new BufferedWriter( new FileWriter( "defReach-"+outputName+".txt" ) );
695 bw.write( this.toString() );
697 } catch( IOException e ) {
698 System.out.println( "ERROR writing definite reachability state:\n "+e );
703 public String toString() {
704 StringBuilder s = new StringBuilder();
706 s.append( "R = {\n" );
707 s.append( R.toString( 2 ) );
710 s.append( "Rs = {\n" );
711 for( TempDescriptor x : Rs.keySet() ) {
712 s.append( " "+x+"->"+Rs.get( x )+"\n" );
716 s.append( "Fu = {\n" );
717 s.append( Fu.toString( 2 ) );
720 s.append( "Fd = {\n" );
721 s.append( Fd.toString( 2 ) );