1 cananian 1.1.2.1 // UnHandler.java, created Wed Dec 23 23:30:32 1998 by cananian 2 cananian 1.1.2.16 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.16 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.IR.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.22 import harpoon.Analysis.Quads.Unreachable; 7 cananian 1.1.2.5 import harpoon.ClassFile.HClass; 8 cananian 1.1.2.23 import harpoon.ClassFile.Linker; 9 cananian 1.1.2.7 import harpoon.Temp.CloningTempMap; 10 cananian 1.1.2.1 import harpoon.Temp.Temp; 11 cananian 1.6 import net.cscott.jutil.Default; 12 cananian 1.1.2.1 import harpoon.Util.Util; 13 cananian 1.1.2.1 14 cananian 1.1.2.15 import java.util.Arrays; 15 cananian 1.1.2.11 import java.util.ArrayList; 16 cananian 1.1.2.11 import java.util.HashMap; 17 cananian 1.1.2.34 import java.util.HashSet; 18 cananian 1.1.2.11 import java.util.Iterator; 19 cananian 1.1.2.11 import java.util.List; 20 cananian 1.1.2.11 import java.util.Map; 21 cananian 1.1.2.1 /** 22 cananian 1.1.2.1 * <code>UnHandler</code> make exception handling explicit and removes 23 cananian 1.1.2.1 * the <code>HANDLER</code> quads from the graph. 24 cananian 1.1.2.1 * 25 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 26 cananian 1.7 * @version $Id: UnHandler.java,v 1.7 2004/02/08 03:21:24 cananian Exp $ 27 cananian 1.1.2.1 */ 28 cananian 1.1.2.1 final class UnHandler { 29 cananian 1.1.2.32 private static final boolean ARRAY_BOUNDS_CHECKS 30 cananian 1.1.2.32 = !Boolean.getBoolean("harpoon.unhandler.noarraychecks"); 31 cananian 1.1.2.1 // entry point. 32 cananian 1.1.2.15 public static final Quad unhandler(final QuadFactory qf, final Code code, 33 cananian 1.1.2.15 boolean coalesce_exceptions) { 34 cananian 1.1.2.1 final QuadMap qm = new QuadMap(); 35 cananian 1.1.2.1 final HEADER old_header = (HEADER)code.getRootElement(); 36 cananian 1.1.2.1 final METHOD old_method = (METHOD) old_header.next(1); 37 cananian 1.1.2.1 final HandlerMap hm = new HandlerMap(qf, old_method); 38 cananian 1.1.2.6 final CloningTempMap ctm = new CloningTempMap(code.qf.tempFactory(), 39 cananian 1.1.2.6 qf.tempFactory()); 40 cananian 1.1.2.15 final StaticState ss = new StaticState(qf, qm, hm, ctm, 41 cananian 1.1.2.15 coalesce_exceptions); 42 cananian 1.1.2.1 visitAll(new Visitor(new TempInfo(), ss), old_header); 43 cananian 1.1.2.1 // now qm contains mappings from old to new, we just have to link them. 44 cananian 1.1.2.11 for (Iterator e = code.getElementsI(); e.hasNext(); ) { 45 cananian 1.1.2.11 Quad old = (Quad) e.next(); 46 cananian 1.1.2.1 // link next. 47 cananian 1.1.2.1 Edge[] el = old.nextEdge(); 48 cananian 1.1.2.1 for (int i=0; i<el.length; i++) 49 cananian 1.1.2.1 Quad.addEdge(qm.getFoot((Quad)el[i].from()),el[i].which_succ(), 50 cananian 1.1.2.1 qm.getHead((Quad)el[i].to()), el[i].which_pred()); 51 cananian 1.1.2.1 } 52 cananian 1.1.2.34 // fixup optimized instanceof. 53 cananian 1.1.2.34 ss.iofm.fixup(ss); 54 cananian 1.1.2.1 // fixup try blocks. 55 cananian 1.1.2.6 Temp[] qMp = ((METHOD)qm.getHead(old_method)).params(); 56 cananian 1.1.2.6 final METHOD qM = new METHOD(qf, old_method, qMp, 57 cananian 1.1.2.1 1 /* no HANDLERS any more */); 58 cananian 1.1.2.1 final HEADER qH = (HEADER)qm.getHead(old_header); 59 cananian 1.1.2.1 Quad.addEdge(qH, 1, qM, 0); 60 cananian 1.1.2.1 Edge e = old_method.nextEdge(0); 61 cananian 1.1.2.1 Quad.addEdge(qM, 0, qm.getHead((Quad)e.to()), e.which_pred()); 62 cananian 1.1.2.6 hm.fixup(qf, qH, qm, ss.extra(0), ctm); 63 cananian 1.1.2.1 // return new header. 64 cananian 1.1.2.1 return qH; 65 cananian 1.1.2.1 } 66 cananian 1.1.2.1 /** Recursively visit all quads starting at <code>start</code>. */ 67 cananian 1.1.2.1 private static final void visitAll(Visitor v, Quad start) { 68 cananian 1.1.2.18 start.accept(v); 69 cananian 1.1.2.1 final StaticState ss = v.ss; 70 cananian 1.3.2.1 assert ss.qm.contains(start); 71 cananian 1.1.2.1 Quad[] ql = start.next(); 72 cananian 1.1.2.1 for (int i=0; i<ql.length; i++) { 73 cananian 1.1.2.1 if (ss.qm.contains(ql[i])) continue; // skip if already done. 74 cananian 1.1.2.25 Visitor vv = (ql.length==1)? v : // don't clone if never reused 75 cananian 1.1.2.1 new Visitor((TempInfo) v.ti.clone(), ss); 76 cananian 1.1.2.1 visitAll(vv, ql[i]); 77 cananian 1.1.2.1 } 78 cananian 1.1.2.1 } 79 cananian 1.1.2.1 80 cananian 1.1.2.1 // type information ////////////////// 81 cananian 1.1.2.1 /** Base class for type information. */ 82 cananian 1.1.2.1 private static abstract class Type { 83 cananian 1.1.2.1 // explicit methods to replace "bad" instanceofs. 84 cananian 1.1.2.1 boolean isTop() { return false; } 85 cananian 1.1.2.1 boolean isNonNull() { return false; } 86 cananian 1.1.2.1 boolean isIntConst() { return false; } 87 cananian 1.1.2.1 boolean isFixedArray() { return false; } 88 cananian 1.1.2.1 // explicit accessors to avoid typecasting. 89 cananian 1.1.2.1 int getArrayLength() { throw new Error("Not a FixedArray."); } 90 cananian 1.1.2.1 int getConstValue() { throw new Error("Not an IntConst."); } 91 cananian 1.1.2.31 // debugging 92 cananian 1.1.2.31 public abstract String toString(); 93 cananian 1.1.2.1 // static types for convenience/efficiency. 94 cananian 1.1.2.1 static final Type top=new Top(); 95 cananian 1.1.2.1 static final Type nonnull=new NonNull(); 96 cananian 1.1.2.1 } 97 cananian 1.1.2.1 private static class Top extends Type { 98 cananian 1.1.2.1 boolean isTop() { return true; } 99 cananian 1.1.2.31 public String toString() { return "Top"; } 100 cananian 1.1.2.1 } 101 cananian 1.1.2.1 private static class NonNull extends Type { 102 cananian 1.1.2.1 boolean isNonNull() { return true; } 103 cananian 1.1.2.31 public String toString() { return "NonNull"; } 104 cananian 1.1.2.1 } 105 cananian 1.1.2.1 private static class IntConst extends Type { 106 cananian 1.1.2.1 final int value; 107 cananian 1.1.2.1 IntConst(int value) { this.value = value; } 108 cananian 1.1.2.1 boolean isIntConst() { return true; } 109 cananian 1.1.2.1 int getConstValue() { return value; } 110 cananian 1.1.2.31 public String toString() { return "IntConst("+value+")"; } 111 cananian 1.1.2.1 } 112 cananian 1.1.2.1 private static class FixedArray extends NonNull { 113 cananian 1.1.2.1 final int length; 114 cananian 1.1.2.1 FixedArray(int length) { this.length = length; } 115 cananian 1.1.2.1 boolean isFixedArray() { return true; } 116 cananian 1.1.2.1 int getArrayLength() { return length; } 117 cananian 1.1.2.31 public String toString() { return "FixedArray("+length+")"; } 118 cananian 1.1.2.1 } 119 cananian 1.1.2.1 120 cananian 1.1.2.1 /** Mapping of temps to information known about their values at a 121 cananian 1.1.2.1 * given program point. */ 122 cananian 1.1.2.1 private static class TempInfo implements Cloneable { 123 cananian 1.1.2.31 private static class AliasList { 124 cananian 1.1.2.31 static class TypeBox { 125 cananian 1.1.2.31 Type type; 126 cananian 1.1.2.31 TypeBox(Type type) { this.type = type; } 127 cananian 1.1.2.31 } 128 cananian 1.1.2.31 Temp temp; 129 cananian 1.1.2.31 TypeBox box; 130 cananian 1.1.2.31 AliasList prevAlias, nextAlias; // circular list 131 cananian 1.1.2.31 AliasList(Temp temp, Type ty) { 132 cananian 1.1.2.31 this.temp = temp; this.box=new TypeBox(ty); 133 cananian 1.1.2.31 this.prevAlias=this.nextAlias=this; // its own alias. 134 cananian 1.1.2.31 } 135 cananian 1.1.2.31 } 136 cananian 1.1.2.31 final private Map h = new HashMap(); 137 cananian 1.1.2.31 public TempInfo() { /* do nothing */ } 138 cananian 1.1.2.31 private TempInfo(Map h) { 139 cananian 1.1.2.31 // copy types 140 cananian 1.7 for (Object alO : h.values()) { 141 cananian 1.7 AliasList al = (AliasList) alO; 142 cananian 1.1.2.31 this.put(al.temp, al.box.type); 143 cananian 1.1.2.31 } 144 cananian 1.1.2.31 // and copy aliases 145 cananian 1.7 for (Object alO : h.values()) { 146 cananian 1.7 AliasList al = (AliasList) alO; 147 cananian 1.1.2.31 if (al.prevAlias!=null) 148 cananian 1.1.2.31 this.createAlias(al.temp, al.prevAlias.temp); 149 cananian 1.1.2.31 } 150 cananian 1.1.2.31 } 151 cananian 1.1.2.1 152 cananian 1.1.2.1 /** Get the type of a given temp. */ 153 cananian 1.1.2.1 public Type get(Temp t) { 154 cananian 1.1.2.31 AliasList al = (AliasList) h.get(t); 155 cananian 1.1.2.31 return (al==null) ? Type.top : al.box.type; 156 cananian 1.1.2.1 } 157 cananian 1.1.2.31 /** Put a type for a temp, breaking any alias to the temp. */ 158 cananian 1.1.2.1 public void put(Temp t, Type ty) { 159 cananian 1.1.2.31 breakAlias(t); update(t, ty); 160 cananian 1.1.2.31 } 161 cananian 1.1.2.31 /** Update a type for a temp, updating all aliases as well. */ 162 cananian 1.1.2.31 public void update(Temp t, Type ty) { 163 cananian 1.1.2.31 // all aliases also get the type. 164 cananian 1.1.2.31 if (ty==null) ty=Type.top; 165 cananian 1.1.2.31 AliasList al = (AliasList) h.get(t); 166 cananian 1.1.2.31 // if top and no aliases... 167 cananian 1.1.2.31 if (ty.isTop() && (al==null || al.prevAlias==al)) 168 cananian 1.1.2.31 h.remove(t); // ...save memory. 169 cananian 1.1.2.31 else if (al==null) // no previous type. 170 cananian 1.1.2.31 h.put(t, new AliasList(t, ty)); 171 cananian 1.1.2.31 else al.box.type = ty; // update type for all aliases at once. 172 cananian 1.1.2.31 } 173 cananian 1.1.2.31 /** Process a move. Type of dst becomes that of src. */ 174 cananian 1.1.2.31 public void doMove(Temp dst, Temp src) { 175 cananian 1.1.2.31 put(dst, get(src)); createAlias(dst, src); 176 cananian 1.1.2.31 } 177 cananian 1.1.2.31 /** Break an alias. Type of target becomes independent. */ 178 cananian 1.1.2.31 private void breakAlias(Temp t) { 179 cananian 1.1.2.31 AliasList al = (AliasList) h.get(t); 180 cananian 1.1.2.31 if (al==null || al.prevAlias==al) return; // no aliases. 181 cananian 1.1.2.31 // remove from circular list. 182 cananian 1.1.2.31 al.prevAlias.nextAlias = al.nextAlias; 183 cananian 1.1.2.31 al.nextAlias.prevAlias = al.prevAlias; 184 cananian 1.1.2.31 al.nextAlias=al.prevAlias=al; 185 cananian 1.1.2.31 // and give it a type box of its own. 186 cananian 1.1.2.31 al.box = new AliasList.TypeBox(al.box.type); 187 cananian 1.1.2.31 } 188 cananian 1.1.2.31 /** Create an alias between (all aliases of) dst and (all aliases of) 189 cananian 1.1.2.31 * src. The type of (all aliases of) dst becomes that of src. */ 190 cananian 1.1.2.31 public void createAlias(Temp dst, Temp src) { 191 cananian 1.1.2.31 AliasList d0 = (AliasList) h.get(dst); 192 cananian 1.1.2.31 AliasList s0 = (AliasList) h.get(src); 193 cananian 1.1.2.31 if (d0==null) h.put(dst, d0=new AliasList(dst, Type.top)); 194 cananian 1.1.2.31 if (s0==null) h.put(src, s0=new AliasList(src, Type.top)); 195 cananian 1.1.2.33 // if they're already aliases we're already done. 196 cananian 1.1.2.33 if (d0.box==s0.box) return; 197 cananian 1.1.2.31 // all boxes in dst must point to src. 198 cananian 1.1.2.31 AliasList al=d0; 199 cananian 1.1.2.31 do { 200 cananian 1.1.2.31 al.box=s0.box; 201 cananian 1.1.2.31 al=al.nextAlias; 202 cananian 1.1.2.31 } while (al!=d0); 203 cananian 1.1.2.31 // now join the circular lists. 204 cananian 1.1.2.31 AliasList d1 = d0.nextAlias; 205 cananian 1.1.2.31 AliasList s1 = s0.nextAlias; 206 cananian 1.1.2.31 d0.nextAlias=s1; s1.prevAlias=d0; 207 cananian 1.1.2.31 s0.nextAlias=d1; d1.prevAlias=s0; 208 cananian 1.3.2.1 assert s0.box==d0.box && s1.box==d1.box; 209 cananian 1.1.2.1 } 210 cananian 1.1.2.1 /** Clear all type information (ie at program merge points) */ 211 cananian 1.1.2.1 public void clear() { h.clear(); } 212 cananian 1.1.2.1 /** Clone the temp info (ie at program splits) */ 213 cananian 1.1.2.31 public Object clone() { return new TempInfo(h); } 214 cananian 1.1.2.1 } 215 cananian 1.1.2.1 216 cananian 1.1.2.1 /** mapping from old quads to new quads. */ 217 cananian 1.1.2.1 private static class QuadMap { 218 cananian 1.1.2.11 final private Map h = new HashMap(); 219 cananian 1.1.2.1 void put(Quad old, Quad new_header, Quad new_footer) { 220 cananian 1.1.2.1 h.put(old, new Quad[] { new_header, new_footer }); 221 cananian 1.1.2.1 } 222 cananian 1.1.2.1 Quad getHead(Quad old) { 223 cananian 1.1.2.1 Quad[] ql=(Quad[])h.get(old); return (ql==null)?null:ql[0]; 224 cananian 1.1.2.1 } 225 cananian 1.1.2.1 Quad getFoot(Quad old) { 226 cananian 1.1.2.1 Quad[] ql=(Quad[])h.get(old); return (ql==null)?null:ql[1]; 227 cananian 1.1.2.1 } 228 cananian 1.1.2.1 boolean contains(Quad old) { return h.containsKey(old); } 229 cananian 1.1.2.1 } 230 cananian 1.1.2.1 /** HANDLER information. */ 231 cananian 1.1.2.1 private static final class HandlerMap { 232 cananian 1.1.2.1 /** source of HANDLER info */ 233 cananian 1.1.2.1 final private METHOD oldQm; 234 cananian 1.1.2.1 /** input exception temp for every handlerset */ 235 cananian 1.1.2.1 final Temp Tex; 236 cananian 1.1.2.1 237 cananian 1.1.2.1 /** Constructor. */ 238 cananian 1.1.2.1 HandlerMap(QuadFactory qf, METHOD oldQm) { 239 cananian 1.1.2.1 this.oldQm = oldQm; 240 cananian 1.1.2.3 this.Tex = new Temp(qf.tempFactory(), "exc_"); 241 cananian 1.1.2.1 // make entries for all HANDLERs. 242 cananian 1.1.2.1 Quad[] ql = oldQm.next(); 243 cananian 1.1.2.1 for (int i=1; i<ql.length; i++) 244 cananian 1.1.2.1 get(Hhandler, (HANDLER)ql[i]); 245 cananian 1.1.2.1 } 246 cananian 1.1.2.11 247 cananian 1.1.2.15 /** mapping <Exception, HandlerSet> -> fixup list for 248 cananian 1.1.2.15 * exception construction code */ 249 cananian 1.1.2.15 List registry(HClass HCex, HandlerSet hs) { 250 cananian 1.1.2.15 return get(Hehs, Arrays.asList(new Object[] { HCex, hs })); 251 cananian 1.1.2.15 } 252 cananian 1.1.2.15 private final Map Hehs = new HashMap(); 253 cananian 1.1.2.15 254 cananian 1.1.2.1 /** mapping HandlerSet -> test tree */ 255 cananian 1.1.2.1 void register(NOP from, HandlerSet to) { 256 cananian 1.1.2.11 get(Hhs, to).add(from); 257 cananian 1.1.2.1 } 258 cananian 1.1.2.11 private final Map Hhs = new HashMap(); 259 cananian 1.1.2.1 260 cananian 1.1.2.1 /** lonely throws with null handlersets. */ 261 cananian 1.1.2.11 void register(THROW q) { Vthrows.add(q); } 262 cananian 1.1.2.11 private final List Vthrows = new ArrayList(); 263 cananian 1.1.2.1 264 cananian 1.1.2.1 /** HANDLER->Vector. Later, link all NOPs in Vector to PHI. */ 265 cananian 1.1.2.11 private void register(NOP from, HANDLER to) { 266 cananian 1.1.2.11 get(Hhandler, to).add(from); 267 cananian 1.1.2.1 } 268 cananian 1.1.2.11 private final Map Hhandler = new HashMap(); 269 cananian 1.1.2.1 270 cananian 1.1.2.1 final HandlerSet handlers(Quad q) { 271 cananian 1.1.2.1 Quad[] ql = oldQm.next(); 272 cananian 1.1.2.1 HandlerSet hs = null; 273 cananian 1.1.2.1 for (int i=ql.length-1; i > 0; i--) // element 0 not a HANDLER 274 cananian 1.1.2.1 if (((HANDLER)ql[i]).isProtected(q)) 275 cananian 1.1.2.1 hs = new HandlerSet((HANDLER)ql[i], hs); 276 cananian 1.1.2.1 return hs; 277 cananian 1.1.2.1 } 278 cananian 1.1.2.1 279 cananian 1.1.2.1 /** Link registered HANDLER and HandlerSet edges. */ 280 cananian 1.1.2.1 final void fixup(QuadFactory qf, HEADER newQh, 281 cananian 1.1.2.6 QuadMap qm, Temp Textra, CloningTempMap ctm) { 282 cananian 1.1.2.1 METHOD newQm = (METHOD) newQh.next(1); 283 cananian 1.1.2.17 284 cananian 1.1.2.17 // share exception-generation code 285 cananian 1.7 for (Object lO : Hehs.values()) { 286 cananian 1.7 List l = (List) lO; 287 cananian 1.1.2.15 if (l.size() < 2) continue; // no fixup necessary. 288 cananian 1.1.2.15 PHI phi = new PHI(qf, (Quad)l.get(0), new Temp[0], l.size()); 289 cananian 1.1.2.15 Edge ed = ((NEW)l.get(0)).prevEdge(0); 290 cananian 1.1.2.15 Quad.addEdge(phi, 0, (Quad)ed.to(), ed.which_pred()); 291 cananian 1.1.2.15 for (int i=0; i<l.size(); i++) { 292 cananian 1.1.2.15 if (i>0) ed = ((NOP)l.get(i)).prevEdge(0); 293 cananian 1.1.2.15 Quad.addEdge((Quad)ed.from(), ed.which_succ(), phi, i); 294 cananian 1.1.2.15 } 295 cananian 1.1.2.15 } 296 cananian 1.1.2.1 297 cananian 1.1.2.1 // next do HandlerSets 298 cananian 1.7 for (Object hsO : Hhs.keySet()) { 299 cananian 1.7 HandlerSet hs = (HandlerSet) hsO; 300 cananian 1.1.2.11 List v = get(Hhs, hs); 301 cananian 1.3.2.1 assert v.size()>0; // should be! 302 cananian 1.1.2.11 PHI phi = new PHI(qf, (Quad)v.get(0), 303 cananian 1.1.2.1 new Temp[0], v.size() /*arity*/); 304 cananian 1.1.2.1 // link all to in of phi 305 cananian 1.1.2.1 for (int i=0; i<v.size(); i++) { 306 cananian 1.1.2.11 Edge ed = ((NOP)v.get(i)).prevEdge(0); 307 cananian 1.1.2.1 Quad.addEdge((Quad)ed.from(), ed.which_succ(), phi, i); 308 cananian 1.1.2.1 } 309 cananian 1.1.2.1 // now build instanceof tree. exception in Tex. 310 cananian 1.1.2.24 if (hs==null) { // this is common THROW for no-handler case 311 cananian 1.1.2.26 THROW q0 = new THROW(qf, phi, Tex); 312 cananian 1.1.2.26 Quad.addEdge(phi, 0, q0, 0); 313 cananian 1.1.2.24 register(q0); 314 cananian 1.1.2.26 } else { // create TypeSwitch using each handler in handlerset 315 cananian 1.1.2.26 /* count exception types and create keys array */ 316 cananian 1.1.2.26 ArrayList al = new ArrayList(); 317 cananian 1.1.2.26 for (Iterator ee=hs.iterator(); ee.hasNext(); ) { 318 cananian 1.1.2.26 HClass HCex = ((HANDLER)ee.next()).caughtException(); 319 cananian 1.1.2.26 if (HCex==null) break; // this is the 'catch any' case. 320 cananian 1.1.2.26 al.add(HCex); 321 cananian 1.1.2.26 } 322 cananian 1.1.2.26 /* create TYPESWITCH */ 323 cananian 1.1.2.26 TYPESWITCH ts = new TYPESWITCH 324 cananian 1.1.2.26 (qf, phi, Tex, 325 cananian 1.1.2.26 (HClass[]) al.toArray(new HClass[al.size()]), 326 cananian 1.1.2.28 new Temp[0], true); 327 cananian 1.1.2.26 /* link up typeswitch */ 328 cananian 1.1.2.26 Quad.addEdge(phi, 0, ts, 0); 329 cananian 1.1.2.26 int edge=0; 330 cananian 1.1.2.26 for (Iterator ee=hs.iterator(); edge<ts.arity(); edge++) { 331 cananian 1.1.2.26 if (!ee.hasNext()) break; // no 'catch any' handler 332 cananian 1.1.2.26 HANDLER h = (HANDLER)ee.next(); 333 cananian 1.1.2.1 NOP q0 = new NOP(qf, h); 334 cananian 1.1.2.26 Quad.addEdge(ts, edge, q0, 0); 335 cananian 1.1.2.1 register(q0, h); 336 cananian 1.1.2.1 } 337 cananian 1.1.2.26 if (edge<ts.arity()) { // add a 'rethrow' statement 338 cananian 1.1.2.26 THROW q0 = new THROW(qf, phi, Tex); 339 cananian 1.1.2.26 Quad.addEdge(ts, edge++, q0, 0); 340 cananian 1.1.2.17 register(q0); 341 cananian 1.1.2.17 } 342 cananian 1.3.2.1 assert edge==ts.arity(); 343 cananian 1.1.2.26 } 344 cananian 1.1.2.1 } // end 'for each handler set' 345 cananian 1.1.2.17 346 cananian 1.1.2.17 // attach end-of-the-line throws to footer. 347 cananian 1.1.2.17 FOOTER oldQf = (FOOTER) newQh.next(0); int j=oldQf.arity(); 348 cananian 1.1.2.17 FOOTER newQf = oldQf.resize(j + Vthrows.size()); 349 cananian 1.1.2.17 for (Iterator e=Vthrows.iterator(); e.hasNext(); ) 350 cananian 1.1.2.17 Quad.addEdge((THROW)e.next(), 0, newQf, j++); 351 cananian 1.1.2.1 352 cananian 1.1.2.1 // FINALLY link to handlers 353 cananian 1.7 for (Object hO : Hhandler.keySet()) { 354 cananian 1.7 HANDLER h = (HANDLER) hO; 355 cananian 1.1.2.11 List v = get(Hhandler, h); // note that v can be size 0. 356 cananian 1.1.2.1 Edge ed; Quad tail; 357 cananian 1.1.2.9 // note that v.size() may be equal to zero. 358 cananian 1.1.2.9 // if this is the case, then the unreachable code elimination 359 cananian 1.1.2.9 // below will take care of it. 360 cananian 1.1.2.9 PHI q0 = new PHI(qf, h, new Temp[0], v.size() /*arity*/); 361 cananian 1.1.2.9 for (int i=0; i<v.size(); i++) { 362 cananian 1.1.2.11 ed = ((NOP)v.get(i)).prevEdge(0); 363 cananian 1.1.2.9 Quad.addEdge((Quad)ed.from(), ed.which_succ(), q0, i); 364 cananian 1.1.2.1 } 365 cananian 1.1.2.9 MOVE q1 = new MOVE(qf, h, Quad.map(ctm, h.exceptionTemp()), 366 cananian 1.1.2.9 Tex); 367 cananian 1.1.2.9 Quad.addEdge(q0, 0, q1, 0); 368 cananian 1.1.2.9 // link into handler. 369 cananian 1.1.2.9 ed = qm.getFoot(h).nextEdge(0); tail = q1; 370 cananian 1.1.2.9 371 cananian 1.1.2.1 Quad.addEdge(tail, 0, (Quad)ed.to(), ed.which_pred()); 372 cananian 1.1.2.1 } 373 cananian 1.1.2.9 // trim unreachables (those 0-input phis in the above) 374 cananian 1.1.2.9 Unreachable.prune(newQh); 375 cananian 1.1.2.9 // done. 376 cananian 1.1.2.1 } 377 cananian 1.1.2.1 378 cananian 1.1.2.1 // make hashtables appear to map directly to vectors. 379 cananian 1.1.2.11 private static List get(Map h, Object o) { 380 cananian 1.1.2.11 List v = (List) h.get(o); 381 cananian 1.1.2.11 if (v==null) { v = new ArrayList(); h.put(o, v); } 382 cananian 1.1.2.1 return v; 383 cananian 1.1.2.1 } 384 cananian 1.1.2.1 } 385 cananian 1.1.2.34 /** Fixup information for optimized INSTANCEOFs. */ 386 cananian 1.1.2.34 private static final class InstanceOfFixupMap extends HashSet { 387 cananian 1.1.2.34 void put(CJMP cjmp, PHI phi) { this.add(Default.pair(cjmp, phi)); } 388 cananian 1.1.2.34 void fixup(StaticState ss) { 389 cananian 1.7 for (Object pairO : this) { 390 cananian 1.7 List pair = (List) pairO; 391 cananian 1.1.2.34 CJMP cjmp = (CJMP) pair.get(0); 392 cananian 1.1.2.34 PHI phi = (PHI) pair.get(1); 393 cananian 1.1.2.34 // get new version of the cjmp. 394 cananian 1.1.2.34 cjmp = (CJMP) ss.qm.getFoot(cjmp); 395 cananian 1.1.2.34 // add 0-PHI-0 to 0-edge of CJMP. 396 cananian 1.1.2.34 Edge e = cjmp.nextEdge(0); 397 cananian 1.1.2.34 Quad.addEdge((Quad)e.from(), e.which_succ(), phi, 0); 398 cananian 1.1.2.34 Quad.addEdge(phi, 0, (Quad)e.to(), e.which_pred()); 399 cananian 1.1.2.34 // done! 400 cananian 1.1.2.34 } 401 cananian 1.1.2.34 } 402 cananian 1.1.2.34 } 403 cananian 1.1.2.1 404 cananian 1.1.2.1 /** Static state for visitor. */ 405 cananian 1.1.2.1 private static final class StaticState { 406 cananian 1.1.2.1 final QuadFactory qf; 407 cananian 1.1.2.1 final QuadMap qm; 408 cananian 1.1.2.1 final HandlerMap hm; 409 cananian 1.1.2.6 final CloningTempMap ctm; 410 cananian 1.1.2.34 final InstanceOfFixupMap iofm = new InstanceOfFixupMap(); 411 cananian 1.1.2.15 final boolean coalesce; 412 cananian 1.1.2.11 final List extra = new ArrayList(4); 413 cananian 1.1.2.6 StaticState(QuadFactory qf, QuadMap qm, HandlerMap hm, 414 cananian 1.1.2.15 CloningTempMap ctm, boolean coalesce) { 415 cananian 1.1.2.6 this.qf = qf; this.qm = qm; this.hm = hm; this.ctm = ctm; 416 cananian 1.1.2.15 this.coalesce = coalesce; 417 cananian 1.1.2.1 } 418 cananian 1.1.2.1 Temp extra(int i) { 419 cananian 1.1.2.1 while (extra.size() <= i) 420 cananian 1.1.2.11 extra.add(new Temp(qf.tempFactory(), 421 cananian 1.1.2.11 "un"+extra.size()+"_")); 422 cananian 1.1.2.11 return (Temp) extra.get(i); 423 cananian 1.1.2.1 } 424 cananian 1.1.2.1 } 425 cananian 1.1.2.1 426 cananian 1.1.2.1 /** Guts of the algorithm: map from old to new quads, putting the 427 cananian 1.1.2.1 * result in the QuadMap. */ 428 cananian 1.1.2.1 private static final class Visitor extends QuadVisitor { 429 cananian 1.1.2.1 final QuadFactory qf; 430 cananian 1.1.2.1 // which Temps are non-null/arrays of known length/integer constants 431 cananian 1.1.2.1 final TempInfo ti; 432 cananian 1.1.2.1 // various bits of static state. 433 cananian 1.1.2.1 final StaticState ss; 434 cananian 1.1.2.1 435 cananian 1.1.2.23 Visitor(TempInfo ti, StaticState ss) { 436 cananian 1.1.2.23 this.qf = ss.qf; this.ti = ti; this.ss = ss; 437 cananian 1.1.2.23 //////////////// exceptions. 438 cananian 1.1.2.23 // (try to cache these up here, since they are frequently used) 439 cananian 1.1.2.23 Linker linker=qf.getLinker(); 440 cananian 1.1.2.23 this.HCarraystoreE = 441 cananian 1.1.2.23 linker.forName("java.lang.ArrayStoreException"); 442 cananian 1.1.2.23 this.HCnullpointerE = 443 cananian 1.1.2.23 linker.forName("java.lang.NullPointerException"); 444 cananian 1.1.2.23 this.HCarrayindexE = 445 cananian 1.1.2.23 linker.forName("java.lang.ArrayIndexOutOfBoundsException"); 446 cananian 1.1.2.23 this.HCnegativearrayE = 447 cananian 1.1.2.23 linker.forName("java.lang.NegativeArraySizeException"); 448 cananian 1.1.2.23 this.HCarithmeticE = 449 cananian 1.1.2.23 linker.forName("java.lang.ArithmeticException"); 450 cananian 1.1.2.23 this.HCclasscastE = 451 cananian 1.1.2.23 linker.forName("java.lang.ClassCastException"); 452 cananian 1.1.2.23 } 453 cananian 1.1.2.1 454 cananian 1.1.2.1 /** By default, just clone and set all destinations to top. */ 455 cananian 1.1.2.1 public void visit(Quad q) { 456 cananian 1.3.2.1 assert !ss.qm.contains(q); 457 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 458 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 459 cananian 1.1.2.1 Temp d[] = q.def(); 460 cananian 1.1.2.1 for (int i=0; i<d.length; i++) 461 cananian 1.1.2.1 ti.put(d[i], Type.top); 462 cananian 1.1.2.1 } 463 cananian 1.1.2.29 // watch order of type updates below: always update src before dst 464 cananian 1.1.2.29 // to allow dst type to overwrite src if src==dst. 465 cananian 1.1.2.1 public void visit(AGET q) { 466 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head = nq; 467 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 468 cananian 1.1.2.1 Type Tind = ti.get(q.index()); 469 cananian 1.1.2.32 if (ARRAY_BOUNDS_CHECKS && 470 cananian 1.1.2.32 ! (Tobj.isFixedArray() && 471 cananian 1.1.2.1 Tind.isIntConst() && 472 cananian 1.1.2.1 Tind.getConstValue() < Tobj.getArrayLength() && 473 cananian 1.1.2.1 Tind.getConstValue() >= 0) ) 474 cananian 1.1.2.1 if (Tobj.isFixedArray()) // don't make ALENGTH quad 475 cananian 1.1.2.1 head = boundsCheck(q,head,Tobj.getArrayLength(),q.index()); 476 cananian 1.1.2.1 else // have to query for ALENGTH 477 cananian 1.1.2.1 head = boundsCheck(q,head, q.objectref(), q.index()); 478 cananian 1.1.2.1 if (!Tobj.isNonNull()) 479 cananian 1.1.2.1 head = nullCheck(q, head, q.objectref()); 480 cananian 1.1.2.1 ss.qm.put(q, head, nq); 481 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 482 cananian 1.1.2.29 ti.put(q.dst(), Type.top); 483 cananian 1.1.2.1 } 484 cananian 1.1.2.1 public void visit(ALENGTH q) { 485 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head = nq; 486 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 487 cananian 1.1.2.1 if (!Tobj.isNonNull()) 488 cananian 1.1.2.1 head = nullCheck(q, head, q.objectref()); 489 cananian 1.1.2.1 ss.qm.put(q, head, nq); 490 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 491 cananian 1.1.2.1 if (Tobj.isFixedArray()) 492 cananian 1.1.2.1 ti.put(q.dst(), new IntConst(Tobj.getArrayLength())); 493 cananian 1.1.2.1 else 494 cananian 1.1.2.1 ti.put(q.dst(), Type.top); 495 cananian 1.1.2.1 } 496 cananian 1.1.2.1 public void visit(ANEW q) { 497 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head = nq; 498 cananian 1.1.2.1 Type Tdim = null; 499 cananian 1.1.2.1 for (int i=q.dimsLength()-1; i>=0; i--) { 500 cananian 1.1.2.1 Tdim = ti.get(q.dims(i)); 501 cananian 1.1.2.1 if ( ! (Tdim.isIntConst() && Tdim.getConstValue() >= 0)) 502 cananian 1.1.2.1 head = minusCheck(q, head, q.dims(i)); 503 cananian 1.1.2.1 } 504 cananian 1.1.2.1 ss.qm.put(q, head, nq); 505 cananian 1.1.2.1 if (Tdim.isIntConst()) // type of first array dimension. 506 cananian 1.1.2.1 ti.put(q.dst(), new FixedArray(Tdim.getConstValue())); 507 cananian 1.1.2.1 else ti.put(q.dst(), Type.nonnull); 508 cananian 1.1.2.1 } 509 cananian 1.1.2.1 public void visit(ARRAYINIT q) { 510 cananian 1.1.2.1 // hmm. have to break it up if we can't prove that it's safe. 511 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 512 cananian 1.1.2.1 // XXX break the following into its three component cases? 513 cananian 1.1.2.1 if (Tobj.isFixedArray() && q.offset() >= 0 && 514 cananian 1.1.2.1 q.offset()+q.value().length <= Tobj.getArrayLength() ) { 515 cananian 1.1.2.1 // safe. 516 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 517 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 518 cananian 1.1.2.1 } else { 519 cananian 1.1.2.1 // not safe. Break into components. 520 cananian 1.3.2.1 assert false; // FIXME 521 cananian 1.1.2.1 } 522 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 523 cananian 1.1.2.1 } 524 cananian 1.1.2.1 public void visit(ASET q) { 525 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head = nq; 526 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 527 cananian 1.1.2.1 Type Tind = ti.get(q.index()); 528 cananian 1.1.2.20 // do COMPONENTOF test for non-primitive arrays. 529 cananian 1.1.2.27 if (!q.type().isPrimitive()) 530 cananian 1.1.2.20 head = componentCheck(q, head, q.objectref(), q.src()); 531 cananian 1.1.2.32 if (ARRAY_BOUNDS_CHECKS && 532 cananian 1.1.2.32 ! (Tobj.isFixedArray() && 533 cananian 1.1.2.1 Tind.isIntConst() && 534 cananian 1.1.2.1 Tind.getConstValue() < Tobj.getArrayLength() && 535 cananian 1.1.2.1 Tind.getConstValue() >= 0) ) 536 cananian 1.1.2.1 if (Tobj.isFixedArray()) // don't make ALENGTH quad. 537 cananian 1.1.2.1 head = boundsCheck(q,head,Tobj.getArrayLength(),q.index()); 538 cananian 1.1.2.1 else // have to query for ALENGTH 539 cananian 1.1.2.1 head = boundsCheck(q,head, q.objectref(), q.index()); 540 cananian 1.1.2.1 if (!Tobj.isNonNull()) 541 cananian 1.1.2.1 head = nullCheck(q, head, q.objectref()); 542 cananian 1.1.2.1 ss.qm.put(q, head, nq); 543 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 544 cananian 1.1.2.1 } 545 cananian 1.1.2.1 public void visit(CALL q) { 546 cananian 1.1.2.1 Quad nq, head; 547 cananian 1.3.2.1 assert q.retex()==null : "don't allow checked ex in qwt"; 548 cananian 1.1.2.1 // if retex==null, add the proper checks. 549 cananian 1.1.2.6 if (q.retex()!=null) nq=head=(Quad)q.clone(qf, ss.ctm); 550 cananian 1.1.2.1 else { 551 cananian 1.1.2.19 Temp Tex = ss.extra(0); 552 cananian 1.1.2.30 Temp Trv = q.retval()==null ? null : ss.extra(1); 553 cananian 1.1.2.6 head = new CALL(qf, q, q.method(), Quad.map(ss.ctm,q.params()), 554 cananian 1.1.2.30 Trv, Tex, q.isVirtual(), q.isTailCall(), 555 cananian 1.1.2.21 new Temp[0]); 556 cananian 1.1.2.1 Quad q4 = _throwException_(qf, q, Tex); 557 cananian 1.1.2.19 Quad.addEdge(head, 1, q4, 0); 558 cananian 1.1.2.19 nq = head; 559 cananian 1.1.2.30 // because of "define both" CALL semantics, we need to rewrite 560 cananian 1.1.2.30 // so that we only redefine retval if non-exceptional edge 561 cananian 1.1.2.30 // is taken. 562 cananian 1.1.2.30 if (q.retval()!=null) { 563 cananian 1.1.2.30 Quad q5=new MOVE(qf, q, Quad.map(ss.ctm, q.retval()), Trv); 564 cananian 1.1.2.30 Quad.addEdge(head, 0, q5, 0); 565 cananian 1.1.2.30 nq = q5; 566 cananian 1.1.2.30 } 567 cananian 1.1.2.1 } 568 cananian 1.1.2.1 // if non-static, check that receiver is not null. 569 cananian 1.1.2.1 if (!q.isStatic() && !ti.get(q.params(0)).isNonNull()) 570 cananian 1.1.2.1 head = nullCheck(q, head, q.params(0)); 571 cananian 1.1.2.1 ss.qm.put(q, head, nq); 572 cananian 1.1.2.12 // 'this' is non-null by now. 573 cananian 1.1.2.31 if (!q.isStatic()) ti.update(q.params(0), 574 cananian 1.1.2.31 alsoNonNull(ti.get(q.params(0)))); 575 cananian 1.1.2.1 // nothing known about return values or exceptions thrown. 576 cananian 1.1.2.1 if (q.retval()!=null) ti.put(q.retval(), Type.top); 577 cananian 1.1.2.31 if (q.retex()!=null) ti.put(q.retex(), Type.nonnull); 578 cananian 1.1.2.1 } 579 cananian 1.1.2.1 580 cananian 1.1.2.1 // no run-time checks necessary: 581 cananian 1.1.2.1 /*public void visit(CJMP q);*/ 582 cananian 1.1.2.1 /*public void visit(COMPONENTOF q);*/ 583 cananian 1.1.2.1 584 cananian 1.1.2.1 public void visit(CONST q) { 585 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 586 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 587 cananian 1.1.2.1 if (q.type() == HClass.Int) 588 cananian 1.1.2.1 ti.put(q.dst(), new IntConst(((Integer)q.value()).intValue())); 589 cananian 1.1.2.1 else 590 cananian 1.1.2.1 ti.put(q.dst(), Type.top); 591 cananian 1.1.2.1 } 592 cananian 1.1.2.1 593 cananian 1.1.2.1 /*public void visit(DEBUG q);*/ 594 cananian 1.1.2.1 /*public void visit(FOOTER q);*/ 595 cananian 1.1.2.1 public void visit(GET q) { 596 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 597 cananian 1.1.2.1 if (!q.isStatic()) { 598 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 599 cananian 1.1.2.1 if (!Tobj.isNonNull()) 600 cananian 1.1.2.1 head = nullCheck(q, head, q.objectref()); 601 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 602 cananian 1.1.2.1 } 603 cananian 1.1.2.1 ss.qm.put(q, head, nq); 604 cananian 1.1.2.1 ti.put(q.dst(), Type.top); 605 cananian 1.1.2.1 } 606 cananian 1.1.2.1 /*public void visit(HEADER q);*/ 607 cananian 1.1.2.20 public void visit(INSTANCEOF q) { 608 cananian 1.1.2.20 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 609 cananian 1.1.2.20 Type Tobj = ti.get(q.src()); 610 cananian 1.1.2.20 if (!Tobj.isNonNull()) { 611 cananian 1.1.2.20 // insert explicit test against null. 612 cananian 1.1.2.20 Temp Tr = ss.extra(0); 613 cananian 1.1.2.20 Quad q0 = new CONST(qf, head, Tr, null, HClass.Void); 614 cananian 1.1.2.20 Quad q1 = new OPER(qf, head, Qop.ACMPEQ, Tr, 615 cananian 1.1.2.20 new Temp[]{Quad.map(ss.ctm, q.src()), Tr}); 616 cananian 1.1.2.20 Quad q2 = new CJMP(qf, head, Tr, new Temp[0]); 617 cananian 1.1.2.20 Quad q3 = new CONST(qf, head, Quad.map(ss.ctm, q.dst()), 618 cananian 1.1.2.20 new Integer(0), HClass.Int); 619 cananian 1.1.2.20 Quad q4 = new PHI(qf, head, new Temp[0], 2); 620 cananian 1.1.2.20 Quad.addEdges(new Quad[] { q0, q1, q2, head, q4 }); 621 cananian 1.1.2.20 Quad.addEdge(q2, 1, q3, 0); 622 cananian 1.1.2.20 Quad.addEdge(q3, 0, q4, 1); 623 cananian 1.1.2.20 head = q0; nq = q4; 624 cananian 1.1.2.34 // optimize: if INSTANCEOF directly feeds a CJMP, then we 625 cananian 1.1.2.34 // can change q2 to directly jump to proper dest, removing 626 cananian 1.1.2.34 // need to second test. (also, analysis works better on 627 cananian 1.1.2.34 // this version, due to the way the value merges are arranged) 628 cananian 1.1.2.34 if (q.next(0) instanceof CJMP && 629 cananian 1.1.2.34 ((CJMP)q.next(0)).test().equals(q.dst())) { 630 cananian 1.1.2.34 CJMP cjmp = (CJMP) q.next(0); 631 cananian 1.1.2.34 // translation of this quad will resume after instanceof 632 cananian 1.1.2.34 nq = q2.next(0); 633 cananian 1.1.2.34 // add to fixup map. 634 cananian 1.1.2.34 ss.iofm.put(cjmp, (PHI) q4); 635 cananian 1.1.2.34 } 636 cananian 1.1.2.20 } 637 cananian 1.1.2.20 ss.qm.put(q, head, nq); 638 cananian 1.1.2.29 ti.put(q.dst(), Type.top); 639 cananian 1.1.2.20 } 640 cananian 1.1.2.1 /*public void visit(LABEL q);*/ 641 cananian 1.1.2.1 /*public void visit(HANDLER q);*/ 642 cananian 1.1.2.1 public void visit(METHOD q) { 643 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 644 cananian 1.1.2.1 for (int i=0; i<q.paramsLength(); i++) 645 cananian 1.1.2.1 ti.put(q.params(i), // 'this' is non-null for non-static. 646 cananian 1.1.2.1 (i==0 && !q.isStatic()) ? Type.nonnull : Type.top); 647 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 648 cananian 1.1.2.1 } 649 cananian 1.1.2.1 public void visit(MONITORENTER q) { 650 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 651 cananian 1.1.2.1 Type Tlck = ti.get(q.lock()); 652 cananian 1.1.2.1 if (!Tlck.isNonNull()) 653 cananian 1.1.2.1 head = nullCheck(q, head, q.lock()); 654 cananian 1.1.2.1 ss.qm.put(q, head, nq); 655 cananian 1.1.2.31 ti.update(q.lock(), alsoNonNull(Tlck)); 656 cananian 1.1.2.1 } 657 cananian 1.1.2.1 public void visit(MONITOREXIT q) { 658 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 659 cananian 1.1.2.1 Type Tlck = ti.get(q.lock()); 660 cananian 1.5 // unfortunately, not all compiler authors are smart enough 661 cananian 1.5 // to always protect a MONITOREXIT with a handler. Since there 662 cananian 1.5 // is incorrect bytecode floating around out there already, we're 663 cananian 1.5 // going to have to assume that MONITOREXIT never fails. 664 cananian 1.5 if (Boolean.getBoolean("harpoon.all.monitorexits.are.safe")) { 665 cananian 1.5 // this is the correct thing to do: add a null-pointer 666 cananian 1.5 // check before the MONITOREXIT. 667 cananian 1.5 if (!Tlck.isNonNull()) 668 cananian 1.5 head = nullCheck(q, head, q.lock()); 669 cananian 1.5 ti.update(q.lock(), alsoNonNull(Tlck)); 670 cananian 1.5 } 671 cananian 1.1.2.1 ss.qm.put(q, head, nq); 672 cananian 1.1.2.1 } 673 cananian 1.1.2.1 public void visit(MOVE q) { 674 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 675 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 676 cananian 1.1.2.31 ti.doMove(q.dst(), q.src()); 677 cananian 1.1.2.1 } 678 cananian 1.1.2.1 public void visit(NEW q) { 679 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm); 680 cananian 1.1.2.1 ss.qm.put(q, nq, nq); 681 cananian 1.1.2.1 ti.put(q.dst(), Type.nonnull); 682 cananian 1.1.2.1 } 683 cananian 1.1.2.1 /*public void visit(NOP q);*/ 684 cananian 1.1.2.1 public void visit(OPER q) { 685 cananian 1.1.2.8 // we're really ambitious; we do limited constant prop 686 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 687 cananian 1.1.2.1 Type Td = Type.top; 688 cananian 1.1.2.8 if (q.operandsLength()==1) { 689 cananian 1.1.2.8 Type To = ti.get(q.operands(0)); 690 cananian 1.1.2.8 switch (q.opcode()) { 691 cananian 1.1.2.8 case Qop.INEG: 692 cananian 1.1.2.8 if (To.isIntConst()) 693 cananian 1.1.2.8 Td = new IntConst(-To.getConstValue()); 694 cananian 1.1.2.8 break; 695 cananian 1.1.2.8 default: break; 696 cananian 1.1.2.8 } 697 cananian 1.1.2.8 } else if (q.operandsLength()==2) { 698 cananian 1.1.2.1 Type Tl = ti.get(q.operands(0)); 699 cananian 1.1.2.1 Type Tr = ti.get(q.operands(1)); 700 cananian 1.1.2.1 switch (q.opcode()) { 701 cananian 1.1.2.1 case Qop.LDIV: 702 cananian 1.1.2.1 case Qop.LREM: 703 cananian 1.1.2.1 head = longZeroCheck(q, head, q.operands(1)); 704 cananian 1.1.2.1 break; 705 cananian 1.1.2.1 case Qop.IDIV: 706 cananian 1.1.2.1 if (Tl.isIntConst() && Tr.isIntConst() && 707 cananian 1.1.2.1 Tr.getConstValue()!=0) 708 cananian 1.1.2.1 Td = new IntConst(Tl.getConstValue() / 709 cananian 1.1.2.1 Tr.getConstValue()); 710 cananian 1.1.2.1 else head = intZeroCheck(q, head, q.operands(1)); 711 cananian 1.1.2.1 break; 712 cananian 1.1.2.1 case Qop.IREM: 713 cananian 1.1.2.1 if (Tl.isIntConst() && Tr.isIntConst() && 714 cananian 1.1.2.1 Tr.getConstValue()!=0) 715 cananian 1.1.2.1 Td = new IntConst(Tl.getConstValue() % 716 cananian 1.1.2.1 Tr.getConstValue()); 717 cananian 1.1.2.1 else head = intZeroCheck(q, head, q.operands(1)); 718 cananian 1.1.2.1 break; 719 cananian 1.1.2.1 case Qop.IADD: 720 cananian 1.1.2.1 if (Tl.isIntConst() && Tr.isIntConst()) 721 cananian 1.1.2.1 Td = new IntConst(Tl.getConstValue() + 722 cananian 1.1.2.1 Tr.getConstValue()); 723 cananian 1.1.2.1 break; 724 cananian 1.1.2.1 case Qop.IMUL: 725 cananian 1.1.2.1 if (Tl.isIntConst() && Tr.isIntConst()) 726 cananian 1.1.2.1 Td = new IntConst(Tl.getConstValue() * 727 cananian 1.1.2.1 Tr.getConstValue()); 728 cananian 1.1.2.1 break; 729 cananian 1.1.2.1 default: break; 730 cananian 1.1.2.1 } 731 cananian 1.1.2.1 } 732 cananian 1.1.2.1 ti.put(q.dst(), Td); 733 cananian 1.1.2.1 ss.qm.put(q, head, nq); 734 cananian 1.1.2.1 } 735 cananian 1.1.2.13 public void visit(PHI q) { 736 cananian 1.1.2.13 ti.clear(); // clear all info at program merge points. 737 cananian 1.1.2.13 visit((Quad)q); // copy 738 cananian 1.1.2.13 } 739 cananian 1.1.2.1 /*public void visit(RETURN q);*/ 740 cananian 1.1.2.1 public void visit(SET q) { 741 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head=nq; 742 cananian 1.1.2.1 if (!q.isStatic()) { 743 cananian 1.1.2.1 Type Tobj = ti.get(q.objectref()); 744 cananian 1.1.2.1 if (!Tobj.isNonNull()) 745 cananian 1.1.2.1 head = nullCheck(q, head, q.objectref()); 746 cananian 1.1.2.31 ti.update(q.objectref(), alsoNonNull(Tobj)); 747 cananian 1.1.2.1 } 748 cananian 1.1.2.1 ss.qm.put(q, head, nq); 749 cananian 1.1.2.1 } 750 cananian 1.1.2.1 /*public void visit(SIGMA q);*/ 751 cananian 1.1.2.1 /*public void visit(SWITCH q);*/ 752 cananian 1.1.2.1 public void visit(THROW q) { 753 cananian 1.1.2.14 Temp Tex = Quad.map(ss.ctm, q.throwable()); 754 cananian 1.1.2.14 Quad head = _throwException_(qf, q, Tex); // new throw. 755 cananian 1.1.2.1 Type Tthr = ti.get(q.throwable()); 756 cananian 1.1.2.1 if (!Tthr.isNonNull()) 757 cananian 1.1.2.1 head = nullCheck(q, head, q.throwable()); 758 cananian 1.1.2.14 // make a unreachable chain. The PHI would be enough, except 759 cananian 1.1.2.14 // that the Quad superclass enforces the 'only connect 760 cananian 1.1.2.14 // THROW, HEADER, or RETURN to FOOTER' rule. So we have to 761 cananian 1.1.2.14 // go ahead and clone the THROW so we have something to 762 cananian 1.1.2.14 // connect. This whole string will be wiped out by the 763 cananian 1.1.2.14 // unreachable code elimination pass. 764 cananian 1.1.2.14 Quad q0 = new PHI(qf, q, new Temp[0], 0); // unreachable head. 765 cananian 1.1.2.14 Quad nq = (Quad) q.clone(qf, ss.ctm); // unreachable foot. 766 cananian 1.1.2.14 Quad.addEdge(q0, 0, nq, 0); 767 cananian 1.1.2.1 ss.qm.put(q, head, nq); 768 cananian 1.1.2.31 ti.update(q.throwable(), alsoNonNull(Tthr)); // arguably useless. 769 cananian 1.1.2.1 } 770 cananian 1.1.2.2 public void visit(TYPECAST q) { 771 cananian 1.1.2.2 // translate as: 772 cananian 1.1.2.2 // if (obj!=null && !(obj instanceof class)) 773 cananian 1.1.2.2 // throw new ClassCastException(); 774 cananian 1.1.2.6 Quad nq = (Quad) q.clone(qf, ss.ctm), head; 775 cananian 1.1.2.2 Type Tobj = ti.get(q.objectref()); 776 cananian 1.1.2.2 Temp Tr = ss.extra(0); 777 cananian 1.1.2.6 Quad q1 = new INSTANCEOF(qf, q, Tr, 778 cananian 1.1.2.6 Quad.map(ss.ctm, q.objectref()), 779 cananian 1.1.2.6 q.hclass()); 780 cananian 1.1.2.2 Quad q2 = new CJMP(qf, q, Tr, new Temp[0]); 781 cananian 1.1.2.2 Quad q3 = _throwException_(qf, q, HCclasscastE); 782 cananian 1.1.2.2 Quad.addEdges(new Quad[] { q1, q2, q3 }); 783 cananian 1.1.2.2 Quad.addEdge(q2, 1, nq, 0); 784 cananian 1.1.2.2 head = q1; 785 cananian 1.1.2.2 if (!Tobj.isNonNull()) { // specially handle null. 786 cananian 1.1.2.2 Quad q4 = new CONST(qf, q, Tr, null, HClass.Void); 787 cananian 1.1.2.2 Quad q5 = new OPER(qf, q, Qop.ACMPEQ, Tr, 788 cananian 1.1.2.6 new Temp[] { Quad.map(ss.ctm,q.objectref()), 789 cananian 1.1.2.6 Tr }); 790 cananian 1.1.2.2 Quad q6 = new CJMP(qf, q, Tr, new Temp[0]); 791 cananian 1.1.2.2 Quad q7 = new PHI(qf, q, new Temp[0], 2); // a-ok merge 792 cananian 1.1.2.2 Quad.addEdges(new Quad[] { q4, q5, q6, head }); 793 cananian 1.1.2.2 Quad.addEdge(q6, 1, q7, 0); // if null, branch to a-ok 794 cananian 1.1.2.2 Quad.addEdge(q2, 1, q7, 1); // if instanceof class, goto a-ok 795 cananian 1.1.2.2 Quad.addEdge(q7, 0, nq, 0); // (link PHI to a-ok) 796 cananian 1.1.2.2 head = q4; 797 cananian 1.1.2.2 } 798 cananian 1.1.2.2 ss.qm.put(q, head, nq); 799 cananian 1.1.2.2 // no change to type info, since we don't keep track of class 800 cananian 1.1.2.2 } 801 cananian 1.1.2.1 802 cananian 1.1.2.1 /// Add 'nonnull' attribute 803 cananian 1.1.2.1 Type alsoNonNull(Type in) { 804 cananian 1.1.2.1 return in.isNonNull()?in:Type.nonnull; 805 cananian 1.1.2.1 } 806 cananian 1.1.2.1 807 cananian 1.1.2.1 //////////////// exceptions. 808 cananian 1.1.2.23 private final HClass HCarraystoreE; 809 cananian 1.1.2.23 private final HClass HCnullpointerE; 810 cananian 1.1.2.23 private final HClass HCarrayindexE; 811 cananian 1.1.2.23 private final HClass HCnegativearrayE; 812 cananian 1.1.2.23 private final HClass HCarithmeticE; 813 cananian 1.1.2.23 private final HClass HCclasscastE; 814 cananian 1.1.2.1 815 cananian 1.1.2.1 //////////////// runtime checks. 816 cananian 1.1.2.1 Quad intZeroCheck(Quad old, Quad head, Temp Tz) { 817 cananian 1.1.2.1 QuadFactory qf = head.qf; 818 cananian 1.1.2.1 Temp Tr = ss.extra(0); 819 cananian 1.1.2.1 Quad q0 = new CONST(qf, head, Tr, new Integer(0), HClass.Int); 820 cananian 1.1.2.1 Quad q1 = new OPER(qf, head, Qop.ICMPEQ, Tr, 821 cananian 1.1.2.6 new Temp[] { Quad.map(ss.ctm,Tz), Tr }); 822 cananian 1.1.2.1 Quad q2 = new CJMP(qf, head, Tr, new Temp[0]); 823 cananian 1.1.2.1 Quad q3 = _throwException_(qf, old, HCarithmeticE); 824 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q2, head }); 825 cananian 1.1.2.1 Quad.addEdge(q2, 1, q3, 0); 826 cananian 1.1.2.1 return q0; 827 cananian 1.1.2.1 } 828 cananian 1.1.2.1 Quad longZeroCheck(Quad old, Quad head, Temp Tz) { 829 cananian 1.1.2.1 QuadFactory qf = head.qf; 830 cananian 1.1.2.1 Temp Tr = ss.extra(0); 831 cananian 1.1.2.1 Quad q0 = new CONST(qf, head, Tr, new Long(0), HClass.Long); 832 cananian 1.1.2.1 Quad q1 = new OPER(qf, head, Qop.LCMPEQ, Tr, 833 cananian 1.1.2.6 new Temp[] { Quad.map(ss.ctm, Tz), Tr }); 834 cananian 1.1.2.1 Quad q2 = new CJMP(qf, head, Tr, new Temp[0]); 835 cananian 1.1.2.1 Quad q3 = _throwException_(qf, old, HCarithmeticE); 836 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q2, head }); 837 cananian 1.1.2.1 Quad.addEdge(q2, 1, q3, 0); 838 cananian 1.1.2.1 return q0; 839 cananian 1.1.2.1 } 840 cananian 1.1.2.1 Quad componentCheck(Quad old, Quad head, Temp Tobj, Temp Tsrc) { 841 cananian 1.1.2.1 QuadFactory qf = head.qf; 842 cananian 1.1.2.1 Temp Tr = ss.extra(0); 843 cananian 1.1.2.20 // test Tobj against null & branch around COMPONENTOF. 844 cananian 1.1.2.6 Quad q0 = new COMPONENTOF(qf, head, Tr, 845 cananian 1.1.2.6 Quad.map(ss.ctm, Tobj), 846 cananian 1.1.2.6 Quad.map(ss.ctm, Tsrc)); 847 cananian 1.1.2.1 Quad q1 = new CJMP(qf, head, Tr, new Temp[0]); 848 cananian 1.1.2.1 Quad q2 = _throwException_(qf, old, HCarraystoreE); 849 cananian 1.1.2.20 if (ti.get(Tsrc).isNonNull()) { 850 cananian 1.1.2.20 Quad.addEdges(new Quad[] { q0, q1, q2 }); 851 cananian 1.1.2.20 Quad.addEdge(q1, 1, head, 0); 852 cananian 1.1.2.20 return q0; 853 cananian 1.1.2.20 } else { // insert null check if src is not known non-null 854 cananian 1.1.2.20 Quad qa = new CONST(qf, head, Tr, null, HClass.Void); 855 cananian 1.1.2.20 Quad qb = new OPER(qf, head, Qop.ACMPEQ, Tr, 856 cananian 1.1.2.20 new Temp[] { Quad.map(ss.ctm, Tsrc), Tr }); 857 cananian 1.1.2.20 Quad qc = new CJMP(qf, head, Tr, new Temp[0]); 858 cananian 1.1.2.20 Quad qd = new PHI(qf, head, new Temp[0], 2); 859 cananian 1.1.2.20 Quad.addEdges(new Quad[] { qa, qb, qc, q0, q1, q2 }); 860 cananian 1.1.2.20 Quad.addEdge(qc, 1, qd, 0); 861 cananian 1.1.2.20 Quad.addEdge(q1, 1, qd, 1); 862 cananian 1.1.2.20 Quad.addEdge(qd, 0, head, 0); 863 cananian 1.1.2.20 return qa; 864 cananian 1.1.2.20 } 865 cananian 1.1.2.1 } 866 cananian 1.1.2.1 Quad nullCheck(Quad old, Quad head, Temp Tobj) { 867 cananian 1.1.2.1 QuadFactory qf = head.qf; 868 cananian 1.1.2.1 Temp Tr = ss.extra(0); 869 cananian 1.1.2.1 Quad q0 = new CONST(qf, head, Tr, null, HClass.Void); 870 cananian 1.1.2.1 Quad q1 = new OPER(qf, head, Qop.ACMPEQ, Tr, 871 cananian 1.1.2.6 new Temp[] { Quad.map(ss.ctm, Tobj), Tr }); 872 cananian 1.1.2.1 Quad q2 = new CJMP(qf, head, Tr, new Temp[0]); 873 cananian 1.1.2.1 Quad q3 = _throwException_(qf, old, HCnullpointerE); 874 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q2, head }); 875 cananian 1.1.2.1 Quad.addEdge(q2, 1, q3, 0); 876 cananian 1.1.2.1 return q0; 877 cananian 1.1.2.1 } 878 cananian 1.1.2.1 Quad boundsCheck(Quad old, Quad head, int length, Temp Ttst) { 879 cananian 1.1.2.1 Quad q0 = new CONST(qf, head, ss.extra(0), 880 cananian 1.1.2.1 new Integer(length), HClass.Int); 881 cananian 1.1.2.6 Quad q1 = _boundsCheck_(old, head, ss.extra(0), 882 cananian 1.1.2.6 Quad.map(ss.ctm, Ttst), ss.extra(1)); 883 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 884 cananian 1.1.2.1 return q0; 885 cananian 1.1.2.1 } 886 cananian 1.1.2.1 Quad boundsCheck(Quad old, Quad head, Temp Tobj, Temp Ttst) { 887 cananian 1.1.2.6 Quad q0 = new ALENGTH(qf, head, ss.extra(0), 888 cananian 1.1.2.6 Quad.map(ss.ctm, Tobj)); 889 cananian 1.1.2.6 Quad q1 = _boundsCheck_(old, head, ss.extra(0), 890 cananian 1.1.2.6 Quad.map(ss.ctm, Ttst), ss.extra(1)); 891 cananian 1.1.2.1 Quad.addEdge(q0, 0, q1, 0); 892 cananian 1.1.2.1 return q0; 893 cananian 1.1.2.1 } 894 cananian 1.1.2.1 private Quad _boundsCheck_(Quad old, Quad head, Temp Tlen, Temp Ttst, 895 cananian 1.1.2.1 Temp Textra1) { 896 cananian 1.3.2.1 assert Tlen.tempFactory()==head.qf.tempFactory(); 897 cananian 1.3.2.1 assert Ttst.tempFactory()==head.qf.tempFactory(); 898 cananian 1.3.2.1 assert Textra1.tempFactory()==head.qf.tempFactory(); 899 cananian 1.1.2.1 QuadFactory qf = head.qf; 900 cananian 1.1.2.1 Quad q0 = new OPER(qf, head, Qop.ICMPGT, Tlen, 901 cananian 1.1.2.1 new Temp[] { Tlen, Ttst }); 902 cananian 1.1.2.1 Quad q1 = new CJMP(qf, head, Tlen, new Temp[0]); 903 cananian 1.1.2.1 Temp Tz = Tlen; // reuse this temp. 904 cananian 1.1.2.1 Quad q2 = new CONST(qf, head, Tz, new Integer(0), HClass.Int); 905 cananian 1.1.2.1 Quad q3 = new OPER(qf, head, Qop.ICMPGT, Tz, 906 cananian 1.1.2.1 new Temp[] { Tz, Ttst }); 907 cananian 1.1.2.1 Quad q4 = new CJMP(qf, head, Tz, new Temp[0]); 908 cananian 1.1.2.1 Temp Tex = Tlen, Textra2 = Ttst; // reuse temps again. 909 cananian 1.1.2.1 Quad q5 = new PHI(qf, head, new Temp[0], 2); 910 cananian 1.1.2.1 Quad q6 = _throwException_(qf, old, HCarrayindexE); 911 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q5, q6 }); 912 cananian 1.1.2.1 Quad.addEdge(q1, 1, q2, 0); 913 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q2, q3, q4, head }); 914 cananian 1.1.2.1 Quad.addEdge(q4, 1, q5, 1); 915 cananian 1.1.2.1 return q0; 916 cananian 1.1.2.1 } 917 cananian 1.1.2.1 Quad minusCheck(Quad old, Quad head, Temp Ttst) { 918 cananian 1.1.2.1 QuadFactory qf = head.qf; 919 cananian 1.1.2.1 Temp Tz = ss.extra(0); 920 cananian 1.1.2.1 Quad q0 = new CONST(qf, head, Tz, new Integer(0), HClass.Int); 921 cananian 1.1.2.1 Quad q1 = new OPER(qf, head, Qop.ICMPGT, Tz, 922 cananian 1.1.2.6 new Temp[] { Tz, Quad.map(ss.ctm, Ttst) }); 923 cananian 1.1.2.1 Quad q2 = new CJMP(qf, head, Tz, new Temp[0]); 924 cananian 1.1.2.1 Quad q3 = _throwException_(qf, old, HCnegativearrayE); 925 cananian 1.1.2.1 Quad.addEdges(new Quad[] { q0, q1, q2, head }); 926 cananian 1.1.2.1 Quad.addEdge(q2, 1, q3, 0); 927 cananian 1.1.2.1 return q0; 928 cananian 1.1.2.1 } 929 cananian 1.1.2.1 private Quad _throwException_(QuadFactory qf, Quad old, HClass HCex) { 930 cananian 1.1.2.15 List l = ss.hm.registry(HCex, ss.hm.handlers(old)); 931 cananian 1.1.2.15 if (ss.coalesce && l.size()>0) { 932 cananian 1.1.2.15 // if we've already made an exception of this type, just 933 cananian 1.1.2.15 // save a trailer for the fixup. 934 cananian 1.1.2.15 Quad q = new NOP(qf, old); 935 cananian 1.1.2.15 l.add(q); 936 cananian 1.1.2.15 return q; 937 cananian 1.1.2.15 } 938 cananian 1.1.2.1 Temp Tex = ss.hm.Tex, Tex2 = ss.extra(0), Tnull = ss.extra(1); 939 cananian 1.1.2.1 Quad q0 = new NEW(qf, old, Tex, HCex); 940 cananian 1.1.2.1 Quad q1 = new CALL(qf, old, HCex.getConstructor(new HClass[0]), 941 cananian 1.1.2.30 new Temp[] { Tex }, null, Tex2, false, false, 942 cananian 1.1.2.19 new Temp[0]); 943 cananian 1.1.2.30 Quad q5 = new MOVE(qf, old, Tex, Tex2); 944 cananian 1.1.2.1 Quad q6 = new PHI(qf, old, new Temp[0], 2); 945 cananian 1.1.2.1 Quad q7 = _throwException_(qf, old, Tex); 946 cananian 1.1.2.19 Quad.addEdges(new Quad[] { q0, q1, q6, q7 }); 947 cananian 1.1.2.30 Quad.addEdge(q1, 1, q5, 0); 948 cananian 1.1.2.30 Quad.addEdge(q5, 0, q6, 1); 949 cananian 1.1.2.15 // save the header so we can reuse this exception-generation code. 950 cananian 1.1.2.15 if (ss.coalesce) l.add(q0); 951 cananian 1.1.2.1 return q0; 952 cananian 1.1.2.1 } 953 cananian 1.1.2.1 private Quad _throwException_(QuadFactory qf, Quad old, Temp Tex) { 954 cananian 1.1.2.1 HandlerSet hs = ss.hm.handlers(old); 955 cananian 1.1.2.24 // if ss.coalesce==true, we coalesce even the no-handler case. 956 cananian 1.1.2.24 if (hs==null && !ss.coalesce) { 957 cananian 1.1.2.1 THROW q0 = new THROW(qf, old, Tex); 958 cananian 1.1.2.1 ss.hm.register(q0); 959 cananian 1.1.2.1 return q0; 960 cananian 1.1.2.1 } else { 961 cananian 1.1.2.1 NOP q0 = new NOP(qf, old); 962 cananian 1.1.2.1 ss.hm.register(q0, hs); 963 cananian 1.1.2.1 if (Tex == ss.hm.Tex) return q0; // done already. 964 cananian 1.1.2.1 // else... 965 cananian 1.1.2.1 MOVE q1 = new MOVE(qf, old, ss.hm.Tex, Tex); 966 cananian 1.1.2.1 Quad.addEdge(q1, 0, q0, 0); 967 cananian 1.1.2.1 return q1; 968 cananian 1.1.2.1 } 969 cananian 1.1.2.1 } 970 cananian 1.1.2.1 } 971 cananian 1.2 }