1 cananian 1.1.2.1 // TypeSwitchRemover.java, created Tue Oct 10 13:32:03 2000 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Analysis.Quads;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.Analysis.Maps.Derivation;
  7 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
  8 cananian 1.1.2.1 import harpoon.ClassFile.HCode;
  9 cananian 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps;
 10 cananian 1.1.2.1 import harpoon.ClassFile.HCodeElement;
 11 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory;
 12 cananian 1.1.2.2 import harpoon.IR.Quads.CJMP;
 13 cananian 1.1.2.2 import harpoon.IR.Quads.Code;
 14 cananian 1.1.2.2 import harpoon.IR.Quads.Edge;
 15 cananian 1.1.2.2 import harpoon.IR.Quads.INSTANCEOF;
 16 cananian 1.1.2.2 import harpoon.IR.Quads.Quad;
 17 cananian 1.1.2.2 import harpoon.IR.Quads.QuadFactory;
 18 cananian 1.1.2.2 import harpoon.IR.Quads.SIGMA;
 19 cananian 1.1.2.2 import harpoon.IR.Quads.TYPESWITCH;
 20 cananian 1.1.2.1 import harpoon.IR.LowQuad.DerivationMap;
 21 cananian 1.1.2.1 import harpoon.Temp.Temp;
 22 cananian 1.1.2.1 import harpoon.Temp.TempFactory;
 23 cananian 1.6     import net.cscott.jutil.CombineIterator;
 24 cananian 1.1.2.1 import harpoon.Util.HClassUtil;
 25 cananian 1.1.2.1 import harpoon.Util.Util;
 26 cananian 1.1.2.1 
 27 cananian 1.1.2.1 import java.util.Iterator;
 28 cananian 1.1.2.1 import java.util.LinkedList;
 29 cananian 1.1.2.1 import java.util.List;
 30 cananian 1.1.2.1 /**
 31 cananian 1.1.2.1  * <code>TypeSwitchRemover</code> converts <code>TYPESWITCH</code> quads
 32 cananian 1.1.2.1  * into chains of <code>INSTANCEOF</code> and <code>CJMP</code> quads.
 33 cananian 1.1.2.1  * 
 34 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 35 cananian 1.6      * @version $Id: TypeSwitchRemover.java,v 1.6 2004/02/08 01:53:14 cananian Exp $
 36 cananian 1.1.2.1  */
 37 cananian 1.1.2.1 public final class TypeSwitchRemover
 38 cananian 1.5         extends harpoon.Analysis.Transformation.MethodMutator<Quad> {
 39 cananian 1.1.2.1     
 40 cananian 1.1.2.1     /** Creates a <code>TypeSwitchRemover</code>. */
 41 cananian 1.1.2.1     public TypeSwitchRemover(HCodeFactory parent) { super(parent); }
 42 cananian 1.1.2.1 
 43 cananian 1.5         protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) {
 44 cananian 1.1.2.1         Code hc = (Code) input.hcode();
 45 cananian 1.1.2.1         // get mutable derivation map.
 46 cananian 1.1.2.1         // (no changes necessary to allocation information map)
 47 cananian 1.5             DerivationMap<Quad> dm = (DerivationMap<Quad>) hc.getDerivation();
 48 cananian 1.1.2.1         // dm (if non-null) will be updated as TYPESWITCHes are replaced.
 49 cananian 1.1.2.1 
 50 cananian 1.1.2.1         // we put all elements in array to avoid screwing up the
 51 cananian 1.1.2.1         // iterator as we mutate the quad graph in-place.
 52 cananian 1.5             Quad[] allquads = hc.getElements();
 53 cananian 1.1.2.1         for (int i=0; i<allquads.length; i++)
 54 cananian 1.1.2.1             if (allquads[i] instanceof TYPESWITCH)
 55 cananian 1.1.2.1                 replace((TYPESWITCH) allquads[i], dm);
 56 cananian 1.1.2.1         // now we have to prune off any newly-unreachable TYPESWITCH cases.
 57 cananian 1.1.2.1         Unreachable.prune(hc);
 58 cananian 1.1.2.1         // yay, done!
 59 cananian 1.1.2.1         return hc;
 60 cananian 1.1.2.1     }
 61 cananian 1.1.2.1 
 62 cananian 1.5         private static void replace(TYPESWITCH ts, DerivationMap<Quad> dm) {
 63 cananian 1.1.2.1         /* construct instanceof chain */
 64 cananian 1.1.2.1         Edge e = ts.prevEdge(0);
 65 cananian 1.1.2.1         TypeTree tt =
 66 cananian 1.5                 makeTest(constructCT(ts), ts, e.from(), e.which_succ(),
 67 cananian 1.1.2.1                      ts.src(), dm);
 68 cananian 1.1.2.1         // fixup derivations if present.
 69 cananian 1.1.2.1         if (dm!=null) tt.fixupSigmaDerivations(ts, dm);
 70 cananian 1.1.2.1     }
 71 cananian 1.1.2.1     /** Construct INSTANCEOF chain from a proper & pruned ClassTree */
 72 cananian 1.1.2.1     private static TypeTree makeTest(ClassTree ct, TYPESWITCH ts,
 73 cananian 1.1.2.1                                      Quad head, int which_succ, Temp[] src,
 74 cananian 1.5                                          DerivationMap<Quad> dm) {
 75 cananian 1.1.2.1         QuadFactory qf = ts.getFactory();
 76 cananian 1.1.2.1         TempFactory tf = qf.tempFactory();
 77 cananian 1.1.2.1         TypeNode ftn = new TypeNode(null), ptn = ftn; // keep track of TypeTree
 78 cananian 1.5             for (Iterator<ClassTree> it=ct.children(); it.hasNext(); ) {
 79 cananian 1.1.2.1             // for each child c of ct...
 80 cananian 1.5                 ClassTree c = it.next();
 81 cananian 1.1.2.1             // tweak sigma functions.
 82 cananian 1.1.2.1             Temp[][] dst = mkdst(src);
 83 cananian 1.1.2.1             if (!c.children().hasNext())
 84 cananian 1.1.2.1                 tweak(dst, 1, ts, c.edgenum);// copy into slice 1
 85 cananian 1.1.2.1             if (!it.hasNext())
 86 cananian 1.1.2.1                 tweak(dst, 0, ts, ct.edgenum);// copy into slice 0
 87 cananian 1.1.2.1             // make INSTANCEOF(c.key) then makeTest(c) else...
 88 cananian 1.1.2.1             Temp Textra = new Temp(tf);
 89 cananian 1.1.2.1             Quad q0 = new INSTANCEOF(qf, ts, Textra, ts.index(), c.key);
 90 cananian 1.1.2.1             CJMP q1 = new CJMP(qf, ts, Textra, dst, src);
 91 cananian 1.1.2.1             Quad.addEdge(head, which_succ, q0, 0);
 92 cananian 1.1.2.1             Quad.addEdge(q0, 0, q1, 0);
 93 cananian 1.1.2.1             if (dm!=null) // update derivation w/ info about Textra
 94 cananian 1.1.2.1                 dm.putType(q0, Textra, HClass.Int/*internal form of boolean*/);
 95 cananian 1.1.2.1             ptn = (TypeNode) (ptn.child[0] = new TypeNode(q1));
 96 cananian 1.1.2.1             // then...
 97 cananian 1.1.2.1             ptn.child[1] = makeTest(c, ts, q1, 1, slice(q1, 1), dm);
 98 cananian 1.1.2.1             // else...
 99 cananian 1.1.2.1             head=q1; which_succ=0; src=slice(q1, 0);
100 cananian 1.1.2.1         }
101 cananian 1.1.2.1         // link remaining else... to TYPESWITCH edge ct.edgenum
102 cananian 1.1.2.1         Edge e = ts.nextEdge(ct.edgenum);
103 cananian 1.5             Quad.addEdge(head, which_succ, e.to(), e.which_pred());
104 cananian 1.1.2.1         ptn.child[0] = new TypeLeaf(ct.edgenum);
105 cananian 1.1.2.1         // check that all sigma functions have been handled
106 cananian 1.1.2.1         if (ct.key==null && !ct.children().hasNext())
107 cananian 1.3.2.1             assert ts.numSigmas()==0;// um, 1-arity TS should not have
108 cananian 1.1.2.1                                            // sigma functions
109 cananian 1.1.2.1         // done.
110 cananian 1.1.2.1         return ftn.child[0]; // return root of TypeTree.
111 cananian 1.1.2.1     }
112 cananian 1.1.2.1     /** Copy a slice of the TYPESWITCH's sigma function to the specified
113 cananian 1.1.2.1      *  slice of the dst array. */
114 cananian 1.1.2.1     private static void tweak(Temp[][] dst, int dslice,
115 cananian 1.1.2.1                               TYPESWITCH ts, int edgenum) {
116 cananian 1.1.2.1         for (int i=0; i<dst.length; i++)
117 cananian 1.1.2.1             dst[i][dslice] = ts.dst(i, edgenum);
118 cananian 1.1.2.1     }
119 cananian 1.1.2.1     /** make a slice of the given sigma function dsts */
120 cananian 1.1.2.1     private static Temp[] slice(SIGMA s, int nTuple) {
121 cananian 1.1.2.1         Temp[] r = new Temp[s.numSigmas()];
122 cananian 1.1.2.1         for (int i=0; i<s.numSigmas(); i++)
123 cananian 1.1.2.1             r[i] = s.dst(i, nTuple);
124 cananian 1.1.2.1         return r;
125 cananian 1.1.2.1     }
126 cananian 1.1.2.1     /** clone the src array temps twice to make an appropriate dst array */
127 cananian 1.1.2.1     private static Temp[][] mkdst(Temp[] src) {
128 cananian 1.1.2.1         Temp[][] r = new Temp[src.length][2];
129 cananian 1.1.2.1         for (int i=0; i<src.length; i++)
130 cananian 1.1.2.1             for (int j=0; j<2; j++)
131 cananian 1.1.2.1                 r[i][j] = new Temp(src[i]);
132 cananian 1.1.2.1         return r;
133 cananian 1.1.2.1     }
134 cananian 1.1.2.1 
135 cananian 1.1.2.1     /** Make pruned ClassTree from cases of the TYPESWITCH */
136 cananian 1.1.2.1     private static ClassTree constructCT(TYPESWITCH ts) {
137 cananian 1.1.2.1         ClassTree root = new ClassTree(null, ts.keysLength());
138 cananian 1.1.2.1         for (int i=0; i<ts.keysLength(); i++)
139 cananian 1.1.2.1             addNode(root, new ClassTree(ts.keys(i), i));
140 cananian 1.1.2.3         // if the TYPESWITCH has no default case, fixup the ClassTree.
141 cananian 1.1.2.3         if (!ts.hasDefault()) {
142 cananian 1.5                 Iterator<ClassTree> it = root.children();
143 cananian 1.1.2.3             // must have at least one key if it has no default.
144 cananian 1.1.2.3             // make key with highest edgenum the new default.
145 cananian 1.5                 ClassTree newdefault = it.next();
146 cananian 1.1.2.3             while (it.hasNext()) {
147 cananian 1.5                     ClassTree ct = it.next();
148 cananian 1.1.2.3                 if (ct.edgenum > newdefault.edgenum)
149 cananian 1.1.2.3                     newdefault = ct;
150 cananian 1.1.2.3             }
151 cananian 1.1.2.3             // now make new root node and reparent children of newdefault
152 cananian 1.1.2.3             // and other children of root.
153 cananian 1.1.2.3             ClassTree newroot = new ClassTree(null, newdefault.edgenum);
154 cananian 1.5                 it = new CombineIterator<ClassTree>
155 cananian 1.5                     (root.children(), newdefault.children());
156 cananian 1.1.2.3             while (it.hasNext()) {
157 cananian 1.5                     ClassTree ct = it.next();
158 cananian 1.1.2.3                 it.remove();
159 cananian 1.1.2.3                 if (ct!=newdefault) newroot.addChild(ct);
160 cananian 1.1.2.3             }
161 cananian 1.1.2.3             root = newroot;
162 cananian 1.1.2.3         }
163 cananian 1.1.2.3         // okay, done.
164 cananian 1.1.2.1         return root;
165 cananian 1.1.2.1     }
166 cananian 1.1.2.1     /** Recursively descend ClassTree to find where to place this node */
167 cananian 1.1.2.1     private static void addNode(ClassTree root, ClassTree node) {
168 cananian 1.3.2.1         assert root.key==null || node.key.isInstanceOf(root.key);
169 cananian 1.3.2.1         assert !node.children().hasNext();
170 cananian 1.1.2.1         if (node.edgenum > root.edgenum) return;
171 cananian 1.1.2.1         // traverse child list. either node is a subclass of a child,
172 cananian 1.1.2.1         // or one-or-more children are subclasses of node, or neither.
173 cananian 1.1.2.1         boolean linkme=true;
174 cananian 1.5             for (Iterator<ClassTree> it=root.children(); it.hasNext(); ) {
175 cananian 1.5                 ClassTree ctp = it.next();
176 cananian 1.1.2.1             if (node.key.isInstanceOf(ctp.key)) {
177 cananian 1.1.2.1                 addNode(ctp, node);
178 cananian 1.1.2.1                 linkme=false;
179 cananian 1.1.2.1             } else if (ctp.key.isInstanceOf(node.key)) {
180 cananian 1.1.2.1                 /* unlink this node from parent */
181 cananian 1.1.2.1                 it.remove();
182 cananian 1.1.2.1                 /* now, if propitious, link to this. */
183 cananian 1.1.2.1                 if (ctp.edgenum < node.edgenum)
184 cananian 1.1.2.1                     node.addChild(ctp);
185 cananian 1.1.2.1                 continue;
186 cananian 1.1.2.1             }
187 cananian 1.1.2.1         }
188 cananian 1.1.2.1         if (linkme)
189 cananian 1.1.2.1             root.addChild(node);
190 cananian 1.1.2.1     }
191 cananian 1.1.2.1 
192 cananian 1.1.2.3     /** The class tree structure represents the class hierarchy relation
193 cananian 1.1.2.3      *  over the subset of the classes mentioned in the TYPESWITCH.
194 cananian 1.1.2.3      *  Each node also contains an edgenum which corresponds to the
195 cananian 1.1.2.3      *  key number in the TYPESWITCH which mentions this class; nodes
196 cananian 1.1.2.3      *  are pruned on insertion such that parent.edgenum &gt; child.edgenum,
197 cananian 1.1.2.3      *  which ensures that all nodes correspond to reachable cases of
198 cananian 1.1.2.3      *  the TYPESWITCH.  The root corresponds to the default case. */
199 cananian 1.1.2.1     private static class ClassTree {
200 cananian 1.1.2.1         final HClass key;
201 cananian 1.1.2.1         final int edgenum;
202 cananian 1.5             private List<ClassTree> children;
203 cananian 1.1.2.1         ClassTree(HClass key, int edgenum) {
204 cananian 1.1.2.1             this.key = key; this.edgenum = edgenum;
205 cananian 1.1.2.1             this.children = new LinkedList();
206 cananian 1.1.2.1         }
207 cananian 1.5             Iterator<ClassTree> children() { return children.iterator(); }
208 cananian 1.1.2.1         void addChild(ClassTree nchild) {
209 cananian 1.3.2.1             assert this.edgenum > nchild.edgenum;
210 cananian 1.1.2.1             children.add(nchild);
211 cananian 1.1.2.1         }           
212 cananian 1.1.2.1         // pretty-printing.
213 cananian 1.1.2.1         public String toString() { return "CT<"+key+","+edgenum+">"; }
214 cananian 1.1.2.1         public void dump(java.io.PrintWriter pw) { dump(pw, 0); pw.flush(); }
215 cananian 1.1.2.1         private void dump(java.io.PrintWriter pw, int indent) {
216 cananian 1.1.2.1             for (int i=0; i<indent; i++) pw.print("  ");
217 cananian 1.1.2.1             pw.println(toString());
218 cananian 1.5                 for (Iterator<ClassTree> it=children(); it.hasNext(); )
219 cananian 1.5                     it.next().dump(pw, indent+1);
220 cananian 1.1.2.1         }
221 cananian 1.1.2.1         public void dump(java.io.Writer w) {
222 cananian 1.1.2.1             dump(new java.io.PrintWriter(w));
223 cananian 1.1.2.1         }
224 cananian 1.1.2.1         public void dump(java.io.OutputStream os) {
225 cananian 1.1.2.1             dump(new java.io.PrintWriter(os));
226 cananian 1.1.2.1         }
227 cananian 1.1.2.1     }
228 cananian 1.1.2.1 
229 cananian 1.1.2.1     // UGH.  Lots of cruft for proper derivations. ------------
230 cananian 1.1.2.1 
231 cananian 1.1.2.1     /** The typetree keeps a record of the created CJMP structure
232 cananian 1.1.2.1      *  so that we can go back (and with fixupSigmaDerivations()) add
233 cananian 1.1.2.1      *  the proper derivation information in a post-pass. */
234 cananian 1.1.2.1     private static abstract class TypeTree {
235 cananian 1.1.2.1         /** add proper derivation information to the CJMPs described by this.*/
236 cananian 1.1.2.1         abstract TypeAndDerivation[] fixupSigmaDerivations(TYPESWITCH ts,
237 cananian 1.5                                                                DerivationMap<Quad> dm);
238 cananian 1.1.2.1     }
239 cananian 1.1.2.1     /** A TypeNode represents a CJMP, with sigmas that need derivations. */
240 cananian 1.1.2.1     private static class TypeNode extends TypeTree {
241 cananian 1.1.2.1         final CJMP cjmp;
242 cananian 1.1.2.1         final TypeTree[] child = new TypeTree[2];
243 cananian 1.1.2.1         TypeNode(CJMP cjmp) { this.cjmp = cjmp; }
244 cananian 1.1.2.1         TypeAndDerivation[] fixupSigmaDerivations(TYPESWITCH ts,
245 cananian 1.5                                                       DerivationMap<Quad> dm) {
246 cananian 1.1.2.1             TypeAndDerivation[] result=new TypeAndDerivation[ts.numSigmas()];
247 cananian 1.1.2.1             for (int i=0; i<2; i++) {
248 cananian 1.1.2.1                 TypeAndDerivation[] tad=child[i].fixupSigmaDerivations(ts,dm);
249 cananian 1.1.2.1                 for (int j=0; j<tad.length; j++) {
250 cananian 1.1.2.1                     tad[j].apply(dm, cjmp, cjmp.dst(j, i));
251 cananian 1.1.2.1                     result[j] = (result[j]==null) ? tad[j] :
252 cananian 1.1.2.1                         TypeAndDerivation.merge(result[j], tad[j]);
253 cananian 1.1.2.1                 }
254 cananian 1.1.2.1             }
255 cananian 1.1.2.1             return result;
256 cananian 1.1.2.1         }
257 cananian 1.1.2.1     }
258 cananian 1.1.2.1     /** A TypeLeaf represents an edge which corresponds to an edge of
259 cananian 1.1.2.1      *  the original TYPESWITCH -- i.e. the sigma derivations for this
260 cananian 1.1.2.1      *  edge should be identical to those on the original TYPESWITCH edge. */
261 cananian 1.1.2.1     private static class TypeLeaf extends TypeTree {
262 cananian 1.1.2.1         final int edgenum;
263 cananian 1.1.2.1         TypeLeaf(int edgenum) { this.edgenum = edgenum; }
264 cananian 1.1.2.1         TypeAndDerivation[] fixupSigmaDerivations(TYPESWITCH ts,
265 cananian 1.5                                                       DerivationMap<Quad> dm) {
266 cananian 1.1.2.1             // fetch types from appropriate slice of TYPESWITCH
267 cananian 1.1.2.1             TypeAndDerivation[] r = new TypeAndDerivation[ts.numSigmas()];
268 cananian 1.1.2.1             for (int i=0; i<r.length; i++) {
269 cananian 1.1.2.1                 r[i]=new TypeAndDerivation(dm, ts, ts.dst(i, edgenum));
270 cananian 1.1.2.1                 dm.remove(ts, ts.dst(i, edgenum)); // clean up.
271 cananian 1.1.2.1             }
272 cananian 1.1.2.1             return r;
273 cananian 1.1.2.1         }
274 cananian 1.1.2.1     }
275 cananian 1.1.2.1     /** unified type/derivation information. */
276 cananian 1.1.2.1     private static class TypeAndDerivation {
277 cananian 1.1.2.1         /** non-null for base pointers */
278 cananian 1.1.2.1         public final HClass type;
279 cananian 1.1.2.1         /** non-null for derived pointers */ 
280 cananian 1.1.2.1         public final Derivation.DList derivation;
281 cananian 1.1.2.1         // public constructors
282 cananian 1.1.2.1         TypeAndDerivation(HClass type) { this(type, null); }
283 cananian 1.1.2.1         TypeAndDerivation(Derivation.DList deriv) { this(null, deriv); }
284 cananian 1.1.2.1         // helpful.
285 cananian 1.5             <HCE extends HCodeElement> TypeAndDerivation(Derivation<HCE> d,
286 cananian 1.5                                                          HCE hce, Temp t) {
287 cananian 1.1.2.1             this(d.typeMap(hce, t), d.derivation(hce, t));
288 cananian 1.1.2.1         }
289 cananian 1.1.2.1         /** private constructor */
290 cananian 1.1.2.1         private TypeAndDerivation(HClass type, Derivation.DList derivation) {
291 cananian 1.3.2.1             assert type!=null ^ derivation!=null;
292 cananian 1.1.2.1             this.type = type;
293 cananian 1.1.2.1             this.derivation = derivation;
294 cananian 1.1.2.1         }
295 cananian 1.1.2.1         /** store this TypeAndDerivation information in the given
296 cananian 1.1.2.1          *  DerivationMap for the given HCodeElement/Temp pair. */
297 cananian 1.5             <HCE extends HCodeElement> void apply(DerivationMap<HCE> dm,
298 cananian 1.5                                                   HCE hce, Temp t) {
299 cananian 1.1.2.1             if (type!=null) dm.putType(hce, t, type);
300 cananian 1.1.2.1             else dm.putDerivation(hce, t, derivation);
301 cananian 1.1.2.1         }
302 cananian 1.1.2.1         /** Merge the given TypeAndDerivations. */
303 cananian 1.1.2.1         static TypeAndDerivation merge(TypeAndDerivation a,
304 cananian 1.1.2.1                                        TypeAndDerivation b) {
305 cananian 1.1.2.1             if (a.type!=null && b.type!=null)
306 cananian 1.1.2.1                 return new TypeAndDerivation
307 cananian 1.1.2.1                     (HClassUtil.commonParent(a.type, b.type));
308 cananian 1.1.2.1             // both ought to be derivations.
309 cananian 1.3.2.1             assert a.derivation!=null && b.derivation!=null : "can't merge type with derivation";
310 cananian 1.3.2.1             assert a.derivation.equals(b.derivation) : "can't merge derivations";
311 cananian 1.1.2.1             return a;
312 cananian 1.1.2.1         }
313 cananian 1.1.2.1     }
314 cananian 1.2     }