1 cananian 1.1 // SyncRemover.java, created Wed Jul 9 11:57:51 2003 by cananian 2 cananian 1.1 // Copyright (C) 2003 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1 package harpoon.Analysis.DynamicSyncRemoval; 5 cananian 1.1 6 cananian 1.4 import harpoon.Analysis.AllocationInformationMap; 7 cananian 1.4 import harpoon.Analysis.Maps.AllocationInformation; 8 cananian 1.1 import harpoon.Backend.Generic.Frame; 9 cananian 1.1 import harpoon.ClassFile.CachingCodeFactory; 10 cananian 1.1 import harpoon.ClassFile.HClass; 11 cananian 1.1 import harpoon.ClassFile.HCode; 12 cananian 1.1 import harpoon.ClassFile.HCodeAndMaps; 13 cananian 1.1 import harpoon.ClassFile.HCodeFactory; 14 cananian 1.1 import harpoon.ClassFile.HMethod; 15 cananian 1.1 import harpoon.ClassFile.Linker; 16 cananian 1.4 import harpoon.IR.Quads.ANEW; 17 cananian 1.1 import harpoon.IR.Quads.CALL; 18 cananian 1.1 import harpoon.IR.Quads.CJMP; 19 cananian 1.4 import harpoon.IR.Quads.Code; 20 cananian 1.1 import harpoon.IR.Quads.Edge; 21 cananian 1.1 import harpoon.IR.Quads.HEADER; 22 cananian 1.1 import harpoon.IR.Quads.METHOD; 23 cananian 1.1 import harpoon.IR.Quads.MONITORENTER; 24 cananian 1.1 import harpoon.IR.Quads.MONITOREXIT; 25 cananian 1.4 import harpoon.IR.Quads.NEW; 26 cananian 1.1 import harpoon.IR.Quads.PHI; 27 cananian 1.1 import harpoon.IR.Quads.Quad; 28 cananian 1.1 import harpoon.IR.Quads.QuadFactory; 29 cananian 1.1 import harpoon.IR.Quads.QuadNoSSA; 30 cananian 1.1 import harpoon.IR.Quads.QuadValueVisitor; 31 cananian 1.1 import harpoon.Temp.Temp; 32 cananian 1.1 import harpoon.Temp.TempFactory; 33 cananian 1.1 import harpoon.Temp.TempMap; 34 cananian 1.5 import net.cscott.jutil.WorkSet; 35 cananian 1.1 import java.util.ArrayList; 36 cananian 1.1 import java.util.Arrays; 37 cananian 1.1 import java.util.Collection; 38 cananian 1.1 import java.util.HashSet; 39 cananian 1.1 import java.util.Iterator; 40 cananian 1.1 import java.util.LinkedHashMap; 41 cananian 1.1 import java.util.List; 42 cananian 1.1 import java.util.Map; 43 cananian 1.1 import java.util.Set; 44 cananian 1.1 45 cananian 1.1 /** 46 cananian 1.1 * <code>SyncRemover</code> calls a "magic" native method to determine 47 cananian 1.1 * if synchronization should be done on this object, and skips the 48 cananian 1.1 * <code>MONITORENTER</code>/<code>MONITOREXIT</code> sequence if the 49 cananian 1.1 * answer is no. We need to duplication and split the code between 50 cananian 1.1 * <code>MONITORENTER</code> and <code>MONITOREXIT</code> for this to 51 cananian 1.1 * play nicely with the Transactions transformation. 52 cananian 1.1 * 53 cananian 1.1 * For best results, run <code>TreePostPass</code> after this 54 cananian 1.1 * transformation. 55 cananian 1.1 * 56 cananian 1.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 57 cananian 1.6 * @version $Id: SyncRemover.java,v 1.6 2004/02/08 03:19:25 cananian Exp $ 58 cananian 1.1 */ 59 cananian 1.1 public class SyncRemover 60 cananian 1.1 extends harpoon.Analysis.Transformation.MethodMutator<Quad> { 61 cananian 1.1 private final HMethod checkMethod; 62 cananian 1.1 63 cananian 1.1 /** Creates a <code>SyncRemover</code>. */ 64 cananian 1.1 public SyncRemover(HCodeFactory parent, Linker l) { 65 cananian 1.1 // force a caching quad-no-ssa code factory. 66 cananian 1.1 this(new CachingCodeFactory(QuadNoSSA.codeFactory(parent)), l); 67 cananian 1.1 } 68 cananian 1.1 /** The private constructor knows that the code factory is cached and 69 cananian 1.1 * produces quad-no-ssa form. */ 70 cananian 1.1 private SyncRemover(CachingCodeFactory parent, Linker l) { 71 cananian 1.1 super(parent); 72 cananian 1.1 // get the reference to the discriminator method. 73 cananian 1.2 checkMethod = l.forName("harpoon.Runtime.DynamicSyncImpl") 74 cananian 1.3 .getMethod("isNoSync",new HClass[]{l.forName("java.lang.Object")}); 75 cananian 1.1 } 76 cananian 1.1 /** Return an <code>HCodeFactory</code> that will clean up the 77 cananian 1.1 * tree form of the transformed code by performing some optimizations 78 cananian 1.1 * which can't be represented in quad form. */ 79 cananian 1.1 public static HCodeFactory treeCodeFactory(Frame f, HCodeFactory hcf) { 80 cananian 1.1 return new TreeCallOpt(f).codeFactory(hcf); 81 cananian 1.1 } 82 cananian 1.1 protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) { 83 cananian 1.1 Code hc = (Code) input.hcode(); 84 cananian 1.1 METHOD qM = hc.getRootElement().method(); 85 cananian 1.4 AllocationInformationMap aim = (AllocationInformationMap)//heh heh 86 cananian 1.4 hc.getAllocationInformation(); 87 cananian 1.1 // recursively traverse graph, rewriting as we go. 88 cananian 1.4 munge(new Munger(qM.getFactory(), aim), qM); 89 cananian 1.1 return hc; 90 cananian 1.1 } 91 cananian 1.1 private void munge(Munger munger, Quad start) { 92 cananian 1.1 WorkSet<Quad> toDo = new WorkSet<Quad>(); 93 cananian 1.1 Set<Quad> done = new HashSet<Quad>(); 94 cananian 1.1 toDo.add(start); 95 cananian 1.1 while (!toDo.isEmpty()) { 96 cananian 1.1 Quad q = toDo.removeFirst(); 97 cananian 1.1 if (done.contains(q)) continue; 98 cananian 1.6 for (Edge e : q.accept(munger)){ 99 cananian 1.1 toDo.add(e.to()); 100 cananian 1.1 } 101 cananian 1.1 done.add(q); 102 cananian 1.1 } 103 cananian 1.1 } 104 cananian 1.1 105 cananian 1.1 private class Munger extends QuadValueVisitor<Collection<Edge>> { 106 cananian 1.1 final Collection<Edge> NO_EDGES = Arrays.asList(new Edge[0]); 107 cananian 1.4 final AllocationInformationMap aim; 108 cananian 1.1 final QuadFactory qf; 109 cananian 1.1 final TempFactory tf; 110 cananian 1.4 Munger(QuadFactory qf, AllocationInformationMap aim) { 111 cananian 1.1 this.qf = qf; 112 cananian 1.1 this.tf = qf.tempFactory(); 113 cananian 1.4 this.aim = aim; 114 cananian 1.1 } 115 cananian 1.1 116 cananian 1.1 public Collection<Edge> visit(Quad q) { 117 cananian 1.1 return q.succC(); 118 cananian 1.1 } 119 cananian 1.1 public Collection<Edge> visit(MONITOREXIT q) { 120 cananian 1.1 // don't visit beyond a monitorexit. 121 cananian 1.1 return NO_EDGES; 122 cananian 1.1 } 123 cananian 1.1 public Collection<Edge> visit(MONITORENTER q) { 124 cananian 1.1 // rewrite this monitor enter, recurse into contents, and 125 cananian 1.1 // then continue after block. 126 cananian 1.1 127 cananian 1.1 Collection<Edge> result = new ArrayList<Edge>(); 128 cananian 1.1 // rewrite contents. 129 cananian 1.1 munge(this, q.next(0)); 130 cananian 1.1 // now copy contents 131 cananian 1.4 CopyInfo ci = copyGraph(q, aim); 132 cananian 1.1 // now rewrite as follows: 133 cananian 1.1 134 cananian 1.1 // MONITORENTER(lock) 135 cananian 1.1 // statements 136 cananian 1.1 // MONITOREXIT(lock) 137 cananian 1.1 // --- becomes --- 138 cananian 1.1 // if (isSync(lock)) { 139 cananian 1.1 // MONITORENTER(lock) 140 cananian 1.1 // statements 141 cananian 1.1 // MONITOREXIT(lock) 142 cananian 1.1 // } else { 143 cananian 1.1 // statements 144 cananian 1.1 // } 145 cananian 1.3 Temp retval = new Temp(tf, "isNoSync"); 146 cananian 1.1 Temp retex = new Temp(tf, "ignore"); 147 cananian 1.1 Edge in = q.prevEdge(0); 148 cananian 1.1 CALL q0 = new CALL(qf, q, checkMethod, new Temp[] { q.lock() }, 149 cananian 1.1 retval, retex, false, false, new Temp[0]); 150 cananian 1.2 CJMP q1 = new CJMP(qf, q, retval, new Temp[0]); 151 cananian 1.2 PHI q2 = new PHI(qf, q, new Temp[0], 2); 152 cananian 1.1 in = addAt(in, q0); 153 cananian 1.3 in = addAt(in, q1); // monitorenter on 'false' edge 154 cananian 1.2 in = addAt(in, q2); 155 cananian 1.2 Quad.addEdge(q0, 1, q2, 1); 156 cananian 1.3 // add edge past copied monitorenter on 'true' edge. 157 cananian 1.1 Edge e = ci.start.copy.nextEdge(0); 158 cananian 1.3 Quad.addEdge(q1, 1, e.to(), e.which_pred()); 159 cananian 1.1 160 cananian 1.1 // now for every MONITOREXIT in copyMap, add a phi like so: 161 cananian 1.1 // 162 cananian 1.1 // orig1 orig1 ... 163 cananian 1.1 // \ \ / 164 cananian 1.1 // MONITOREXIT -> MONITOREXIT copy1 165 cananian 1.1 // \ \ / 166 cananian 1.1 // orig2 PHI 167 cananian 1.1 // | 168 cananian 1.1 // orig2 169 cananian 1.6 for (CopyPair<MONITOREXIT> exit : ci.endList) { 170 cananian 1.1 PHI qP = new PHI(qf, exit.orig, new Temp[0], 2); 171 cananian 1.1 addAt(exit.orig.nextEdge(0), qP); 172 cananian 1.1 // now add edge from before copied monitorexit 173 cananian 1.1 Edge ee = exit.copy.prevEdge(0); 174 cananian 1.1 Quad.addEdge(ee.from(), ee.which_succ(), qP, 1); 175 cananian 1.1 // add to our successors list 176 cananian 1.1 result.addAll(qP.succC()); 177 cananian 1.1 } 178 cananian 1.1 // done! 179 cananian 1.1 return result; 180 cananian 1.1 } 181 cananian 1.1 /** helper routine to add a quad on an edge. */ 182 cananian 1.1 private Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); } 183 cananian 1.1 /** helper routine to add a quad on an edge. */ 184 cananian 1.1 private Edge addAt(Edge e, int which_pred, Quad q, int which_succ) { 185 cananian 1.1 Quad frm = e.from(); int frm_succ = e.which_succ(); 186 cananian 1.1 Quad to = e.to(); int to_pred = e.which_pred(); 187 cananian 1.1 Quad.addEdge(frm, frm_succ, q, which_pred); 188 cananian 1.1 Quad.addEdge(q, which_succ, to, to_pred); 189 cananian 1.1 return to.prevEdge(to_pred); 190 cananian 1.1 } 191 cananian 1.1 } 192 cananian 1.1 private static class CopyPair<T> { 193 cananian 1.1 public final T orig, copy; 194 cananian 1.1 CopyPair(T orig, T copy) { this.orig = orig; this.copy = copy; } 195 cananian 1.1 } 196 cananian 1.1 private static class CopyInfo { 197 cananian 1.1 // left of pair is orig; right of pair is copy 198 cananian 1.1 final CopyPair<MONITORENTER> start; 199 cananian 1.1 final List<CopyPair<MONITOREXIT>> endList = 200 cananian 1.1 new ArrayList<CopyPair<MONITOREXIT>>(); 201 cananian 1.1 CopyInfo(MONITORENTER origStart, MONITORENTER copyStart) { 202 cananian 1.1 this.start = new CopyPair<MONITORENTER>(origStart, copyStart); 203 cananian 1.1 } 204 cananian 1.1 } 205 cananian 1.4 private static CopyInfo copyGraph(MONITORENTER start, 206 cananian 1.4 AllocationInformationMap aim) { 207 cananian 1.1 WorkSet<Quad> frontier = new WorkSet<Quad>(); 208 cananian 1.1 List<Edge> toLink = new ArrayList<Edge>(); 209 cananian 1.1 Map<Quad,Quad> copyMap = new LinkedHashMap<Quad,Quad>(); 210 cananian 1.1 211 cananian 1.1 // initialize: deal with start node. 212 cananian 1.1 CopyInfo result = new CopyInfo 213 cananian 1.1 (start, (MONITORENTER) 214 cananian 1.1 start.rename(identityTempMap, identityTempMap)); 215 cananian 1.1 copyMap.put(result.start.orig, result.start.copy); 216 cananian 1.1 frontier.addAll(Arrays.asList(result.start.orig.next())); 217 cananian 1.1 toLink.addAll(result.start.orig.succC()); 218 cananian 1.1 219 cananian 1.1 while(!frontier.isEmpty()) { 220 cananian 1.1 Quad q = frontier.removeFirst(); 221 cananian 1.1 if (copyMap.containsKey(q)) continue; 222 cananian 1.1 // handle subgraphs first. 223 cananian 1.1 if (q instanceof MONITORENTER) { 224 cananian 1.1 // this is a subgraph: recurse. 225 cananian 1.4 CopyInfo ci = copyGraph((MONITORENTER)q, aim); 226 cananian 1.1 // now merge the info, including the mapping for q 227 cananian 1.1 copyMap.put(ci.start.orig, ci.start.copy); 228 cananian 1.1 // continue from the subgraph's exit points. 229 cananian 1.6 for (CopyPair<MONITOREXIT> exit : ci.endList) { 230 cananian 1.1 frontier.addAll(Arrays.asList(exit.orig.next())); 231 cananian 1.1 toLink.addAll(exit.orig.succC()); 232 cananian 1.1 copyMap.put(exit.orig, exit.copy); 233 cananian 1.1 } 234 cananian 1.1 continue; 235 cananian 1.1 } 236 cananian 1.1 // otherwise, clone q: 237 cananian 1.1 Quad qq = q.rename(identityTempMap, identityTempMap); 238 cananian 1.1 // add to the mapping. 239 cananian 1.1 copyMap.put(q, qq); 240 cananian 1.4 // clone allocation properties 241 cananian 1.4 if (q instanceof ANEW || q instanceof NEW) 242 cananian 1.4 if (aim!=null) aim.transfer(qq, q, identityTempMap, aim); 243 cananian 1.1 // find connected quads. 244 cananian 1.1 if (q instanceof MONITOREXIT) { 245 cananian 1.1 // don't go past MONITOREXIT, but add it to the endList 246 cananian 1.1 result.endList.add(new CopyPair<MONITOREXIT> 247 cananian 1.1 ((MONITOREXIT)q, (MONITOREXIT)qq)); 248 cananian 1.1 } else { 249 cananian 1.1 // okay, it's normal, keep going through. 250 cananian 1.1 frontier.addAll(Arrays.asList(q.next())); 251 cananian 1.1 // note that we need to link this up eventually 252 cananian 1.1 toLink.addAll(q.succC()); 253 cananian 1.1 } 254 cananian 1.1 } 255 cananian 1.1 // now link all the outgoing edges. 256 cananian 1.6 for (Edge e : toLink) { 257 cananian 1.1 Quad.addEdge(copyMap.get(e.from()), e.which_succ(), 258 cananian 1.1 copyMap.get(e.to()), e.which_pred()); 259 cananian 1.1 } 260 cananian 1.1 // done! 261 cananian 1.1 return result; 262 cananian 1.1 } 263 cananian 1.1 private static final TempMap identityTempMap = new TempMap() { 264 cananian 1.1 public Temp tempMap(Temp t) { return t; } 265 cananian 1.1 }; 266 cananian 1.1 }