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 }