1 cananian 1.1.2.1 // MethodInliningCodeFactory.java, created Mon Feb 1 09:22:29 1999 by pnkfelix 2 cananian 1.1.2.6 // Copyright (C) 1999 Felix S. Klock II <pnkfelix@mit.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.5 import harpoon.Analysis.Maps.UseDefMap; 7 cananian 1.1.2.5 import harpoon.Analysis.UseDef; 8 cananian 1.1.2.7 import harpoon.ClassFile.HCode; 9 cananian 1.1.2.7 import harpoon.ClassFile.HCodeAndMaps; 10 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 11 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 12 cananian 1.1.2.1 import harpoon.IR.Quads.CALL; 13 cananian 1.1.2.7 import harpoon.IR.Quads.Edge; 14 cananian 1.1.2.1 import harpoon.IR.Quads.HEADER; 15 cananian 1.1.2.1 import harpoon.IR.Quads.METHOD; 16 cananian 1.1.2.1 import harpoon.IR.Quads.MOVE; 17 cananian 1.1.2.7 import harpoon.IR.Quads.NOP; 18 cananian 1.1.2.7 import harpoon.IR.Quads.PHI; 19 cananian 1.1.2.7 import harpoon.IR.Quads.Quad; 20 cananian 1.1.2.8 import harpoon.IR.Quads.QuadRSSx; 21 cananian 1.1.2.8 import harpoon.IR.Quads.QuadSSA; 22 cananian 1.1.2.1 import harpoon.IR.Quads.QuadVisitor; 23 cananian 1.1.2.7 import harpoon.IR.Quads.RETURN; 24 cananian 1.1.2.7 import harpoon.IR.Quads.THROW; 25 cananian 1.1.2.1 import harpoon.Util.Util; 26 cananian 1.1.2.1 import harpoon.Temp.TempMap; 27 cananian 1.1.2.1 import harpoon.Temp.Temp; 28 cananian 1.1.2.1 import harpoon.Temp.CloningTempMap; 29 cananian 1.1.2.1 30 cananian 1.1.2.1 31 cananian 1.1.2.7 import java.util.ArrayList; 32 cananian 1.1.2.7 import java.util.HashMap; 33 cananian 1.1.2.1 import java.util.HashSet; 34 cananian 1.1.2.1 import java.util.Iterator; 35 cananian 1.1.2.7 import java.util.List; 36 cananian 1.1.2.7 import java.util.Map; 37 cananian 1.1.2.7 import java.util.Set; 38 cananian 1.1.2.1 39 cananian 1.1.2.1 import java.io.PrintWriter; 40 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 41 cananian 1.1.2.1 import harpoon.ClassFile.HCodeElement; 42 cananian 1.1.2.1 /** 43 cananian 1.1.2.1 * <code>MethodInliningCodeFactory</code> makes an <code>HCode</code> 44 cananian 1.1.2.1 * from an <code>HMethod</code>, and inlines methods at call sites 45 cananian 1.1.2.1 * registered with the <code>inline(CALL)</code> function. 46 cananian 1.1.2.1 * <P> 47 cananian 1.1.2.1 * Recursive functions are legal, but this factory does not provide 48 cananian 1.1.2.1 * facilities for specifying number of recursive inlinings. 49 cananian 1.1.2.1 * 50 cananian 1.1.2.6 * @author Felix S. Klock II <pnkfelix@mit.edu> 51 cananian 1.4 * @version $Id: MethodInliningCodeFactory.java,v 1.4 2002/04/10 03:00:59 cananian Exp $ */ 52 cananian 1.1.2.1 public class MethodInliningCodeFactory implements HCodeFactory { 53 cananian 1.1.2.1 54 cananian 1.1.2.1 HCodeFactory parent; 55 cananian 1.1.2.7 private final Map h = new HashMap(); // code cache. 56 cananian 1.1.2.1 57 cananian 1.1.2.1 // sites to be inlined 58 cananian 1.1.2.1 HashSet inlinedSites; 59 cananian 1.1.2.1 60 cananian 1.1.2.1 // sites that have already been inlined (used to detect recursive 61 cananian 1.1.2.1 // inlining) 62 cananian 1.1.2.7 private HashSet currentlyInlining = new HashSet(); 63 cananian 1.1.2.1 64 cananian 1.1.2.1 /** Creates a <code>MethodInliningCodeFactory</code>, using 65 cananian 1.1.2.1 <code>parentFactory</code>. 66 cananian 1.1.2.1 <BR> <B>requires:</B> <code>parentFactory</code> produces 67 cananian 1.1.2.1 "quad-ssi" code. 68 cananian 1.1.2.1 */ 69 cananian 1.1.2.1 public MethodInliningCodeFactory(HCodeFactory parentFactory) { 70 cananian 1.3.2.1 assert parentFactory.getCodeName().equals(QuadSSA.codename); 71 cananian 1.1.2.1 parent = parentFactory; 72 cananian 1.1.2.1 inlinedSites = new HashSet(); 73 cananian 1.1.2.1 } 74 cananian 1.1.2.1 75 cananian 1.1.2.1 /** Returns a string naming the type of the <code>HCode</code> 76 cananian 1.1.2.1 that this factory produces. <p> 77 cananian 1.1.2.1 <code>this.getCodeName()</code> should equal 78 cananian 1.1.2.1 <code>this.convert(m).getName()</code> for every 79 cananian 1.1.2.1 <code>HMethod m</code>. 80 cananian 1.1.2.1 */ 81 cananian 1.1.2.8 public String getCodeName() { return MyRSSx.codename; } 82 cananian 1.1.2.1 83 cananian 1.1.2.1 /** Removes representation of method <code>m</code> from all caches 84 cananian 1.1.2.1 in this factory and its parents. 85 cananian 1.1.2.1 */ 86 cananian 1.1.2.1 public void clear(HMethod m) { parent.clear(m); } 87 cananian 1.1.2.1 88 cananian 1.1.2.1 /** Make an <code>HCode</code> from an <code>HMethod</code>. 89 cananian 1.1.2.1 <p> 90 cananian 1.1.2.1 <code>convert</code> is allowed to return null if the requested 91 cananian 1.1.2.1 conversion is impossible; typically this is because it's attempt 92 cananian 1.1.2.1 to convert a source representation failed -- for 93 cananian 1.1.2.1 example, because <code>m</code> is a native method. 94 cananian 1.1.2.1 <p> 95 cananian 1.1.2.1 MethodInliningCodeFactory also inlines any call sites within 96 cananian 1.1.2.1 <code>m</code> marked by the <code>this.inline(CALL)</code> 97 cananian 1.1.2.1 method. 98 cananian 1.1.2.1 */ 99 cananian 1.1.2.1 public HCode convert(HMethod m) { 100 cananian 1.1.2.7 if (h.containsKey(m)) return (HCode) h.get(m); // even if get()==null. 101 cananian 1.1.2.8 harpoon.IR.Quads.Code newCode = (QuadSSA) parent.convert(m); 102 cananian 1.1.2.7 if (newCode == null) { h.put(m, null); return null; } 103 cananian 1.1.2.1 104 cananian 1.1.2.1 // The below was added in response to Scott's request that the 105 cananian 1.1.2.1 // HCode be cloned prior to being fuddled with by the Inliner 106 cananian 1.1.2.8 HCodeAndMaps hcam = MyRSSx.cloneToRSSx(newCode, m); 107 cananian 1.1.2.8 newCode = (MyRSSx) hcam.hcode(); 108 cananian 1.1.2.7 Map aem = hcam.ancestorElementMap(); 109 cananian 1.1.2.1 110 cananian 1.1.2.1 Quad[] ql = (Quad[]) newCode.getElements(); 111 cananian 1.1.2.1 112 cananian 1.1.2.1 // pw.println( "Sites to inline are " + inlinedSites ); 113 cananian 1.1.2.1 114 cananian 1.1.2.1 for (int i=0; i<ql.length; i++) { 115 cananian 1.1.2.1 116 cananian 1.1.2.7 boolean inline = inlinedSites.contains( aem.get(ql[i]) ) && 117 cananian 1.1.2.7 ! currentlyInlining.contains( ((CALL)ql[i]).method() ); 118 cananian 1.1.2.1 if (inline) { 119 cananian 1.1.2.1 120 cananian 1.1.2.7 // pw.out.println("Hey, I'm supposed to inline " + ql[i]); 121 cananian 1.1.2.1 122 cananian 1.1.2.1 // ql[i] is a CALL site that has been marked to be 123 cananian 1.1.2.1 // inlined and isn't being inlined currently. Inline it. 124 cananian 1.1.2.1 CALL call = (CALL) ql[i]; 125 cananian 1.1.2.7 currentlyInlining.add( call.method() );// no recursive inlining 126 cananian 1.1.2.1 HCode calledCode = this.convert( call.method() ); 127 cananian 1.1.2.7 currentlyInlining.remove( call.method() ); 128 cananian 1.1.2.1 129 cananian 1.1.2.1 130 cananian 1.1.2.7 Quad header = (HEADER) calledCode.getRootElement(); 131 cananian 1.1.2.1 Quad newQ = Quad.clone(call.getFactory(), header); 132 cananian 1.1.2.1 133 cananian 1.1.2.1 class QuadArrayBuilder { 134 cananian 1.1.2.1 Set s; 135 cananian 1.1.2.1 QuadArrayBuilder(HEADER q) { 136 cananian 1.1.2.1 s = new HashSet(); 137 cananian 1.1.2.1 recurse(q); 138 cananian 1.1.2.1 } 139 cananian 1.1.2.1 140 cananian 1.1.2.1 private void recurse(Quad q) { 141 cananian 1.1.2.7 if (s.contains(q)) return; 142 cananian 1.1.2.1 s.add(q); 143 cananian 1.1.2.1 Quad[] next = q.next(); 144 cananian 1.1.2.1 for (int j=0; j<next.length; j++) { 145 cananian 1.1.2.1 recurse(next[j]); 146 cananian 1.1.2.1 } 147 cananian 1.1.2.1 } 148 cananian 1.1.2.1 149 cananian 1.1.2.1 Quad[] getElements() { 150 cananian 1.1.2.7 return (Quad[]) s.toArray( new Quad[s.size()] ); 151 cananian 1.1.2.1 } 152 cananian 1.1.2.1 } 153 cananian 1.1.2.1 154 cananian 1.1.2.1 155 cananian 1.1.2.1 QuadArrayBuilder build = new QuadArrayBuilder((HEADER) newQ); 156 cananian 1.1.2.7 Quad[] newElems = build.getElements(); 157 cananian 1.1.2.7 // make method-renaming map. 158 cananian 1.1.2.7 TempMap renameMap = makeMap((METHOD)newQ.next(1), call); 159 cananian 1.1.2.1 160 cananian 1.1.2.7 InliningVisitor qv = new InliningVisitor( call ); 161 cananian 1.1.2.1 for(int j=0; j<newElems.length; j++) { 162 cananian 1.1.2.7 if (newElems[j] instanceof HEADER) continue; 163 cananian 1.1.2.7 Quad nq = newElems[j].rename(renameMap, renameMap); 164 cananian 1.1.2.7 Quad.replace(newElems[j], nq); 165 cananian 1.1.2.7 nq.accept(qv); 166 cananian 1.1.2.1 } 167 cananian 1.1.2.7 // now make phis for throw/return merge. 168 cananian 1.1.2.7 PHI retphi = new PHI(newQ.getFactory(), call, 169 cananian 1.1.2.7 new Temp[0], qv.return_sites.size()); 170 cananian 1.1.2.7 PHI thrphi = new PHI(newQ.getFactory(), call, 171 cananian 1.1.2.7 new Temp[0], qv.throw_sites.size()); 172 cananian 1.1.2.7 Edge ret = call.nextEdge(0), thr = call.nextEdge(1); 173 cananian 1.1.2.7 Quad.addEdge(retphi, 0, (Quad)ret.to(), ret.which_pred()); 174 cananian 1.1.2.7 Quad.addEdge(thrphi, 0, (Quad)thr.to(), thr.which_pred()); 175 cananian 1.1.2.7 int j=0; 176 cananian 1.1.2.7 for (Iterator it=qv.return_sites.iterator(); it.hasNext(); ) 177 cananian 1.1.2.7 Quad.addEdge((Quad)it.next(), 0, retphi, j++); 178 cananian 1.1.2.7 j=0; 179 cananian 1.1.2.7 for (Iterator it=qv.throw_sites.iterator(); it.hasNext(); ) 180 cananian 1.1.2.7 Quad.addEdge((Quad)it.next(), 0, thrphi, j++); 181 cananian 1.1.2.1 } 182 cananian 1.1.2.1 } 183 cananian 1.1.2.7 // remove useless/unreachable phis 184 cananian 1.1.2.7 // (methods which don't return/don't throw exceptions, etc) 185 cananian 1.1.2.7 Unreachable.prune(newCode); 186 cananian 1.1.2.7 // done! 187 cananian 1.1.2.7 h.put(m, newCode); // cache this puppy. 188 cananian 1.1.2.1 return newCode; 189 cananian 1.1.2.8 } 190 cananian 1.1.2.8 private static class MyRSSx extends QuadRSSx { 191 cananian 1.1.2.8 private MyRSSx(HMethod m) { super(m, null); } 192 cananian 1.1.2.8 public static HCodeAndMaps cloneToRSSx(harpoon.IR.Quads.Code c, 193 cananian 1.1.2.8 HMethod m) { 194 cananian 1.1.2.8 MyRSSx r = new MyRSSx(m); 195 cananian 1.1.2.8 return r.cloneHelper(c, r); 196 cananian 1.1.2.8 } 197 cananian 1.1.2.1 } 198 cananian 1.1.2.1 199 cananian 1.1.2.1 /** Marks a call site to be inlined when code is generated. 200 cananian 1.1.2.1 <BR> <B>modifies:</B> <code>this</code> 201 cananian 1.1.2.1 <BR> <B>effects:</B> Marks <code>site</code> as a location to 202 cananian 1.1.2.1 inline if <code>this</code> is ever asked 203 cananian 1.1.2.1 to generate code for the 204 cananian 1.1.2.1 <code>HMethod</code> containing 205 cananian 1.1.2.1 <code>site</code>. 206 cananian 1.1.2.1 */ 207 cananian 1.1.2.1 public void inline(CALL site) { 208 cananian 1.1.2.1 inlinedSites.add(site); 209 cananian 1.1.2.1 } 210 cananian 1.1.2.1 211 cananian 1.1.2.1 /** Marks a call site to not be inlined when code is generated. 212 cananian 1.1.2.1 <BR> <B>modifies:</B> <code>this</code> 213 cananian 1.1.2.1 <BR> <B>effects:</B> If <code>site</code> is in the set of 214 cananian 1.1.2.1 call sites to be inlined, takes 215 cananian 1.1.2.1 <code>site</code> out of the set. Else 216 cananian 1.1.2.1 does nothing. 217 cananian 1.1.2.1 */ 218 cananian 1.1.2.1 public void uninline(CALL site) { 219 cananian 1.1.2.1 inlinedSites.remove(site); 220 cananian 1.1.2.1 } 221 cananian 1.1.2.1 222 cananian 1.1.2.7 private static class MapTempMap extends HashMap implements TempMap { 223 cananian 1.1.2.7 public Temp tempMap(Temp t) { 224 cananian 1.1.2.7 return containsKey(t)?(Temp)get(t):t; 225 cananian 1.1.2.7 } 226 cananian 1.1.2.7 } 227 cananian 1.1.2.7 private TempMap makeMap(METHOD q, CALL site) { 228 cananian 1.1.2.7 Temp[] passedParams = site.params(); 229 cananian 1.1.2.7 MapTempMap mtm = new MapTempMap(); 230 cananian 1.1.2.7 // METHOD has temp var parameters for this sequence of 231 cananian 1.1.2.7 // quads...make a temp map to substitute in the passed 232 cananian 1.1.2.7 // arguments. 233 cananian 1.1.2.7 Temp[] params = q.params(); 234 cananian 1.1.2.7 for (int i=0; i<params.length; i++) 235 cananian 1.1.2.7 mtm.put(params[i], passedParams[i]); 236 cananian 1.1.2.7 return mtm; 237 cananian 1.1.2.7 } 238 cananian 1.1.2.7 239 cananian 1.1.2.1 static class InliningVisitor extends QuadVisitor { 240 cananian 1.1.2.1 241 cananian 1.1.2.1 CALL site; 242 cananian 1.1.2.7 MapTempMap renameMap = new MapTempMap(); 243 cananian 1.1.2.7 List return_sites = new ArrayList(); 244 cananian 1.1.2.7 List throw_sites = new ArrayList(); 245 cananian 1.1.2.1 246 cananian 1.1.2.1 247 cananian 1.1.2.7 InliningVisitor( CALL site ) { 248 cananian 1.1.2.1 this.site = site; 249 cananian 1.1.2.1 } 250 cananian 1.1.2.1 251 cananian 1.1.2.1 public void visit(Quad q) { 252 cananian 1.1.2.1 // not sure what to do in the general case... 253 cananian 1.1.2.1 254 cananian 1.1.2.1 } 255 cananian 1.1.2.1 256 cananian 1.1.2.1 public void visit(METHOD q) { 257 cananian 1.1.2.1 // METHOD succ[0] is the first bit of executable bytecode; 258 cananian 1.1.2.1 // make the code prior to the CALL point to it. 259 cananian 1.1.2.7 Edge frm = site.prevEdge(0), to = q.nextEdge(0); 260 cananian 1.1.2.7 Quad.addEdge((Quad) frm.from(), frm.which_succ(), 261 cananian 1.1.2.7 (Quad) to.to(), to.which_pred()); 262 cananian 1.1.2.1 } 263 cananian 1.1.2.1 264 cananian 1.1.2.1 public void visit(THROW q) { 265 cananian 1.1.2.1 // do something similar to RETURN here 266 cananian 1.1.2.1 Temp retEx = site.retex(); 267 cananian 1.1.2.1 Quad replace; 268 cananian 1.1.2.1 if (retEx != null) { 269 cananian 1.1.2.1 replace = new MOVE(site.getFactory(), null, 270 cananian 1.1.2.1 retEx, q.throwable()); 271 cananian 1.1.2.1 } else { 272 cananian 1.1.2.1 // no place to put the exception...don't know under what 273 cananian 1.1.2.1 // situation this would occur...perhaps put in an 274 cananian 1.1.2.1 // assertion to ensure that it doesn't? 275 cananian 1.1.2.1 replace = new NOP(site.getFactory(), null); 276 cananian 1.3.2.1 assert false; 277 cananian 1.1.2.1 } 278 salcianu 1.1.2.3 // make the successor(replace) be the 1-successor of the 279 salcianu 1.1.2.3 // calling site (the succesor for the "exception thrown" case). 280 cananian 1.1.2.7 Edge frm = q.prevEdge(0); 281 cananian 1.1.2.7 Quad.addEdge((Quad)frm.from(), frm.which_succ(), replace, 0); 282 cananian 1.1.2.7 throw_sites.add(replace); 283 cananian 1.1.2.1 } 284 cananian 1.1.2.1 285 cananian 1.1.2.1 public void visit(RETURN q) { 286 cananian 1.1.2.1 // replace with a MOVE to the target value, and a branch to 287 cananian 1.1.2.1 // the footer. 288 cananian 1.1.2.1 Temp retVal = site.retval(); 289 cananian 1.1.2.1 Quad replace; 290 cananian 1.1.2.1 if (retVal != null) { 291 cananian 1.1.2.1 // put in the MOVE to target val and replace := MOVE 292 cananian 1.1.2.1 replace = new MOVE(site.getFactory(), null, 293 cananian 1.1.2.1 retVal, q.retval()); 294 cananian 1.1.2.1 } else { 295 cananian 1.1.2.1 // there is no value to return...ummm...for now put in 296 cananian 1.1.2.1 // a NOP and replace := NOP 297 cananian 1.1.2.1 replace = new NOP(site.getFactory(), null); 298 cananian 1.1.2.1 } 299 salcianu 1.1.2.3 // make the successor(replace) be the 0-successor of the 300 salcianu 1.1.2.3 // calling site (the succesor for the normal case). 301 cananian 1.1.2.7 Edge frm = q.prevEdge(0); 302 cananian 1.1.2.7 Quad.addEdge((Quad)frm.from(), frm.which_succ(), replace, 0); 303 cananian 1.1.2.7 return_sites.add(replace); 304 cananian 1.1.2.1 } 305 cananian 1.1.2.1 } 306 cananian 1.1.2.1 307 cananian 1.2 }