1 cananian 1.1.2.1 // MZFExternalize.java, created Tue Nov 13 23:07:42 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.ClassFile.CachingCodeFactory;
  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.HCodeFactory;
 10 cananian 1.1.2.1 import harpoon.ClassFile.HField;
 11 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
 12 cananian 1.1.2.1 import harpoon.ClassFile.Linker;
 13 cananian 1.1.2.1 import harpoon.IR.Quads.CALL;
 14 cananian 1.1.2.1 import harpoon.IR.Quads.CJMP;
 15 cananian 1.1.2.1 import harpoon.IR.Quads.CONST;
 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.INSTANCEOF;
 21 cananian 1.1.2.2 import harpoon.IR.Quads.OPER;
 22 cananian 1.1.2.2 import harpoon.IR.Quads.PHI;
 23 cananian 1.1.2.2 import harpoon.IR.Quads.Qop;
 24 cananian 1.1.2.1 import harpoon.IR.Quads.Quad;
 25 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory;
 26 cananian 1.1.2.2 import harpoon.IR.Quads.QuadRSSx;
 27 cananian 1.1.2.1 import harpoon.IR.Quads.SET;
 28 cananian 1.1.2.1 import harpoon.IR.Quads.THROW;
 29 cananian 1.1.2.1 import harpoon.Temp.Temp;
 30 cananian 1.7     import net.cscott.jutil.SnapshotIterator;
 31 cananian 1.1.2.1 import harpoon.Util.Util;
 32 cananian 1.1.2.1 
 33 cananian 1.1.2.1 import java.util.HashMap;
 34 cananian 1.1.2.1 import java.util.Iterator;
 35 cananian 1.1.2.1 import java.util.List;
 36 cananian 1.1.2.1 import java.util.Map;
 37 cananian 1.1.2.1 import java.util.Set;
 38 cananian 1.1.2.1 /**
 39 cananian 1.1.2.1  * The <code>MZFExternalize</code> class takes fields which aren't
 40 cananian 1.1.2.1  * 'sub-class final' but *are* sufficiently mostly-zero (according to
 41 cananian 1.1.2.1  * profile information) and turns then into references into an
 42 cananian 1.1.2.1  * external weak hash map.  This saves the memory which the field
 43 cananian 1.1.2.1  * occupies for all the mostly-zero fields, at the expense of requiring
 44 cananian 1.1.2.1  * about twice-the-usual memory for non-zero fields.  If the fields
 45 cananian 1.1.2.1  * really *are* mostly-zero, then the net will be a space savings.
 46 cananian 1.1.2.1  * 
 47 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 48 cananian 1.8      * @version $Id: MZFExternalize.java,v 1.8 2004/02/08 03:20:22 cananian Exp $
 49 cananian 1.1.2.1  */
 50 cananian 1.1.2.1 class MZFExternalize {
 51 cananian 1.1.2.3     public static final double THRESHOLD =
 52 cananian 1.1.2.3         Double.parseDouble(System.getProperty("harpoon.sizeopt.mzf.threshold",
 53 cananian 1.1.2.3                                               "75.0"/*default*/));
 54 cananian 1.1.2.1     final HCodeFactory hcf;
 55 cananian 1.1.2.1     final Linker linker;
 56 cananian 1.1.2.1     final private HMethod intGET, intSET, longGET, longSET;
 57 cananian 1.1.2.1     final private HMethod floatGET, floatSET, doubleGET, doubleSET;
 58 cananian 1.1.2.1     final private HMethod ptrGET, ptrSET;
 59 cananian 1.1.2.1     
 60 cananian 1.1.2.1     /** Creates a <code>MZFExternalize</code>. */
 61 cananian 1.1.2.1     MZFExternalize(HCodeFactory hcf, Linker linker, ProfileParser pp,
 62 cananian 1.5                        Set<HClass> stoplist, Set<HField> doneFields) {
 63 cananian 1.1.2.1         //first initialize the HMethods which define the external map interface
 64 cananian 1.1.2.1         this.linker = linker;
 65 cananian 1.1.2.1         HClass HCexmap = linker.forClass(harpoon.Runtime.MZFExternalMap.class);
 66 cananian 1.1.2.1         this.intGET = HCexmap.getDeclaredMethod
 67 cananian 1.1.2.1             ("intGET", "(Ljava/lang/Object;Ljava/lang/Object;I)I");
 68 cananian 1.1.2.1         this.intSET = HCexmap.getDeclaredMethod
 69 cananian 1.1.2.1             ("intSET", "(Ljava/lang/Object;Ljava/lang/Object;II)V");
 70 cananian 1.1.2.1         this.longGET = HCexmap.getDeclaredMethod
 71 cananian 1.1.2.1             ("longGET", "(Ljava/lang/Object;Ljava/lang/Object;J)J");
 72 cananian 1.1.2.1         this.longSET = HCexmap.getDeclaredMethod
 73 cananian 1.1.2.1             ("longSET", "(Ljava/lang/Object;Ljava/lang/Object;JJ)V");
 74 cananian 1.1.2.1         this.floatGET = HCexmap.getDeclaredMethod
 75 cananian 1.1.2.1             ("floatGET", "(Ljava/lang/Object;Ljava/lang/Object;F)F");
 76 cananian 1.1.2.1         this.floatSET = HCexmap.getDeclaredMethod
 77 cananian 1.1.2.1             ("floatSET", "(Ljava/lang/Object;Ljava/lang/Object;FF)V");
 78 cananian 1.1.2.1         this.doubleGET = HCexmap.getDeclaredMethod
 79 cananian 1.1.2.1             ("doubleGET", "(Ljava/lang/Object;Ljava/lang/Object;D)D");
 80 cananian 1.1.2.1         this.doubleSET = HCexmap.getDeclaredMethod
 81 cananian 1.1.2.1             ("doubleSET", "(Ljava/lang/Object;Ljava/lang/Object;DD)V");
 82 cananian 1.1.2.1         this.ptrGET = HCexmap.getDeclaredMethod
 83 cananian 1.1.2.1             ("ptrGET", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
 84 cananian 1.1.2.1         this.ptrSET = HCexmap.getDeclaredMethod
 85 cananian 1.1.2.1             ("ptrSET", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
 86 cananian 1.1.2.1         // okay, not collect a list of fields which we want to transform.
 87 cananian 1.5             Map<HField,Number> myfields = new HashMap<HField,Number>();
 88 cananian 1.8             for (Object pairO : pp.fieldsAboveThresh(THRESHOLD)) {
 89 cananian 1.8                 List pair = (List) pairO;
 90 cananian 1.1.2.1             HField hf = (HField) pair.get(0);
 91 cananian 1.1.2.1             Number mostly = (Number) pair.get(1);
 92 cananian 1.1.2.1             if (stoplist.contains(hf.getDeclaringClass())) continue;
 93 cananian 1.1.2.1             if (doneFields.contains(hf)) continue;
 94 cananian 1.1.2.1             // okay, this is one we want to do.
 95 cananian 1.1.2.1             myfields.put(hf, mostly);
 96 cananian 1.1.2.1         }
 97 cananian 1.1.2.1         System.out.println("EXTERNALIZING: "+myfields);
 98 cananian 1.1.2.1         // turn these fields into accessors.
 99 cananian 1.1.2.1         Field2Method f2m = new Field2Method(hcf, myfields.keySet());
100 cananian 1.1.2.1         hcf = f2m.codeFactory();
101 cananian 1.1.2.1         // except now we implement the getters/setters ourselves.
102 cananian 1.1.2.1         hcf = new CachingCodeFactory(hcf);
103 cananian 1.8             for (HField hf : myfields.keySet()){
104 cananian 1.5                 HMethod getter = f2m.field2getter.get(hf);
105 cananian 1.5                 HMethod setter = f2m.field2setter.get(hf);
106 cananian 1.5                 Number mostly = myfields.get(hf);
107 cananian 1.1.2.1             ((CachingCodeFactory)hcf).put
108 cananian 1.1.2.1                 (getter, makeGetter(hcf, getter, hf, mostly));
109 cananian 1.1.2.1             ((CachingCodeFactory)hcf).put
110 cananian 1.1.2.1                 (setter, makeSetter(hcf, setter, hf, mostly));
111 cananian 1.1.2.1         }
112 cananian 1.1.2.1         // okay, it should now be safe to go ahead and remove those fields.
113 cananian 1.8             for (HField hf : myfields.keySet()){
114 cananian 1.1.2.1             hf.getDeclaringClass().getMutator().removeDeclaredField(hf);//ta-da
115 cananian 1.1.2.1         }
116 cananian 1.1.2.1         // set the externally-visible code factory.
117 cananian 1.1.2.1         this.hcf = hcf;
118 cananian 1.1.2.1     }
119 cananian 1.1.2.1     public HCodeFactory codeFactory() { return this.hcf; }
120 cananian 1.1.2.1 
121 cananian 1.1.2.1     // Let's use the (address of the) string constant corresponding to the
122 cananian 1.1.2.1     // full name of the (former) field as our secondary key into the hash
123 cananian 1.1.2.1     // table.  This isn't ideal from a space perspective: we ought to be
124 cananian 1.1.2.1     // able to squeeze the object pointer and the field identifier into
125 cananian 1.1.2.1     // one word.  But it'll do for now.
126 cananian 1.1.2.1     
127 cananian 1.1.2.1     // also, we're going to simplify the native method implementation so
128 cananian 1.1.2.1     // that we just have three types: 32-bit word, 64-bit word, and pointer.
129 cananian 1.1.2.1     // we'll do the appropriate conversions in java-land.
130 cananian 1.1.2.1 
131 cananian 1.5         HCode<Quad> makeGetter(HCodeFactory hcf, HMethod getter,
132 cananian 1.1.2.1                      HField hf, Number mostly) {
133 cananian 1.1.2.1         // xxx cheat: get old getter and replace GET with our cruft.
134 cananian 1.1.2.1         // would be better to make this from scratch.
135 cananian 1.5             HCode<Quad> hc = hcf.convert(getter);
136 cananian 1.3.2.1         assert hc.getName().equals(QuadRSSx.codename) : hc;
137 cananian 1.6             for (Iterator<Quad> it=new SnapshotIterator<Quad>
138 cananian 1.6                      (hc.getElementsI()); it.hasNext(); ) {
139 cananian 1.6                 Quad aquad = it.next();
140 cananian 1.6                 if (aquad instanceof GET) {
141 cananian 1.6                     GET q = (GET) aquad;
142 cananian 1.3.2.1                 assert q.field().equals(hf);
143 cananian 1.1.2.1                 // mu-ha-ha-ha-ha-ha!
144 cananian 1.1.2.1                 QuadFactory qf = q.getFactory();
145 cananian 1.1.2.1                 Temp defT = new Temp(qf.tempFactory(), "default");
146 cananian 1.1.2.1                 Temp keyT = new Temp(qf.tempFactory(), "key");
147 cananian 1.1.2.1                 Temp retexT = new Temp(qf.tempFactory(), "retex");
148 cananian 1.1.2.1                 HClass ty = widen(q.field().getType());
149 cananian 1.1.2.1                 String KEY = hf.getDeclaringClass().getName()+"."+hf.getName();
150 cananian 1.1.2.1                 Quad q0 = new CONST
151 cananian 1.1.2.1                     (qf, q, keyT, KEY, linker.forName("java.lang.String"));
152 cananian 1.3.2.1                 assert ty.isPrimitive()?true:mostly.intValue()==0;
153 cananian 1.1.2.1                 Quad q1 = ty.isPrimitive() ?
154 cananian 1.1.2.1                     new CONST(qf, q, defT, makeValue(ty, mostly), ty) :
155 cananian 1.1.2.1                     new CONST(qf, q, defT, null, HClass.Void);
156 cananian 1.1.2.1                 // call HASHGET(KEY, obj, mostly)
157 cananian 1.1.2.1                 Quad q2 = new CALL
158 cananian 1.1.2.1                     (qf, q, hashGET(ty),
159 cananian 1.1.2.1                      new Temp[] { keyT, q.objectref(), defT },
160 cananian 1.1.2.1                      q.dst(), retexT, false, ty.isPrimitive(), new Temp[0]);
161 cananian 1.1.2.1                 // throw any error returned.
162 cananian 1.1.2.1                 Quad q3 = new THROW(qf, q, retexT);
163 cananian 1.1.2.1                 // okay, link all these together.
164 cananian 1.1.2.1                 Edge in = q.prevEdge(0), out = q.nextEdge(0);
165 cananian 1.5                     Quad.addEdge(in.from(), in.which_succ(), q0, 0);
166 cananian 1.1.2.1                 Quad.addEdges(new Quad[] { q0, q1, q2 });
167 cananian 1.1.2.1                 Quad.addEdge(q2, 0, (Quad)out.to(), out.which_pred());
168 cananian 1.1.2.1                 Quad.addEdge(q2, 1, q3, 0);
169 cananian 1.6                     FOOTER f = ((HEADER)hc.getRootElement()).footer();
170 cananian 1.1.2.1                 f=f.attach(q3, 0);
171 cananian 1.1.2.1                 // insert type check for non-primitive types.
172 cananian 1.1.2.1                 if (!ty.isPrimitive()) {
173 cananian 1.1.2.2                     // INSTANCEOF can't be given null, so do a null-check 1st.
174 cananian 1.3.2.1                     // if (q!=null && !(q instanceof xxx)) assert 0;
175 cananian 1.1.2.2                     Temp nullT = new Temp(qf.tempFactory(), "null");
176 cananian 1.1.2.1                     Temp tstT = new Temp(qf.tempFactory(), "test");
177 cananian 1.1.2.2                     Quad q4 = new CONST(qf, q, nullT, null, HClass.Void);
178 cananian 1.1.2.2                     Quad q5 = new OPER(qf, q, Qop.ACMPEQ, tstT,
179 cananian 1.1.2.2                                        new Temp[] { q.dst(), nullT });
180 cananian 1.1.2.2                     Quad q6 = new CJMP(qf, q, tstT, new Temp[0]);
181 cananian 1.1.2.2                     Quad q7 = new INSTANCEOF(qf, q, tstT, q.dst(), ty);
182 cananian 1.1.2.2                     Quad q8 = new CJMP(qf, q, tstT, new Temp[0]);
183 cananian 1.1.2.2                     Quad q9 = new PHI(qf, q, new Temp[0], 2);//nrm
184 cananian 1.1.2.1                     // what do i do if not valid?  i'm too lazy to create
185 cananian 1.1.2.2                     // an exception to throw.  let's infinite-loop.
186 cananian 1.1.2.2                     Quad q10= new PHI(qf, q, new Temp[0], 2);//ex
187 cananian 1.1.2.2                     Quad.addEdges(new Quad[] { q2, q4, q5, q6, q7, q8, q10 });
188 cananian 1.1.2.2                     Quad.addEdge(q6, 1, q9, 0);
189 cananian 1.1.2.2                     Quad.addEdge(q8, 1, q9, 1);
190 cananian 1.5                         Quad.addEdge(q9, 0, out.to(), out.which_pred());
191 cananian 1.1.2.2                     Quad.addEdge(q10, 0, q10, 1);
192 cananian 1.1.2.1                 }
193 cananian 1.1.2.1             }
194 cananian 1.1.2.1         }
195 cananian 1.1.2.1         // done!
196 cananian 1.1.2.1         return hc;
197 cananian 1.1.2.1     }
198 cananian 1.5         HCode<Quad> makeSetter(HCodeFactory hcf, HMethod setter,
199 cananian 1.1.2.1                      HField hf, Number mostly) {
200 cananian 1.1.2.1         // xxx cheat: get old setter and replace SET with our cruft.
201 cananian 1.1.2.1         // would be better to make this from scratch.
202 cananian 1.5             HCode<Quad> hc = hcf.convert(setter);
203 cananian 1.3.2.1         assert hc.getName().equals(QuadRSSx.codename) : hc;
204 cananian 1.6             for (Iterator<Quad> it=new SnapshotIterator<Quad>
205 cananian 1.6                      (hc.getElementsI()); it.hasNext(); ) {
206 cananian 1.6                 Quad aquad = it.next();
207 cananian 1.6                 if (aquad instanceof SET) {
208 cananian 1.6                     SET q = (SET) aquad;
209 cananian 1.3.2.1                 assert q.field().equals(hf);
210 cananian 1.1.2.1                 // mu-ha-ha-ha-ha-ha!
211 cananian 1.1.2.1                 QuadFactory qf = q.getFactory();
212 cananian 1.1.2.1                 Temp defT = new Temp(qf.tempFactory(), "default");
213 cananian 1.1.2.1                 Temp keyT = new Temp(qf.tempFactory(), "key");
214 cananian 1.1.2.1                 Temp retexT = new Temp(qf.tempFactory(), "retex");
215 cananian 1.1.2.1                 HClass ty = widen(q.field().getType());
216 cananian 1.1.2.1                 String KEY = hf.getDeclaringClass().getName()+"."+hf.getName();
217 cananian 1.1.2.1                 Quad q0 = new CONST
218 cananian 1.1.2.1                     (qf, q, keyT, KEY, linker.forName("java.lang.String"));
219 cananian 1.3.2.1                 assert ty.isPrimitive()?true:mostly.intValue()==0;
220 cananian 1.1.2.1                 Quad q1 = ty.isPrimitive() ?
221 cananian 1.1.2.1                     new CONST(qf, q, defT, makeValue(ty, mostly), ty) :
222 cananian 1.1.2.1                     new CONST(qf, q, defT, null, HClass.Void);
223 cananian 1.1.2.1                 // call HASHSET(KEY, obj, newvalue, mostly)
224 cananian 1.1.2.1                 Quad q2 = new CALL
225 cananian 1.1.2.1                     (qf, q, hashSET(ty),
226 cananian 1.1.2.1                      new Temp[] { keyT, q.objectref(), q.src(), defT },
227 cananian 1.1.2.1                      null, retexT, false, true, new Temp[0]);
228 cananian 1.1.2.1                 // throw any error returned.
229 cananian 1.1.2.1                 Quad q3 = new THROW(qf, q, retexT);
230 cananian 1.1.2.1                 // okay, link all these together.
231 cananian 1.1.2.1                 Edge in = q.prevEdge(0), out = q.nextEdge(0);
232 cananian 1.1.2.1                 Quad.addEdge((Quad)in.from(), in.which_succ(), q0, 0);
233 cananian 1.1.2.1                 Quad.addEdges(new Quad[] { q0, q1, q2 });
234 cananian 1.1.2.1                 Quad.addEdge(q2, 0, (Quad)out.to(), out.which_pred());
235 cananian 1.1.2.1                 Quad.addEdge(q2, 1, q3, 0);
236 cananian 1.6                     FOOTER f = ((HEADER)hc.getRootElement()).footer();
237 cananian 1.1.2.1                 f=f.attach(q3, 0);
238 cananian 1.1.2.1             }
239 cananian 1.1.2.1         }
240 cananian 1.1.2.1         // done!
241 cananian 1.1.2.1         return hc;
242 cananian 1.1.2.1     }
243 cananian 1.1.2.1     // private helper functions.
244 cananian 1.1.2.1     private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); }
245 cananian 1.1.2.1     private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) {
246 cananian 1.5             Quad frm = e.from(); int frm_succ = e.which_succ();
247 cananian 1.5             Quad to  = e.to();   int to_pred = e.which_pred();
248 cananian 1.1.2.1         Quad.addEdge(frm, frm_succ, q, which_pred);
249 cananian 1.1.2.1         Quad.addEdge(q, which_succ, to, to_pred);
250 cananian 1.1.2.1         return to.prevEdge(to_pred);
251 cananian 1.1.2.1     }
252 cananian 1.1.2.1     // widen sub-int primitive types.
253 cananian 1.1.2.1     private static HClass widen(HClass hc) {
254 cananian 1.1.2.1         return MZFCompressor.widen(hc);
255 cananian 1.1.2.1     }
256 cananian 1.1.2.1     // wrap a value w/ an object of the appropriate type.
257 cananian 1.1.2.1     private static Object makeValue(HClass type, Number num) {
258 cananian 1.1.2.1         return MZFCompressor.wrap(type, num);
259 cananian 1.1.2.1     }
260 cananian 1.1.2.1     private HMethod hashGET(HClass type) {
261 cananian 1.1.2.1         if (!type.isPrimitive()) return ptrGET;
262 cananian 1.1.2.1         if (type==HClass.Int) return intGET;
263 cananian 1.1.2.1         if (type==HClass.Long) return longGET;
264 cananian 1.1.2.1         if (type==HClass.Float) return floatGET;
265 cananian 1.1.2.1         if (type==HClass.Double) return doubleGET;
266 cananian 1.3.2.1         assert false : ("unknown type: "+type);
267 cananian 1.1.2.1         return null;
268 cananian 1.1.2.1     }
269 cananian 1.1.2.1     private HMethod hashSET(HClass type) {
270 cananian 1.1.2.1         if (!type.isPrimitive()) return ptrSET;
271 cananian 1.1.2.1         if (type==HClass.Int) return intSET;
272 cananian 1.1.2.1         if (type==HClass.Long) return longSET;
273 cananian 1.1.2.1         if (type==HClass.Float) return floatSET;
274 cananian 1.1.2.1         if (type==HClass.Double) return doubleSET;
275 cananian 1.3.2.1         assert false : ("unknown type: "+type);
276 cananian 1.1.2.1         return null;
277 cananian 1.1.2.1     }
278 cananian 1.2     }