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