1 cananian 1.1.2.1 // Field2Method.java, created Sat Nov 10 20:43:46 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.SizeOpt;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.Analysis.Transformation.MethodMutator;
  7 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
  8 cananian 1.1.2.1 import harpoon.ClassFile.HClassMutator;
  9 cananian 1.1.2.1 import harpoon.ClassFile.HCode;
 10 cananian 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps;
 11 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory;
 12 cananian 1.1.2.1 import harpoon.ClassFile.HField;
 13 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
 14 cananian 1.1.2.1 import harpoon.ClassFile.HMethodMutator;
 15 cananian 1.1.2.1 import harpoon.IR.Quads.CALL;
 16 cananian 1.1.2.1 import harpoon.IR.Quads.Edge;
 17 cananian 1.1.2.1 import harpoon.IR.Quads.FOOTER;
 18 cananian 1.1.2.1 import harpoon.IR.Quads.GET;
 19 cananian 1.1.2.1 import harpoon.IR.Quads.HEADER;
 20 cananian 1.1.2.1 import harpoon.IR.Quads.METHOD;
 21 cananian 1.1.2.1 import harpoon.IR.Quads.Quad;
 22 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory;
 23 cananian 1.1.2.1 import harpoon.IR.Quads.QuadSSI;
 24 cananian 1.1.2.1 import harpoon.IR.Quads.QuadVisitor;
 25 cananian 1.1.2.1 import harpoon.IR.Quads.RETURN;
 26 cananian 1.1.2.1 import harpoon.IR.Quads.SET;
 27 cananian 1.1.2.1 import harpoon.IR.Quads.THROW;
 28 cananian 1.1.2.1 import harpoon.Temp.Temp;
 29 cananian 1.6     import net.cscott.jutil.GenericInvertibleMultiMap;
 30 cananian 1.6     import net.cscott.jutil.InvertibleMultiMap;
 31 cananian 1.6     import net.cscott.jutil.SnapshotIterator;
 32 cananian 1.1.2.1 import harpoon.Util.Util;
 33 cananian 1.1.2.1 
 34 cananian 1.1.2.1 import java.lang.reflect.Modifier;
 35 cananian 1.1.2.1 import java.util.ArrayList;
 36 cananian 1.1.2.2 import java.util.Collections;
 37 cananian 1.1.2.1 import java.util.Iterator;
 38 cananian 1.1.2.1 import java.util.List;
 39 cananian 1.1.2.1 import java.util.Map;
 40 cananian 1.1.2.1 import java.util.Set;
 41 cananian 1.1.2.1 
 42 cananian 1.1.2.1 /**
 43 cananian 1.1.2.1  * The <code>Field2Method</code> code factory converts all <code>GET</code>
 44 cananian 1.1.2.1  * and <code>SET</code> operations on a given set of fields into calls
 45 cananian 1.1.2.1  * to accessor getter/setter methods.
 46 cananian 1.1.2.1  * 
 47 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 48 cananian 1.7      * @version $Id: Field2Method.java,v 1.7 2004/02/08 03:20:22 cananian Exp $
 49 cananian 1.1.2.1  */
 50 cananian 1.1.2.1 public class Field2Method {
 51 cananian 1.1.2.1     // xxx declarations below *should* be 'invertibleMap' but the
 52 cananian 1.1.2.1     //     definitions aren't consistent yet.
 53 cananian 1.1.2.2     /** maps 'getter' methods to the field they get. MUTABLE. */
 54 cananian 1.5         private final InvertibleMultiMap<HMethod,HField> _getters =
 55 cananian 1.5             new GenericInvertibleMultiMap<HMethod,HField>();
 56 cananian 1.1.2.2     /** maps 'setter' methods to the field they set. MUTABLE. */
 57 cananian 1.5         private final InvertibleMultiMap<HMethod,HField> _setters =
 58 cananian 1.5             new GenericInvertibleMultiMap<HMethod,HField>();
 59 cananian 1.1.2.2     // these are public-visible unmodifiable versions of these.
 60 cananian 1.1.2.2     /** This maps 'getter' methods to the field they get. */
 61 cananian 1.5         public final Map<HMethod,HField> getter2field =
 62 cananian 1.5             Collections.unmodifiableMap(_getters);
 63 cananian 1.1.2.2     /** This maps 'setter' methods to the field they set. */
 64 cananian 1.5         public final Map<HMethod,HField> setter2field =
 65 cananian 1.5             Collections.unmodifiableMap(_setters);
 66 cananian 1.1.2.2     /** This maps fields to 'getter' methods. */
 67 cananian 1.5         public final Map<HField,HMethod> field2getter =
 68 cananian 1.5             Collections.unmodifiableMap(_getters.invert());
 69 cananian 1.1.2.2     /** This maps fields to 'setter' methods. */
 70 cananian 1.5         public final Map<HField,HMethod> field2setter =
 71 cananian 1.5             Collections.unmodifiableMap(_setters.invert());
 72 cananian 1.1.2.1     
 73 cananian 1.1.2.1     /** Creates a <code>Field2Method</code> code factory which converts
 74 cananian 1.1.2.1      *  all <code>GET</code> and <code>SET</code> operations on the
 75 cananian 1.1.2.1      *  fields in the <code>fields2convert</code> <code>Set</code> into
 76 cananian 1.1.2.1      *  calls to accessor getter/setter methods.  The input may be
 77 cananian 1.1.2.1      *  in Quad SSI/SSA/NoSSA/RSSx forms.  The output will be in
 78 cananian 1.1.2.1      *  Quad-SSI form. */
 79 cananian 1.5         public Field2Method(final HCodeFactory hcf, Set<HField> fields2convert) {
 80 cananian 1.1.2.1         // okay, create the appropriate new methods.
 81 cananian 1.7             for (HField hf : fields2convert) {
 82 cananian 1.1.2.1             HClass hc = hf.getDeclaringClass();
 83 cananian 1.1.2.1             String name = "$$$"+
 84 cananian 1.1.2.1                 hf.getDeclaringClass().getName()+".."+hf.getName();
 85 cananian 1.1.2.1             name = replace(name, "_", "_1");
 86 cananian 1.1.2.1             name = replace(name, ".", "_");
 87 cananian 1.1.2.1             // TYPE XXX_<classname>_get()
 88 cananian 1.1.2.1             HMethod getter = hc.getMutator().addDeclaredMethod
 89 cananian 1.1.2.1                 (name+"$get", "()"+hf.getType().getDescriptor());
 90 cananian 1.1.2.1             getter.getMutator().addModifiers(Modifier.PUBLIC);
 91 cananian 1.1.2.1             // void XXX_<classname>_set(TYPE val)
 92 cananian 1.1.2.1             HMethod setter = hc.getMutator().addDeclaredMethod
 93 cananian 1.1.2.1                 (name+"$set", "("+hf.getType().getDescriptor()+")V");
 94 cananian 1.1.2.1             setter.getMutator().addModifiers(Modifier.PUBLIC);
 95 cananian 1.1.2.1             // add these to the appropriate maps.
 96 cananian 1.1.2.2             _getters.put(getter, hf);
 97 cananian 1.1.2.2             _setters.put(setter, hf);
 98 cananian 1.1.2.1         }
 99 cananian 1.1.2.1         // Make an HCodeFactory that defines these getters and setters
100 cananian 1.1.2.1         HCodeFactory expanded = new HCodeFactory() {
101 cananian 1.1.2.1                 public HCode convert(HMethod hm) {
102 cananian 1.1.2.2                     if (getter2field.containsKey(hm))
103 cananian 1.1.2.1                         return makeGetter(hm, getCodeName());
104 cananian 1.1.2.2                     if (setter2field.containsKey(hm))
105 cananian 1.1.2.1                         return makeSetter(hm, getCodeName());
106 cananian 1.1.2.1                     return hcf.convert(hm);
107 cananian 1.1.2.1                 }
108 cananian 1.1.2.1                 public String getCodeName() { return hcf.getCodeName(); }
109 cananian 1.1.2.1                 public void clear(HMethod hm) { hcf.clear(hm); }
110 cananian 1.1.2.1             };
111 cananian 1.1.2.1         // And chain this with a MethodMutator to change the GETs and SETs
112 cananian 1.1.2.1         // to calls to the getter/setters.
113 cananian 1.1.2.1         this.hcf = new Mutator(expanded).codeFactory();
114 cananian 1.1.2.1         // done!
115 cananian 1.1.2.1     }
116 cananian 1.1.2.1     final HCodeFactory hcf;
117 cananian 1.1.2.1     public HCodeFactory codeFactory() { return hcf; }
118 cananian 1.1.2.1     /** This mutator class turns GETs and SETs into calls to accessor methods.
119 cananian 1.1.2.1      */
120 cananian 1.5         class Mutator extends MethodMutator<Quad> {
121 cananian 1.1.2.1         Mutator(HCodeFactory hcf) { super(hcf); }
122 cananian 1.1.2.1         protected String mutateCodeName(String codeName) {
123 cananian 1.1.2.1             /** XXX: do we need to turn SSI into RSSx form?
124 cananian 1.1.2.1             if (codeName.equals(QuadSSI.codename)) return QuadRSSx.codename;
125 cananian 1.1.2.1             */
126 cananian 1.1.2.1             return codeName;
127 cananian 1.1.2.1         }
128 cananian 1.5             protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) {
129 cananian 1.5                 HCode<Quad> hc = input.hcode();
130 cananian 1.1.2.1             // only mutate if this is not itself a setter/getter!
131 cananian 1.1.2.2             if (getter2field.containsKey(hc.getMethod()) ||
132 cananian 1.1.2.2                 setter2field.containsKey(hc.getMethod())) return hc; // bail!
133 cananian 1.1.2.1             // List of THROWs which need to be added to the FOOTER.
134 cananian 1.5                 final List<THROW> fixup = new ArrayList<THROW>();
135 cananian 1.1.2.1             // visitor class to effect the transformation.
136 cananian 1.1.2.1             QuadVisitor qv = new QuadVisitor() {
137 cananian 1.1.2.1                     public void visit(Quad q) {/* do nothing for most quads */}
138 cananian 1.1.2.1                     public void visit(GET q) {
139 cananian 1.1.2.1                         if (!field2getter.containsKey(q.field())) return;
140 cananian 1.3.2.1                         assert !q.field().isStatic();
141 cananian 1.1.2.1                         Temp retex = new Temp(q.getFactory().tempFactory());
142 cananian 1.5                             CALL call = new CALL(q.getFactory(), q,
143 cananian 1.1.2.1                                              field2getter.get(q.field()),
144 cananian 1.1.2.1                                              new Temp[] { q.objectref() },
145 cananian 1.1.2.1                                              q.dst(), retex,
146 cananian 1.1.2.1                                              true/* is virtual */,
147 cananian 1.1.2.1                                              false/* not a tailCall */,
148 cananian 1.1.2.1                                              new Temp[0]);
149 cananian 1.1.2.1                         replace(q, call);
150 cananian 1.1.2.1                     }
151 cananian 1.1.2.1                     public void visit(SET q) {
152 cananian 1.1.2.1                         if (!field2setter.containsKey(q.field())) return;
153 cananian 1.3.2.1                         assert !q.field().isStatic();
154 cananian 1.1.2.1                         Temp retex = new Temp(q.getFactory().tempFactory());
155 cananian 1.5                             CALL call = new CALL(q.getFactory(), q,
156 cananian 1.1.2.1                                              field2setter.get(q.field()),
157 cananian 1.1.2.1                                              new Temp[]{q.objectref(),q.src()},
158 cananian 1.1.2.1                                              null, retex,
159 cananian 1.1.2.1                                              true/* is virtual */,
160 cananian 1.1.2.1                                              false/* not a tailCall */,
161 cananian 1.1.2.1                                              new Temp[0]);
162 cananian 1.1.2.1                         replace(q, call);
163 cananian 1.1.2.1                     }
164 cananian 1.1.2.1                     /** replace q with CALL, make THROW, add to fixup list. */
165 cananian 1.1.2.1                     private void replace(Quad q, CALL call) {
166 cananian 1.3.2.1                         assert q.prevLength()==1 && q.nextLength()==1;
167 cananian 1.1.2.1                         Edge in = q.prevEdge(0), out = q.nextEdge(0);
168 cananian 1.5                             Quad.addEdge(in.from(), in.which_succ(), call, 0);
169 cananian 1.5                             Quad.addEdge(call,0, out.to(), out.which_pred());
170 cananian 1.1.2.1                         THROW thr = new THROW(call.getFactory(), call, 
171 cananian 1.1.2.1                                               call.retex());
172 cananian 1.1.2.1                         Quad.addEdge(call, 1, thr, 0);
173 cananian 1.1.2.1                         fixup.add(thr);
174 cananian 1.1.2.1                     }
175 cananian 1.1.2.1                 };
176 cananian 1.1.2.1             // use the visitor to replace them boys!
177 cananian 1.5                 for (Iterator<Quad> it=new SnapshotIterator<Quad>
178 cananian 1.5                          (hc.getElementsI()); it.hasNext(); )
179 cananian 1.5                     it.next().accept(qv);
180 cananian 1.1.2.1             // fixup throws by adding to footer.
181 cananian 1.1.2.1             if (fixup.size()>0) {
182 cananian 1.1.2.1                 FOOTER oldF = (FOOTER) ((HEADER)hc.getRootElement()).next(0);
183 cananian 1.1.2.1                 FOOTER newF = oldF.resize(oldF.arity()+fixup.size());
184 cananian 1.1.2.1                 int n = newF.arity();
185 cananian 1.7                     for (THROW thr : fixup) {
186 cananian 1.1.2.1                     Quad.addEdge(thr, 0, newF, --n);
187 cananian 1.1.2.1                 }
188 cananian 1.1.2.1             }
189 cananian 1.1.2.1             // presto, done!
190 cananian 1.1.2.1             return hc;
191 cananian 1.1.2.1         }
192 cananian 1.1.2.1     }
193 cananian 1.1.2.1     /** Make a getter method. */
194 cananian 1.5         HCode<Quad> makeGetter(HMethod hm, String codename) {
195 cananian 1.5             HField hf = getter2field.get(hm);
196 cananian 1.1.2.1         MyCode hc = new MyCode(hm, codename);
197 cananian 1.1.2.1         // make quads.
198 cananian 1.1.2.1         QuadFactory qf = hc.getQF();
199 cananian 1.1.2.1         Temp thisT = new Temp(qf.tempFactory(), "this");
200 cananian 1.1.2.1         Temp retvT = new Temp(qf.tempFactory(), "retval");
201 cananian 1.1.2.1         Quad qH = new HEADER(qf, null);
202 cananian 1.1.2.1         Quad q1 = new METHOD(qf, null, new Temp[] { thisT }, 1);
203 cananian 1.1.2.1         Quad q2 = new GET(qf, null, retvT, hf, thisT);
204 cananian 1.1.2.1         Quad q3 = new RETURN(qf, null, retvT);
205 cananian 1.1.2.1         Quad qF = new FOOTER(qf, null, 2);
206 cananian 1.1.2.1         Quad.addEdge(qH, 0, qF, 0);
207 cananian 1.1.2.1         Quad.addEdge(qH, 1, q1, 0);
208 cananian 1.1.2.1         Quad.addEdges(new Quad[] { q1, q2, q3 });
209 cananian 1.1.2.1         Quad.addEdge(q3, 0, qF, 1);
210 cananian 1.1.2.1         // put these quads into hc.
211 cananian 1.1.2.1         hc.setRoot(qH);
212 cananian 1.1.2.1         // done!
213 cananian 1.1.2.1         return hc;
214 cananian 1.1.2.1     }
215 cananian 1.1.2.1     /** Make a setter method. */
216 cananian 1.5         HCode<Quad> makeSetter(HMethod hm, String codename) {
217 cananian 1.5             HField hf = setter2field.get(hm);
218 cananian 1.1.2.1         MyCode hc = new MyCode(hm, codename);
219 cananian 1.1.2.1         // make quads.
220 cananian 1.1.2.1         QuadFactory qf = hc.getQF();
221 cananian 1.1.2.1         Temp thisT = new Temp(qf.tempFactory(), "this");
222 cananian 1.1.2.1         Temp newvT = new Temp(qf.tempFactory(), "value");
223 cananian 1.1.2.1         Quad qH = new HEADER(qf, null);
224 cananian 1.1.2.1         Quad q1 = new METHOD(qf, null, new Temp[] { thisT, newvT }, 1);
225 cananian 1.1.2.1         Quad q2 = new SET(qf, null, hf, thisT, newvT);
226 cananian 1.1.2.1         Quad q3 = new RETURN(qf, null, null);
227 cananian 1.1.2.1         Quad qF = new FOOTER(qf, null, 2);
228 cananian 1.1.2.1         Quad.addEdge(qH, 0, qF, 0);
229 cananian 1.1.2.1         Quad.addEdge(qH, 1, q1, 0);
230 cananian 1.1.2.1         Quad.addEdges(new Quad[] { q1, q2, q3 });
231 cananian 1.1.2.1         Quad.addEdge(q3, 0, qF, 1);
232 cananian 1.1.2.1         // put these quads into hc.
233 cananian 1.1.2.1         hc.setRoot(qH);
234 cananian 1.1.2.1         // done!
235 cananian 1.1.2.1         return hc;
236 cananian 1.1.2.1     }
237 cananian 1.1.2.1     class MyCode extends harpoon.IR.Quads.QuadSSI {
238 cananian 1.1.2.1         final String codename;
239 cananian 1.1.2.1         MyCode(HMethod hm, String codename) {
240 cananian 1.1.2.1             super(hm, null);
241 cananian 1.1.2.1             this.codename=codename;
242 cananian 1.1.2.1         }
243 cananian 1.1.2.1         // Field2Method-private accessors.
244 cananian 1.1.2.1         void setRoot(Quad root) { this.quads = root; }
245 cananian 1.1.2.1         QuadFactory getQF() { return this.qf; }
246 cananian 1.1.2.1         // implementation of Code abstract methods.
247 cananian 1.1.2.1         public String getName() { return codename; }
248 cananian 1.5             public HCodeAndMaps<Quad> clone(HMethod newMethod) {
249 cananian 1.1.2.1             return cloneHelper(new MyCode(newMethod, codename));
250 cananian 1.1.2.1         }
251 cananian 1.1.2.1     }
252 cananian 1.1.2.1     /** helper method to replace occurences of 'oldstr' in 's' with 'newstr'.*/
253 cananian 1.1.2.1     private static String replace(String s, String oldstr, String newstr) {
254 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
255 cananian 1.1.2.1         while (true) {
256 cananian 1.1.2.1             // find oldstr
257 cananian 1.1.2.1             int idx = s.indexOf(oldstr);
258 cananian 1.1.2.1             // if not found, then done.
259 cananian 1.1.2.1             if (idx<0) break;
260 cananian 1.1.2.1             // split at idx
261 cananian 1.1.2.1             sb.append(s.substring(0, idx));
262 cananian 1.1.2.1             s = s.substring(idx+oldstr.length());
263 cananian 1.1.2.1             // add newstr.
264 cananian 1.1.2.1             sb.append(newstr);
265 cananian 1.1.2.1         }
266 cananian 1.1.2.1         sb.append(s);
267 cananian 1.1.2.1         return sb.toString();
268 cananian 1.1.2.1     }
269 cananian 1.2     }