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 }