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