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 }