1 cananian 1.1.2.1 // NewMover.java, created Wed Nov  7 22:20:28 2001 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.4 import harpoon.Analysis.Transformation.MethodMutator;
  7 cananian 1.1.2.4 import harpoon.ClassFile.CachingCodeFactory;
  8 cananian 1.1.2.4 import harpoon.ClassFile.HCode;
  9 cananian 1.1.2.4 import harpoon.ClassFile.HCodeAndMaps;
 10 cananian 1.1.2.4 import harpoon.ClassFile.HCodeFactory;
 11 cananian 1.1.2.4 import harpoon.IR.Quads.CALL;
 12 cananian 1.1.2.4 import harpoon.IR.Quads.Edge;
 13 cananian 1.1.2.4 import harpoon.IR.Quads.FOOTER;
 14 cananian 1.1.2.4 import harpoon.IR.Quads.HEADER;
 15 cananian 1.1.2.4 import harpoon.IR.Quads.METHOD;
 16 cananian 1.1.2.4 import harpoon.IR.Quads.MOVE;
 17 cananian 1.1.2.4 import harpoon.IR.Quads.NEW;
 18 cananian 1.1.2.4 import harpoon.IR.Quads.PHI;
 19 cananian 1.1.2.4 import harpoon.IR.Quads.Quad;
 20 cananian 1.1.2.4 import harpoon.IR.Quads.QuadVisitor;
 21 cananian 1.1.2.4 import harpoon.IR.Quads.SIGMA;
 22 cananian 1.1.2.4 import harpoon.Temp.Temp;
 23 cananian 1.6     import net.cscott.jutil.GenericInvertibleMultiMap;
 24 cananian 1.6     import net.cscott.jutil.InvertibleMultiMap;
 25 cananian 1.6     import net.cscott.jutil.CombineIterator;
 26 cananian 1.1.2.4 import harpoon.Util.Util;
 27 cananian 1.1.2.1 
 28 cananian 1.1.2.4 import java.util.Collection;
 29 cananian 1.1.2.4 import java.util.HashMap;
 30 cananian 1.1.2.4 import java.util.HashSet;
 31 cananian 1.1.2.4 import java.util.Iterator;
 32 cananian 1.1.2.4 import java.util.Map;
 33 cananian 1.1.2.4 import java.util.Set;
 34 cananian 1.1.2.1 /**
 35 cananian 1.1.2.1  * The <code>NewMover</code> class moves <code>NEW</code> operations
 36 cananian 1.1.2.1  * as close as possible to the <code>CALL</code> to their initializers.
 37 cananian 1.1.2.1  * In java bytecode, these two operations can be arbitrarily far apart
 38 cananian 1.1.2.1  * in expressions such as:
 39 cananian 1.1.2.1  * <ul><li><code>new Foo(new Bar(blah(), 2+5, ...), ...)</code></li></ul>
 40 cananian 1.1.2.1  * <p>
 41 cananian 1.1.2.1  * This movement is illegal if a <code>OutOfMemoryException</code> may
 42 cananian 1.1.2.1  * ever be thrown, as moving the <code>NEW</code> changes where the
 43 cananian 1.1.2.1  * exception would be thrown.  However, FLEX operates under the assumption
 44 cananian 1.1.2.1  * that such exceptions are never thrown.
 45 cananian 1.1.2.1  * <p>
 46 cananian 1.1.2.1  * <code>NewMover</code> works best on <code>QuadWithTry</code> form.
 47 cananian 1.1.2.1  * 
 48 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 49 cananian 1.7      * @version $Id: NewMover.java,v 1.7 2004/02/08 03:20:10 cananian Exp $
 50 cananian 1.1.2.1  */
 51 cananian 1.1.2.1 public class NewMover extends MethodMutator {
 52 cananian 1.1.2.4     /** If true, then the NewMover will attempt to move NEWs across SIGMAs.
 53 cananian 1.1.2.4      *  This yields better results when applied to QuadNoSSA form, but
 54 cananian 1.1.2.4      *  increases code size w/ no appreciable benefit on QuadWithTry form. */
 55 cananian 1.1.2.5     private static final boolean movePastSigmas=false;
 56 cananian 1.1.2.1     /** Creates a <code>NewMover</code> that uses the given
 57 cananian 1.1.2.1      *  <code>HCodeFactory</code> <code>hcf</code>. */
 58 cananian 1.1.2.1     public NewMover(HCodeFactory hcf) {
 59 cananian 1.1.2.1         super(new CachingCodeFactory(/*QuadWithTry.codeFactory*/(hcf)));
 60 cananian 1.1.2.1     }
 61 cananian 1.1.2.1     protected HCode mutateHCode(HCodeAndMaps input) {
 62 cananian 1.1.2.1         HCode hc = input.hcode();
 63 cananian 1.1.2.1         HEADER header = (HEADER) hc.getRootElement();
 64 cananian 1.1.2.3         METHOD method = (METHOD) header.next(1);
 65 cananian 1.1.2.3         // traverse all edges from method (handler blocks and regular code)
 66 cananian 1.1.2.3         MoveVisitor mv = new MoveVisitor();
 67 cananian 1.1.2.3         for (int i=0; i<method.nextLength(); i++) {
 68 cananian 1.1.2.3             mv.state = new State();
 69 cananian 1.1.2.3             traverseBlock(mv, method.nextEdge(i));
 70 cananian 1.1.2.3         }
 71 cananian 1.1.2.3         // done!
 72 cananian 1.1.2.1         return hc;
 73 cananian 1.1.2.1     }
 74 cananian 1.1.2.1     // recursive traversal of all paths.
 75 cananian 1.1.2.1     void traverseBlock(MoveVisitor mv, Edge in) {
 76 cananian 1.1.2.1         mv.from = in;
 77 cananian 1.1.2.1         mv.done = false;
 78 cananian 1.1.2.1         while (!mv.done)
 79 cananian 1.1.2.1             ((Quad)mv.from.to()).accept(mv);
 80 cananian 1.1.2.1         // okay, recursively invoke on the one that stopped us.
 81 cananian 1.1.2.1         Quad stopper = (Quad) mv.from.to();
 82 cananian 1.1.2.1         if (stopper instanceof FOOTER) return; // end-of-the-line!
 83 cananian 1.1.2.4         if (mv.seen.add(stopper)) {
 84 cananian 1.1.2.4             // haven't started with this one before, so do it!
 85 cananian 1.1.2.4             State s = mv.state;
 86 cananian 1.1.2.4             for (int i=0; i<stopper.nextLength(); i++) {
 87 cananian 1.1.2.4                 mv.state = (i<stopper.nextLength()-1) ? new State(s) : s;
 88 cananian 1.1.2.1                 traverseBlock(mv, stopper.nextEdge(i));
 89 cananian 1.1.2.4             }
 90 cananian 1.3.2.1         } else assert stopper instanceof PHI;
 91 cananian 1.1.2.1     }
 92 cananian 1.1.2.2     static class State {
 93 cananian 1.1.2.2         /** Set of NEWs we are moving, maintained as a map from dst->NEW. */
 94 cananian 1.1.2.2         final Map moving;
 95 cananian 1.1.2.2         /** MultiMap of aliases for a given Temp (defined by a NEW) */
 96 cananian 1.1.2.2         final InvertibleMultiMap aliases;
 97 cananian 1.1.2.2         State() {
 98 cananian 1.1.2.2             this.moving=new HashMap();
 99 cananian 1.1.2.2             this.aliases=new GenericInvertibleMultiMap();
100 cananian 1.1.2.2         }
101 cananian 1.1.2.2         State(State s) {
102 cananian 1.1.2.4             this.moving=new HashMap();
103 cananian 1.1.2.2             this.aliases=new GenericInvertibleMultiMap(s.aliases);
104 cananian 1.1.2.4             // copy/clone mappings from s.moving.
105 cananian 1.7                 for (Object oldQO : s.moving.values()) {
106 cananian 1.7                     NEW oldQ = (NEW) oldQO;
107 cananian 1.1.2.4                 NEW newQ = (NEW) oldQ.clone();
108 cananian 1.1.2.4                 newQ.addHandlers(oldQ.handlers());
109 cananian 1.1.2.4                 this.moving.put(newQ.dst(), newQ);
110 cananian 1.1.2.4             }
111 cananian 1.1.2.2         }
112 cananian 1.6             public State clone() { return new State(this); }
113 cananian 1.1.2.4         public String toString() { return moving+" / "+aliases; }
114 cananian 1.1.2.2     }
115 cananian 1.1.2.1     class MoveVisitor extends QuadVisitor {
116 cananian 1.1.2.1         Edge from; boolean done;
117 cananian 1.1.2.2         State state = new State();
118 cananian 1.1.2.1         Set seen = new HashSet();
119 cananian 1.1.2.1         public void visit(Quad q) {
120 cananian 1.5                 // if this quad uses or redefines any NEWs which are in 'moving',
121 cananian 1.1.2.2             // (or any temps which are in aliases.values())
122 cananian 1.1.2.2             // drop them before here. (MOVEs to aliases follow NEWs)
123 cananian 1.3.2.1             assert q.prevLength()==1;
124 cananian 1.1.2.1             Edge e = q.prevEdge(0);
125 cananian 1.5                 for (Iterator it=new CombineIterator
126 cananian 1.5                          (q.useC().iterator(), q.defC().iterator());
127 cananian 1.5                      it.hasNext(); ) {
128 cananian 1.1.2.1                 Temp t = (Temp) it.next();
129 cananian 1.1.2.2                 if (!state.aliases.values().contains(t)) continue; //boring.
130 cananian 1.1.2.2                 // unmap alias to canonical temp (defined by NEW)
131 cananian 1.1.2.2                 Temp src = (Temp) state.aliases.invert().get(t);
132 cananian 1.3.2.1                 assert state.aliases.invert().getValues(t).size()==1;
133 cananian 1.1.2.2                 // dump it!
134 cananian 1.1.2.2                 e = dumpOne(e, src);
135 cananian 1.1.2.2                 state.moving.remove(src);
136 cananian 1.1.2.2                 state.aliases.remove(src);
137 cananian 1.1.2.1             }
138 cananian 1.1.2.1             // done.
139 cananian 1.3.2.1             assert q.nextLength()==1;
140 cananian 1.1.2.1             from = q.nextEdge(0);
141 cananian 1.1.2.1         }
142 cananian 1.1.2.1         public void visit(NEW q) {
143 cananian 1.1.2.1             // pick this guy up
144 cananian 1.1.2.1             Edge in = q.prevEdge(0), out = q.nextEdge(0);
145 cananian 1.1.2.1             from = Quad.addEdge((Quad)in.from(), in.which_succ(),
146 cananian 1.1.2.1                                 (Quad)out.to(), out.which_pred());
147 cananian 1.1.2.1             // note that q is still in handler sets, which is what we want.
148 cananian 1.1.2.2             state.moving.put(q.dst(), q);
149 cananian 1.1.2.2             state.aliases.add(q.dst(), q.dst()); // always alias to itself.
150 cananian 1.1.2.1         }
151 cananian 1.1.2.1         public void visit(MOVE q) {
152 cananian 1.1.2.1             // if this MOVE uses the result of a NEW which we're moving,
153 cananian 1.1.2.1             // pick it up, too.
154 cananian 1.1.2.2             if (state.aliases.values().contains(q.src())) {
155 cananian 1.1.2.2                 // get 'real' source (filter through inverted aliasMap)
156 cananian 1.1.2.2                 Temp src = (Temp) state.aliases.invert().get(q.src());
157 cananian 1.1.2.2                 // add a new alias.
158 cananian 1.1.2.2                 state.aliases.add(src, q.dst());
159 cananian 1.1.2.2                 // remove this guy.
160 cananian 1.1.2.2                 from = q.remove();
161 cananian 1.1.2.1             } else visit((Quad) q); // fallback to boring.
162 cananian 1.1.2.1         }
163 cananian 1.1.2.2         Edge dumpOne(Edge e, Temp t) {
164 cananian 1.3.2.1             assert state.moving.containsKey(t);
165 cananian 1.1.2.2             // first dump the NEW
166 cananian 1.1.2.2             NEW qN = (NEW) state.moving.get(t);
167 cananian 1.1.2.2             e = addAt(e, qN);
168 cananian 1.1.2.2             // then dump all associated MOVEs.
169 cananian 1.3.2.1             Temp src = qN.dst(); assert t.equals(src);
170 cananian 1.7                 for (Object dstO : state.aliases.getValues(src)) {
171 cananian 1.7                     Temp dst = (Temp) dstO;
172 cananian 1.1.2.2                 if (src.equals(dst)) continue;
173 cananian 1.1.2.2                 // no handler for the MOVE, but we don't care.
174 cananian 1.1.2.2                 e = addAt(e, new MOVE(qN.getFactory(), qN, dst, src));
175 cananian 1.1.2.2             }
176 cananian 1.1.2.2             // done!
177 cananian 1.1.2.2             return e;
178 cananian 1.1.2.2         }
179 cananian 1.1.2.1         void visitPhiSigma(Quad q) {
180 cananian 1.1.2.1             // stop here, dump all moving MOVEs and NEWs on 'from'
181 cananian 1.1.2.1             Edge e = from;
182 cananian 1.1.2.2             for (Iterator it=state.moving.keySet().iterator(); it.hasNext(); )
183 cananian 1.1.2.2                 e = dumpOne(e, (Temp)it.next());
184 cananian 1.1.2.2             state.moving.clear();
185 cananian 1.1.2.2             state.aliases.clear();
186 cananian 1.1.2.1         }
187 cananian 1.1.2.1         public void visit(PHI q) {
188 cananian 1.1.2.1             visitPhiSigma(q);
189 cananian 1.1.2.1             if (seen.add(q))
190 cananian 1.1.2.1                 // not seen before.  keep going with next edge.
191 cananian 1.1.2.1                 from = q.nextEdge(0);
192 cananian 1.1.2.1             else
193 cananian 1.1.2.1                 // seen before.  we're done with this.
194 cananian 1.1.2.1                 done = true;
195 cananian 1.1.2.1         }
196 cananian 1.1.2.1         public void visit(SIGMA q) {
197 cananian 1.1.2.4             // keep state, but bail out of the iteration to recurse.
198 cananian 1.1.2.4             if (!movePastSigmas)
199 cananian 1.1.2.4                 visitPhiSigma(q); // don't push past sigmas.
200 cananian 1.1.2.4             else { // check for vars used by sigma.
201 cananian 1.1.2.4                 Edge e = from;
202 cananian 1.7                     for (Object tO : q.useC()) {
203 cananian 1.7                         Temp t = (Temp) tO;
204 cananian 1.1.2.4                     if (!state.aliases.values().contains(t)) continue;//boring.
205 cananian 1.1.2.4                     // unmap alias to canonical temp (defined by NEW)
206 cananian 1.1.2.4                     Temp src = (Temp) state.aliases.invert().get(t);
207 cananian 1.3.2.1                     assert state.aliases.invert().getValues(t).size()==1;
208 cananian 1.1.2.4                     // dump it!
209 cananian 1.1.2.4                     e = dumpOne(e, src);
210 cananian 1.1.2.4                     state.moving.remove(src);
211 cananian 1.1.2.4                     state.aliases.remove(src);
212 cananian 1.1.2.4                 }
213 cananian 1.1.2.4             }
214 cananian 1.1.2.4             from = q.prevEdge(0);
215 cananian 1.1.2.1             done = true;
216 cananian 1.1.2.1         }
217 cananian 1.1.2.1         public void visit(CALL q) {
218 cananian 1.1.2.1             // calls aren't really sigmas in quad-with-try form.
219 cananian 1.1.2.1             if (q.retex()==null)
220 cananian 1.1.2.1                 visit((Quad)q); // an ordinary joe.
221 cananian 1.1.2.1             else
222 cananian 1.1.2.1                 visit((SIGMA)q); // a sigma!
223 cananian 1.1.2.1         }
224 cananian 1.1.2.1         public void visit(FOOTER q) {
225 cananian 1.1.2.1             // if we haven't used the MOVE/NEW by now, discard it.
226 cananian 1.7                 for (Object qNO : state.moving.values()){
227 cananian 1.7                     NEW qN = (NEW) qNO;
228 cananian 1.1.2.4                 // remove the NEW from any handler sets, too.
229 cananian 1.1.2.4                 qN.removeHandlers(qN.handlers());
230 cananian 1.1.2.4             }
231 cananian 1.1.2.2             state.moving.clear();
232 cananian 1.1.2.2             state.aliases.clear();
233 cananian 1.1.2.1             done=true;
234 cananian 1.1.2.1         }
235 cananian 1.1.2.1     }
236 cananian 1.1.2.1     // private helper functions.
237 cananian 1.1.2.1     private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); }
238 cananian 1.1.2.1     private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) {
239 cananian 1.1.2.1         Quad frm = (Quad) e.from(); int frm_succ = e.which_succ();
240 cananian 1.1.2.1         Quad to  = (Quad) e.to();   int to_pred = e.which_pred();
241 cananian 1.1.2.1         Quad.addEdge(frm, frm_succ, q, which_pred);
242 cananian 1.1.2.1         Quad.addEdge(q, which_succ, to, to_pred);
243 cananian 1.1.2.1         return to.prevEdge(to_pred);
244 cananian 1.1.2.1     }
245 cananian 1.1.2.1     private static Edge addReversedAt(Edge e, Quad q) {
246 cananian 1.1.2.1         return addReversedAt(e, 0, q, 0);
247 cananian 1.1.2.1     }
248 cananian 1.1.2.1     private static Edge addReversedAt(Edge e,
249 cananian 1.1.2.1                                       int which_pred, Quad q, int which_succ) {
250 cananian 1.1.2.1         Quad frm = (Quad) e.from(); int frm_succ = e.which_succ();
251 cananian 1.1.2.1         Quad to  = (Quad) e.to();   int to_pred = e.which_pred();
252 cananian 1.1.2.1         Quad.addEdge(frm, frm_succ, q, which_pred);
253 cananian 1.1.2.1         Quad.addEdge(q, which_succ, to, to_pred);
254 cananian 1.1.2.1         return frm.nextEdge(frm_succ);
255 cananian 1.1.2.1     }
256 cananian 1.2     }