1 //////////////////////////////////////////////////
3 // The object of this analysis is to maintain a
4 // relation for program points:
5 // array variable -> variables referenced by the array's elements
7 // This analysis is useful in reachability analysis
8 // because if a variable is read from an array,
9 // then inserted back into the array, we can be
10 // sure that no new reachability paths are created.
12 //////////////////////////////////////////////////
17 import IR.Flat.FlatMethod;
18 import IR.Flat.FlatNode;
19 import IR.Flat.FlatCall;
22 import IR.ClassDescriptor;
23 import IR.MethodDescriptor;
24 import IR.TaskDescriptor;
25 import IR.TypeDescriptor;
26 import Util.UtilAlgorithms;
31 public class ArrayReferencees {
33 ////////////////////////////////
35 ////////////////////////////////
36 public ArrayReferencees( State state ) {
40 public boolean mayCreateNewReachabilityPaths( FlatSetElementNode fsen ) {
43 ////////////////////////////////
44 // end public interface
45 ////////////////////////////////
49 protected State state;
51 // maintain the relation at every program point
52 protected Hashtable<FlatNode, InArrayRelation> fn2rel;
55 protected ArrayReferencees() {}
57 protected void init( State state ) {
59 fn2rel = new Hashtable<FlatNode, InArrayRelation>();
63 protected void buildRelation() {
64 // just analyze every method of every class that the
65 // compiler has code for, fix if this is too costly
66 Iterator classItr = state.getClassSymbolTable().getDescriptorsIterator();
67 while( classItr.hasNext() ) {
68 ClassDescriptor cd = (ClassDescriptor)classItr.next();
70 Iterator methodItr = cd.getMethods();
71 while( methodItr.hasNext() ) {
72 MethodDescriptor md = (MethodDescriptor)methodItr.next();
74 FlatMethod fm = state.getMethodFlat( md );
80 protected void analyzeMethod( FlatMethod fm ) {
81 Set<FlatNode> toVisit = new HashSet<FlatNode>();
84 while( !toVisit.isEmpty() ) {
85 FlatNode fn = toVisit.iterator().next();
88 // find the result flowing into this node
89 InArrayRelation rel = new InArrayRelation();
91 // the join operation is intersection, so
92 // merge with 1st predecessor (if any) and
93 // then do intersect with all others
94 if( fn.numPrev() > 0 ) {
95 rel.merge( fn2rel.get( fn.getPrev( 0 ) ) );
97 for( int i = 1; i < fn.numPrev(); ++i ) {
98 rel.intersect( fn2rel.get( fn.getPrev( i ) ) );
102 analyzeFlatNode( rel, fn );
104 // enqueue child nodes if new results were found
105 InArrayRelation relPrev = fn2rel.get( fn );
106 if( !rel.equals( relPrev ) ) {
107 fn2rel.put( fn, rel );
108 for( int i = 0; i < fn.numNext(); i++ ) {
109 FlatNode nn = fn.getNext( i );
116 protected void analyzeFlatNode( FlatNode fn,
117 InArrayRelation rel ) {
122 // use node type to transform relation
123 switch( fn.kind() ) {
125 case FKind.FlatElementNode:
127 FlatElementNode fen = (FlatElementNode) fn;
131 rel.put_array2refee( rhs, lhs );
134 case FKind.FlatSetElementNode:
136 FlatSetElementNode fsen = (FlatSetElementNode) fn;
139 rel.put_array2refee( lhs, rhs );
143 // the default action is to remove every temp
144 // written by this node from the relation
145 TempDescriptor[] writeTemps = fn.writesTemps();
146 for( int i = 0; i < writeTemps.length; ++i ) {
147 TempDescriptor td = writeTemps[i];
158 protected class InArrayRelation {
160 // The relation is possibly dense, in that any variable might
161 // be referenced by many arrays, and an array may reference
162 // many variables. So maintain the relation as two hashtables
163 // that are redundant but allow efficient operations
164 protected Hashtable< TempDescriptor, Set<TempDescriptor> > array2refees;
165 protected Hashtable< TempDescriptor, Set<TempDescriptor> > refee2arrays;
167 public InArrayRelation() {
168 array2refees = new Hashtable< TempDescriptor, Set<TempDescriptor> >();
169 refee2arrays = new Hashtable< TempDescriptor, Set<TempDescriptor> >();
172 public void put_array2refee( TempDescriptor array, TempDescriptor refee ) {
173 // update one direction
174 Set<TempDescriptor> refees = array2refees.get( array );
175 if( refees == null ) {
176 refees = new HashSet<TempDescriptor>();
179 array2refees.put( array, refees );
181 // and then the other
182 Set<TempDescriptor> arrays = refee2arrays.get( refee );
183 if( arrayss == null ) {
184 arrays = new HashSet<TempDescriptor>();
187 refee2arrays.put( refee, arrays );
192 public void remove( TempDescriptor td ) {
198 public void merge( InArrayRelation r ) {
202 UtilAlgorithms.mergeHashtablesWithHashSetValues( array2refees, r.array2refees );
203 UtilAlgorithms.mergeHashtablesWithHashSetValues( refee2arrays, r.refee2arrays );
207 public void intersect( InArrayRelation r ) {
209 array2refees.clear();
210 refee2arrays.clear();
213 UtilAlgorithms.intersectHashtablesWithSetValues( array2refees, r.array2refees );
214 UtilAlgorithms.intersectHashtablesWithSetValues( refee2arrays, r.refee2arrays );
218 public void assertConsistent() {
219 assert allEntriesInAReversedInB( array2refees, refee2arrays );
220 assert allEntriesInAReversedInB( refee2arrays, array2refees );
223 protected boolean allEntriesInAReversedInB(
224 Hashtable< TempDescriptor, Set<TempDescriptor> > a,
225 Hashtable< TempDescriptor, Set<TempDescriptor> > b ) {
227 Iterator mapItr = a.entrySet().iterator();
228 while( mapItr.hasNext() ) {
229 Map.Entry me = (Map.Entry) mapItr.next();
230 TempDescriptor keyA = (TempDescriptor) me.getKey();
231 Set<TempDescriptor> valsA = (Set<TempDescriptor>) me.getValue();
233 Iterator<TempDescriptor> valItr = valsA.iterator();
234 while( valItr.hasNext() ) {
235 TempDescriptor valA = valItr.next();
237 Set<TempDescriptor> valsB = b.get( valA );
239 if( valsB == null ) {
243 if( !valsB.contains( keyA ) ) {
252 public boolean equals( Object o ) {
256 if( !(o instanceof InArrayRelation) ) {
259 InArrayRelation rel = (InArrayRelation) o;
261 array2refees.equals( rel.array2refees ) &&
262 refee2arrays.equals( rel.refee2arrays );
265 public int hashCode() {
267 array2refees.hashCode() +
268 refee2arrays.hashCode();