1 cananian 1.1.2.1 // MemoryOptimization.java, created Sun Jun 17 19:10:49 2001 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Analysis.Quads;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.Analysis.BasicBlock;
  7 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy;
  8 cananian 1.1.2.1 import harpoon.ClassFile.HCode;
  9 cananian 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps;
 10 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory;
 11 cananian 1.1.2.1 import harpoon.ClassFile.HField;
 12 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
 13 cananian 1.1.2.1 import harpoon.IR.Quads.AGET;
 14 cananian 1.1.2.1 import harpoon.IR.Quads.ASET;
 15 cananian 1.1.2.1 import harpoon.IR.Quads.CALL;
 16 cananian 1.1.2.3 import harpoon.IR.Quads.Code;
 17 cananian 1.1.2.3 import harpoon.IR.Quads.Edge;
 18 cananian 1.1.2.1 import harpoon.IR.Quads.GET;
 19 cananian 1.1.2.1 import harpoon.IR.Quads.HEADER;
 20 cananian 1.1.2.1 import harpoon.IR.Quads.MONITORENTER;
 21 cananian 1.1.2.1 import harpoon.IR.Quads.MONITOREXIT;
 22 cananian 1.1.2.1 import harpoon.IR.Quads.MOVE;
 23 cananian 1.1.2.1 import harpoon.IR.Quads.PHI;
 24 cananian 1.1.2.1 import harpoon.IR.Quads.Quad;
 25 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory;
 26 cananian 1.1.2.3 import harpoon.IR.Quads.QuadRSSx;
 27 cananian 1.1.2.1 import harpoon.IR.Quads.QuadSSA;
 28 cananian 1.1.2.1 import harpoon.IR.Quads.QuadVisitor;
 29 cananian 1.1.2.1 import harpoon.IR.Quads.SET;
 30 cananian 1.1.2.1 import harpoon.Temp.Temp;
 31 cananian 1.1.2.1 import harpoon.Temp.TempMap;
 32 cananian 1.1.2.1 
 33 cananian 1.1.2.5 import java.lang.reflect.Modifier;
 34 cananian 1.6     
 35 cananian 1.6     import java.util.ArrayList;
 36 cananian 1.6     import java.util.Arrays;
 37 cananian 1.1.2.1 import java.util.HashMap;
 38 cananian 1.1.2.1 import java.util.HashSet;
 39 cananian 1.1.2.1 import java.util.Iterator;
 40 cananian 1.1.2.1 import java.util.List;
 41 cananian 1.1.2.1 import java.util.Map;
 42 cananian 1.1.2.1 import java.util.Set;
 43 cananian 1.6     
 44 cananian 1.6     import net.cscott.jutil.DisjointSet;
 45 cananian 1.6     import net.cscott.jutil.GenericMultiMap;
 46 cananian 1.6     import net.cscott.jutil.MultiMap;
 47 cananian 1.6     import net.cscott.jutil.SnapshotIterator;
 48 cananian 1.6     import net.cscott.jutil.WorkSet;
 49 cananian 1.6     import net.cscott.jutil.Default;
 50 cananian 1.6     import net.cscott.jutil.Default.PairList;
 51 cananian 1.6     
 52 cananian 1.1.2.1 /**
 53 cananian 1.1.2.1  * <code>MemoryOptimization</code> reduces the number of memory operations
 54 cananian 1.1.2.1  * by combining multiple loads/stores to the same field/array element.
 55 cananian 1.1.2.1  * It should be safe with respect to the revised Java memory model.
 56 cananian 1.1.2.1  * 
 57 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 58 cananian 1.7      * @version $Id: MemoryOptimization.java,v 1.7 2004/02/08 05:09:40 cananian Exp $
 59 cananian 1.1.2.1  */
 60 cananian 1.1.2.1 public final class MemoryOptimization
 61 cananian 1.5         extends harpoon.Analysis.Transformation.MethodMutator<Quad> {
 62 cananian 1.1.2.1     final CallGraph cg; final FieldSyncOracle fso;
 63 cananian 1.1.2.1     
 64 cananian 1.1.2.1     /** Creates a <code>MemoryOptimization</code>. */
 65 cananian 1.1.2.1     MemoryOptimization(HCodeFactory parent,
 66 cananian 1.1.2.1                        CallGraph cg, FieldSyncOracle fso) {
 67 cananian 1.1.2.1         // we take in SSA, and output SSA.
 68 cananian 1.1.2.1         super(harpoon.IR.Quads.QuadSSA.codeFactory(parent));
 69 cananian 1.1.2.1         this.cg = cg; this.fso = fso;
 70 cananian 1.1.2.1     }
 71 cananian 1.1.2.1     public MemoryOptimization(HCodeFactory parent,
 72 cananian 1.1.2.1                               ClassHierarchy ch, CallGraph cg) {
 73 cananian 1.1.2.1         this(parent, cg, new FieldSyncOracle(parent, ch, cg));
 74 cananian 1.1.2.1     }
 75 cananian 1.5         protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) {
 76 cananian 1.5             HCode<Quad> hc = input.hcode();
 77 cananian 1.1.2.1         /*
 78 cananian 1.1.2.1         System.out.println("BEFORE: ");
 79 cananian 1.1.2.1         hc.print(new java.io.PrintWriter(System.out));
 80 cananian 1.1.2.1         */
 81 cananian 1.1.2.1         // do the analysis.
 82 cananian 1.1.2.1         Analysis a = new Analysis(hc);
 83 cananian 1.1.2.1         // okay, rename quads and eliminate useless stuff.
 84 cananian 1.5             Iterator<Quad> qit = new SnapshotIterator<Quad>(hc.getElementsI());
 85 cananian 1.1.2.3         // add moves to edges.
 86 cananian 1.7             for (Edge e : a.moves.keySet()) {
 87 cananian 1.7                 Quad q = e.to();
 88 cananian 1.7                 for (Temp[] pair : a.moves.getValues(e)){
 89 cananian 1.1.2.3                 e = addAt(e, new MOVE(q.getFactory(), q,
 90 cananian 1.5                                           a.ds.find(pair[0]),
 91 cananian 1.5                                           a.ds.find(pair[1])));
 92 cananian 1.1.2.3             }
 93 cananian 1.1.2.3         }
 94 cananian 1.5             // note that we created the 'qit' snapshot before adding the MOVEs.
 95 cananian 1.5             while (qit.hasNext()) {
 96 cananian 1.5                 Quad q = qit.next();
 97 cananian 1.1.2.1             // delete useless.
 98 cananian 1.5                 if (a.useless.contains(q))
 99 cananian 1.5                     q.remove();
100 cananian 1.5                 else if (!(q instanceof HEADER)) // rename
101 cananian 1.5                     Quad.replace(q, q.rename(a.tempMap, a.tempMap));
102 cananian 1.1.2.1         }
103 cananian 1.1.2.3         //DeadCode.optimize((harpoon.IR.Quads.Code)hc, null);
104 cananian 1.1.2.1         /*
105 cananian 1.1.2.1         System.out.println("AFTER: ");
106 cananian 1.1.2.1         hc.print(new java.io.PrintWriter(System.out));
107 cananian 1.1.2.1         */
108 cananian 1.1.2.1         // done!
109 cananian 1.1.2.1         return hc;
110 cananian 1.1.2.1     }
111 cananian 1.5         protected HCodeAndMaps<Quad> cloneHCode(HCode<Quad> hc,HMethod newmethod) {
112 cananian 1.1.2.3         // make SSA into RSSx.
113 cananian 1.3.2.1         assert hc.getName().equals(QuadSSA.codename);
114 cananian 1.1.2.3         return MyRSSx.cloneToRSSx((harpoon.IR.Quads.Code)hc, newmethod);
115 cananian 1.1.2.3     }
116 cananian 1.1.2.3     private static class MyRSSx extends QuadRSSx {
117 cananian 1.1.2.3         private MyRSSx(HMethod m) { super(m, null); }
118 cananian 1.5             public static HCodeAndMaps<Quad> cloneToRSSx(harpoon.IR.Quads.Code c,
119 cananian 1.1.2.3                                                HMethod m) {
120 cananian 1.1.2.3             MyRSSx r = new MyRSSx(m);
121 cananian 1.1.2.3             return r.cloneHelper(c, r);
122 cananian 1.1.2.3         }
123 cananian 1.1.2.3     }
124 cananian 1.1.2.3     protected String mutateCodeName(String codeName) {
125 cananian 1.3.2.1         assert codeName.equals(QuadSSA.codename);
126 cananian 1.1.2.3         return MyRSSx.codename;
127 cananian 1.1.2.3     }
128 cananian 1.1.2.3         /** helper routine to add a quad on an edge. */
129 cananian 1.1.2.3     private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); }
130 cananian 1.1.2.3     private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) {
131 cananian 1.5             Quad frm = e.from(); int frm_succ = e.which_succ();
132 cananian 1.5             Quad to  = e.to();   int to_pred = e.which_pred();
133 cananian 1.1.2.3         Quad.addEdge(frm, frm_succ, q, which_pred);
134 cananian 1.1.2.3         Quad.addEdge(q, which_succ, to, to_pred);
135 cananian 1.1.2.3         return to.prevEdge(to_pred);
136 cananian 1.1.2.3     }
137 cananian 1.1.2.3 
138 cananian 1.1.2.1 
139 cananian 1.1.2.1     class Analysis {
140 cananian 1.1.2.1         /** <BasicBlock,temp,field> -> temp */
141 cananian 1.5             final Map<BasicBlock<Quad>,Map<Value,Temp>> out =
142 cananian 1.5                 new HashMap<BasicBlock<Quad>,Map<Value,Temp>>();
143 cananian 1.1.2.1         /** Discovered Temp identities. */
144 cananian 1.5             final DisjointSet<Temp> ds = new DisjointSet<Temp>();
145 cananian 1.1.2.1         /** Set of useless stores */
146 cananian 1.5             final Set<Quad> useless = new HashSet<Quad>();
147 cananian 1.1.2.1         /** tempmap view of ds. */
148 cananian 1.1.2.1         final TempMap tempMap = new TempMap() {
149 cananian 1.5                 public Temp tempMap(Temp t) { return ds.find(t); }
150 cananian 1.1.2.1         };
151 cananian 1.1.2.3         /** <BasicBlock,Value>->Temp */
152 cananian 1.5             private final Map<PairList<BasicBlock<Quad>,Value>,Temp> tempgen =
153 cananian 1.5                 new HashMap<PairList<BasicBlock<Quad>,Value>,Temp>();
154 cananian 1.5             Temp tempgen(BasicBlock<Quad> bb, Value v, Temp template) {
155 cananian 1.5                 PairList<BasicBlock<Quad>,Value> key = Default.pair(bb, v);
156 cananian 1.1.2.3             if (!tempgen.containsKey(key)) {
157 cananian 1.1.2.3                 tempgen.put(key, new Temp(template));
158 cananian 1.1.2.3             }
159 cananian 1.5                 return tempgen.get(key);
160 cananian 1.1.2.3         }
161 cananian 1.1.2.3         /** Edge -> set of moves */
162 cananian 1.5             final MultiMap<Edge,Temp[]> moves = new GenericMultiMap<Edge,Temp[]>();
163 cananian 1.1.2.4         /* set of phis we're adding moves for */
164 cananian 1.5             final Set<PairList<BasicBlock<Quad>,Value>> phiadded =
165 cananian 1.5                 new HashSet<PairList<BasicBlock<Quad>,Value>>();
166 cananian 1.1.2.1 
167 cananian 1.5             Analysis(HCode<Quad> hc) {
168 cananian 1.5                 BasicBlock.Factory<Quad> bbF = new BasicBlock.Factory<Quad>(hc);
169 cananian 1.5                 WorkSet<BasicBlock<Quad>> w =
170 cananian 1.5                     new WorkSet<BasicBlock<Quad>>(bbF.blockSet());
171 cananian 1.1.2.1             // forward dataflow for READ propagation.
172 cananian 1.1.2.1             while (!w.isEmpty()) {
173 cananian 1.5                     BasicBlock<Quad> bb = w.pop();
174 cananian 1.1.2.1                 if (doBlockGET(bbF, bb))  // if block out has changed...
175 cananian 1.1.2.1                     w.addAll(bb.nextSet()); // ... add successors to workset.
176 cananian 1.1.2.1             }
177 cananian 1.1.2.1             // backwards dataflow for WRITE propagation.
178 cananian 1.1.2.1             /*
179 cananian 1.1.2.1             w.addAll(bbF.blockSet());
180 cananian 1.1.2.1             while (!w.isEmpty()) {
181 cananian 1.5                     BasicBlock<Quad> bb = w.pop();
182 cananian 1.1.2.1                 if (doBlockSET(bbF, bb))  // if block out has changed...
183 cananian 1.1.2.1                     w.addAll(bb.prevSet()); // ... add successors to workset.
184 cananian 1.1.2.1             }
185 cananian 1.1.2.1             */
186 cananian 1.1.2.1             // done.
187 cananian 1.1.2.1         }
188 cananian 1.6             Map<Value,List<Temp>> valuemaptempmap(Map<Value,Temp> m,
189 cananian 1.5                                               Quad q, int which_pred) {
190 cananian 1.1.2.2             if (m==null) return null;
191 cananian 1.6                 HashMap<Value,List<Temp>> result = new HashMap<Value,List<Temp>>();
192 cananian 1.7                 for (Map.Entry<Value,Temp> me : m.entrySet()) {
193 cananian 1.5                     Value v = me.getKey().map(ds, q, which_pred);
194 cananian 1.5                     Temp t = ds.find(me.getValue());// not phi-mapped
195 cananian 1.1.2.4                 Temp tt = Value.map(t, ds, q, which_pred);// phi-mapped.
196 cananian 1.6                     result.put(v, Arrays.asList(new Temp[] { tt, t }));
197 cananian 1.1.2.2             }
198 cananian 1.1.2.2             return result;
199 cananian 1.1.2.2         }
200 cananian 1.1.2.2 
201 cananian 1.5             boolean doBlockGET(BasicBlock.Factory<Quad> bbF, BasicBlock<Quad> bb) {
202 cananian 1.5                 List<Quad> quads = bb.statements();
203 cananian 1.1.2.1             // compute in set by merging outs.
204 cananian 1.1.2.1             // map <temp,field>->temp; only present if all inputs have it.
205 cananian 1.1.2.1             // do renaming as per PHI.
206 cananian 1.5                 Map<Value,Temp> in = new HashMap<Value,Temp>();
207 cananian 1.5                 Quad first = quads.get(0);
208 cananian 1.1.2.1             Quad[] pred = first.prev();
209 cananian 1.1.2.2             // collect maps from each pred.
210 cananian 1.6                 List<Map<Value,List<Temp>>> prin = new ArrayList<Map<Value,List<Temp>>>(pred.length);
211 cananian 1.1.2.1             for (int i=0; i<pred.length; i++) {
212 cananian 1.5                     BasicBlock<Quad> prbb = bbF.getBlock(pred[i]);
213 cananian 1.6                     prin.add(valuemaptempmap(out.get(prbb), first, i));
214 cananian 1.1.2.1             }
215 cananian 1.1.2.2             // merge key sets
216 cananian 1.5                 Set<Value> merged=null; boolean allknown=true;
217 cananian 1.1.2.2             for (int i=0; i<pred.length; i++) {
218 cananian 1.6                     if (prin.get(i)==null) { allknown=false; continue; }// no info yet.
219 cananian 1.6                     if (merged==null) merged = prin.get(i).keySet();
220 cananian 1.6                     else merged.retainAll(prin.get(i).keySet());
221 cananian 1.1.2.3                 moves.remove(first.prevEdge(i));
222 cananian 1.1.2.2             }
223 cananian 1.1.2.2             // handle merged inputs.
224 cananian 1.1.2.2             if (merged!=null && allknown)
225 cananian 1.7                     for (Value v : merged) {
226 cananian 1.1.2.4                     Temp t=null; boolean same=true;
227 cananian 1.1.2.4                     for (int i=0; i<pred.length; i++) {
228 cananian 1.6                             if (prin.get(i)==null) continue; // no info.
229 cananian 1.1.2.4                         // tt is the phi-mapped version of the temp.
230 cananian 1.6                             Temp tt = prin.get(i).get(v).get(0);
231 cananian 1.1.2.4                         if (t==null) t=tt;
232 cananian 1.1.2.4                         else if (!t.equals(tt)) same=false;
233 cananian 1.1.2.3                     }
234 cananian 1.1.2.4                     if (t==null) continue; // skip this.
235 cananian 1.1.2.4                     if (same && !phiadded.contains(Default.pair(bb, v)))
236 cananian 1.1.2.4                         in.put(v, t);
237 cananian 1.1.2.4                     else {
238 cananian 1.5                             Temp nt = ds.find(tempgen(bb, v, t));
239 cananian 1.1.2.3                         for (int i=0; i<pred.length; i++) {
240 cananian 1.6                                 if (prin.get(i)==null) continue;
241 cananian 1.1.2.3                             // note that we use the un-phi-mapped temp here.
242 cananian 1.6                                 Temp tt = prin.get(i).get(v).get(1);
243 cananian 1.5                                 moves.add(first.prevEdge(i), new Temp[] {nt,tt});
244 cananian 1.1.2.3                         }
245 cananian 1.1.2.3                         in.put(v, nt);
246 cananian 1.1.2.4                         phiadded.add(Default.pair(bb, v));
247 cananian 1.1.2.2                     }
248 cananian 1.1.2.2                 }
249 cananian 1.1.2.2                     
250 cananian 1.1.2.2 
251 cananian 1.1.2.1             ReadVisitor rv = new ReadVisitor(in);
252 cananian 1.7                 for (Quad q : quads) {
253 cananian 1.1.2.1                 if (!useless.contains(q))
254 cananian 1.1.2.1                     q.accept(rv);
255 cananian 1.1.2.1             }
256 cananian 1.1.2.1             // okay, now we have out map.
257 cananian 1.5                 Map<Value,Temp> oldout = out.put(bb, in);
258 cananian 1.1.2.1             return (oldout==null || !oldout.equals(in));
259 cananian 1.1.2.1         }
260 cananian 1.1.2.1         class ReadVisitor extends QuadVisitor {
261 cananian 1.5                 final Map<Value,Temp> map;
262 cananian 1.5                 ReadVisitor(Map<Value,Temp> map) { this.map = map; }
263 cananian 1.1.2.1             public void visit(Quad q) { /* do nothing */ }
264 cananian 1.1.2.1             public void visit(GET q) {
265 cananian 1.1.2.1                 Value v = new FieldValue
266 cananian 1.5                         (q.field(), q.isStatic()?null:ds.find(q.objectref()));
267 cananian 1.1.2.1                 if (map.containsKey(v)) {
268 cananian 1.5                         ds.union(q.dst(), map.get(v));
269 cananian 1.1.2.1                     useless.add(q);
270 cananian 1.1.2.1                 } else {
271 cananian 1.1.2.1                     map.put(v, q.dst());
272 cananian 1.1.2.1                 }
273 cananian 1.1.2.1             }
274 cananian 1.1.2.1             public void visit(SET q) {
275 cananian 1.1.2.1                 Value v = new FieldValue
276 cananian 1.5                         (q.field(), q.isStatic()?null:ds.find(q.objectref()));
277 cananian 1.1.2.1                 map.put(v, ds.find(q.src()));
278 cananian 1.1.2.1             }
279 cananian 1.1.2.1             public void visit(MOVE q) {
280 cananian 1.1.2.1                 ds.union(q.dst(), q.src());
281 cananian 1.1.2.1                 useless.add(q);
282 cananian 1.1.2.1             }
283 cananian 1.1.2.1             public void visit(AGET q) {
284 cananian 1.5                     Value v = new ArrayValue(ds.find(q.objectref()),
285 cananian 1.5                                              ds.find(q.index()));
286 cananian 1.1.2.1                 if (map.containsKey(v)) {
287 cananian 1.5                         ds.union(q.dst(), map.get(v));
288 cananian 1.1.2.1                     useless.add(q);
289 cananian 1.1.2.1                 } else {
290 cananian 1.1.2.1                     map.put(v, q.dst());
291 cananian 1.1.2.1                 }
292 cananian 1.1.2.1             }
293 cananian 1.1.2.1             public void visit(ASET q) {
294 cananian 1.5                     Value v = new ArrayValue(ds.find(q.objectref()),
295 cananian 1.5                                              ds.find(q.index()));
296 cananian 1.1.2.1                 map.put(v, ds.find(q.src()));
297 cananian 1.1.2.1             }
298 cananian 1.1.2.5             public void visit(MONITORENTER q) { visitMONITOR(q); }
299 cananian 1.1.2.5             public void visit(MONITOREXIT q) { visitMONITOR(q); }
300 cananian 1.1.2.5             public void visitMONITOR(Quad q) {
301 cananian 1.3.2.1                 assert q instanceof MONITORENTER ||
302 cananian 1.3.2.1                             q instanceof MONITOREXIT;
303 cananian 1.5                     for (Iterator<Value> it=map.keySet().iterator(); it.hasNext(); ) {
304 cananian 1.5                         Value v = it.next();
305 cananian 1.1.2.5                     if (v.isArray()) continue;
306 cananian 1.1.2.5                     if (!Modifier.isFinal(v.field().getModifiers()))
307 cananian 1.1.2.5                         it.remove();
308 cananian 1.1.2.5                 }
309 cananian 1.1.2.1             }
310 cananian 1.1.2.5             
311 cananian 1.1.2.1             public void visit(CALL q) {
312 cananian 1.1.2.1                 HMethod calls[] = cg.calls(q.getFactory().getMethod(), q);
313 cananian 1.5                     for (Iterator<Value> it=map.keySet().iterator();
314 cananian 1.5                          it.hasNext(); ) {
315 cananian 1.5                         Value v = it.next();
316 cananian 1.1.2.1                     if (v.isArray()) it.remove();
317 cananian 1.1.2.5                     else if (Modifier.isFinal(v.field().getModifiers()))
318 cananian 1.1.2.5                         continue; // final fields can't be written during call
319 cananian 1.1.2.1                     else for (int i=0; i<calls.length; i++)
320 cananian 1.1.2.1                         if (fso.isSync(calls[i]) ||
321 cananian 1.1.2.1                             fso.isWritten(calls[i], v.field())) {
322 cananian 1.1.2.1                             it.remove();
323 cananian 1.1.2.1                             break;
324 cananian 1.1.2.1                         }
325 cananian 1.1.2.1                 }
326 cananian 1.1.2.1             }
327 cananian 1.1.2.1         }
328 cananian 1.1.2.1     }
329 cananian 1.1.2.1     abstract static class Value { 
330 cananian 1.1.2.1         boolean isArray() { return false; }
331 cananian 1.1.2.1         HField field() { throw new Error(); }
332 cananian 1.5             abstract Value map(DisjointSet<Temp> ds, Quad q, int which_pred);
333 cananian 1.1.2.1         static final Temp map(Temp t,
334 cananian 1.5                                   DisjointSet<Temp> ds, Quad q, int which_pred) {
335 cananian 1.5                 t = ds.find(t);
336 cananian 1.1.2.1             if (q instanceof PHI) {
337 cananian 1.1.2.1                 PHI phi = (PHI) q;
338 cananian 1.1.2.1                 for (int i=0; i<phi.numPhis(); i++)
339 cananian 1.1.2.1                     if (phi.src(i, which_pred).equals(t))
340 cananian 1.5                             return ds.find(phi.dst(i));
341 cananian 1.1.2.1             }
342 cananian 1.1.2.1             return t;
343 cananian 1.1.2.1         }
344 cananian 1.1.2.1     }
345 cananian 1.1.2.1     static class FieldValue extends Value {
346 cananian 1.1.2.1         final HField hf;
347 cananian 1.1.2.1         final Temp receiver;
348 cananian 1.1.2.1         FieldValue(HField hf, Temp receiver) {
349 cananian 1.1.2.1             this.hf = hf; this.receiver=receiver;
350 cananian 1.1.2.1         }
351 cananian 1.1.2.1         HField field() { return hf; }
352 cananian 1.5             Value map(DisjointSet<Temp> ds, Quad q, int which_pred) {
353 cananian 1.1.2.1             if (receiver==null) return this;
354 cananian 1.1.2.1             Temp r = map(receiver, ds, q, which_pred);
355 cananian 1.1.2.1             if (receiver==r) return this;
356 cananian 1.1.2.1             return new FieldValue(hf, r);
357 cananian 1.1.2.1         }
358 cananian 1.1.2.1         public int hashCode() {
359 cananian 1.1.2.1             return hf.hashCode()+7*(receiver==null?0:receiver.hashCode());
360 cananian 1.1.2.1         }
361 cananian 1.1.2.1         public boolean equals(Object o) {
362 cananian 1.1.2.1             if (!(o instanceof FieldValue)) return false;
363 cananian 1.1.2.1             FieldValue fv = (FieldValue) o;
364 cananian 1.1.2.1             return hf.equals(fv.hf) &&
365 cananian 1.1.2.1                 (receiver==null ? fv.receiver==null:
366 cananian 1.1.2.1                  fv.receiver!=null && receiver.equals(fv.receiver));
367 cananian 1.1.2.1         }
368 cananian 1.1.2.1     }
369 cananian 1.1.2.1     static class ArrayValue extends Value {
370 cananian 1.1.2.1         final Temp receiver, length;
371 cananian 1.1.2.1         ArrayValue(Temp receiver, Temp length) {
372 cananian 1.1.2.1             this.receiver=receiver; this.length=length;
373 cananian 1.1.2.1         }
374 cananian 1.1.2.1         boolean isArray() { return true; }
375 cananian 1.5             Value map(DisjointSet<Temp> ds, Quad q, int which_pred) {
376 cananian 1.1.2.1             Temp r = map(receiver, ds, q, which_pred);
377 cananian 1.1.2.1             Temp l = map(length, ds, q, which_pred);
378 cananian 1.1.2.1             if (receiver==r && length==l) return this;
379 cananian 1.1.2.1             return new ArrayValue(r, l);
380 cananian 1.1.2.1         }
381 cananian 1.1.2.1         public int hashCode() {
382 cananian 1.1.2.1             return receiver.hashCode()+length.hashCode();
383 cananian 1.1.2.1         }
384 cananian 1.1.2.1         public boolean equals(Object o) {
385 cananian 1.1.2.1             if (!(o instanceof ArrayValue)) return false;
386 cananian 1.1.2.1             ArrayValue av = (ArrayValue) o;
387 cananian 1.1.2.1             return receiver.equals(av.receiver)&& length.equals(av.length);
388 cananian 1.1.2.1         }
389 cananian 1.1.2.1     }
390 cananian 1.2     }