1 cananian 1.1.2.1 // MZFChooser.java, created Mon Nov 12 22:20:58 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.2 import harpoon.Analysis.Transformation.MethodMutator; 7 cananian 1.1.2.2 import harpoon.ClassFile.HClass; 8 cananian 1.1.2.2 import harpoon.ClassFile.HCode; 9 cananian 1.1.2.2 import harpoon.ClassFile.HCodeAndMaps; 10 cananian 1.1.2.2 import harpoon.ClassFile.HCodeFactory; 11 cananian 1.1.2.2 import harpoon.ClassFile.HConstructor; 12 cananian 1.1.2.2 import harpoon.ClassFile.HField; 13 cananian 1.1.2.2 import harpoon.ClassFile.HMethod; 14 cananian 1.1.2.2 import harpoon.IR.Quads.CALL; 15 cananian 1.1.2.2 import harpoon.IR.Quads.CJMP; 16 cananian 1.1.2.2 import harpoon.IR.Quads.CONST; 17 cananian 1.1.2.2 import harpoon.IR.Quads.Code; 18 cananian 1.1.2.2 import harpoon.IR.Quads.Edge; 19 cananian 1.1.2.2 import harpoon.IR.Quads.NEW; 20 cananian 1.1.2.2 import harpoon.IR.Quads.OPER; 21 cananian 1.1.2.2 import harpoon.IR.Quads.PHI; 22 cananian 1.1.2.2 import harpoon.IR.Quads.Qop; 23 cananian 1.1.2.2 import harpoon.IR.Quads.Quad; 24 cananian 1.1.2.2 import harpoon.IR.Quads.QuadFactory; 25 cananian 1.1.2.2 import harpoon.IR.Quads.QuadRSSx; 26 cananian 1.1.2.2 import harpoon.IR.Quads.QuadSSA; 27 cananian 1.1.2.2 import harpoon.IR.Quads.QuadVisitor; 28 cananian 1.1.2.2 import harpoon.Temp.Temp; 29 cananian 1.7 import net.cscott.jutil.Default.PairList; 30 cananian 1.1.2.2 import harpoon.Util.Util; 31 cananian 1.1.2.1 32 cananian 1.1.2.2 import java.util.HashMap; 33 cananian 1.1.2.2 import java.util.HashSet; 34 cananian 1.1.2.2 import java.util.Iterator; 35 cananian 1.1.2.2 import java.util.List; 36 cananian 1.1.2.2 import java.util.Map; 37 cananian 1.1.2.2 import java.util.Set; 38 cananian 1.1.2.1 /** 39 cananian 1.1.2.1 * <code>MZFChooser</code> adds code to instantiate the correct 40 cananian 1.1.2.1 * MZF-compressed version of a class at run-time. 41 cananian 1.1.2.1 * 42 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 43 cananian 1.8 * @version $Id: MZFChooser.java,v 1.8 2004/02/08 03:20:22 cananian Exp $ 44 cananian 1.1.2.1 */ 45 cananian 1.5 class MZFChooser extends MethodMutator<Quad> { 46 cananian 1.1.2.1 /** an oracle to determine the properties of constructors. */ 47 cananian 1.1.2.1 final ConstructorClassifier cc; 48 cananian 1.1.2.1 /** a map from HClasses to a list of sorted fields; the splitting has 49 cananian 1.1.2.1 * been done in the order of the list. */ 50 cananian 1.6 final Map<HClass,List<PairList<HField,Number>>> listmap; 51 cananian 1.1.2.1 /** a map from <code>HField</code>s to the <code>HClass</code> which 52 cananian 1.1.2.1 * eliminates that field. */ 53 cananian 1.5 final Map<HField,HClass> field2class; 54 cananian 1.1.2.1 /** Creates a <code>MZFChooser</code>. */ 55 cananian 1.1.2.1 public MZFChooser(HCodeFactory hcf, ConstructorClassifier cc, 56 cananian 1.6 Map<HClass,List<PairList<HField,Number>>> listmap, 57 cananian 1.5 Map<HField,HClass> field2class) { 58 cananian 1.1.2.1 super(QuadSSA.codeFactory(hcf)); 59 cananian 1.1.2.1 this.cc = cc; 60 cananian 1.1.2.1 this.listmap = listmap; 61 cananian 1.1.2.1 this.field2class = field2class; 62 cananian 1.1.2.1 } 63 cananian 1.1.2.2 protected String mutateCodeName(String codeName) { 64 cananian 1.1.2.2 // input SSA, output RSSx. 65 cananian 1.1.2.2 return QuadRSSx.codename; 66 cananian 1.1.2.2 } 67 cananian 1.5 protected HCodeAndMaps<Quad> cloneHCode(HCode<Quad> hc, HMethod newmethod){ 68 cananian 1.1.2.2 // make SSA into RSSx. 69 cananian 1.3.2.1 assert hc.getName().equals(QuadSSA.codename); 70 cananian 1.1.2.2 return MyRSSx.cloneToRSSx((harpoon.IR.Quads.Code)hc, newmethod); 71 cananian 1.1.2.2 } 72 cananian 1.1.2.2 private static class MyRSSx extends QuadRSSx { 73 cananian 1.1.2.2 private MyRSSx(HMethod m) { super(m, null); } 74 cananian 1.5 public static HCodeAndMaps<Quad> cloneToRSSx(harpoon.IR.Quads.Code c, 75 cananian 1.1.2.2 HMethod m) { 76 cananian 1.1.2.2 MyRSSx r = new MyRSSx(m); 77 cananian 1.1.2.2 return r.cloneHelper(c, r); 78 cananian 1.1.2.2 } 79 cananian 1.1.2.2 } 80 cananian 1.5 protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) { 81 cananian 1.5 HCode<Quad> hc = input.hcode(); 82 cananian 1.1.2.1 // first, find set of constructor-calls in this HCode. 83 cananian 1.1.2.1 QuadFinder qfinder = new QuadFinder(); 84 cananian 1.5 for (Iterator<Quad> it=hc.getElementsI(); it.hasNext(); ) 85 cananian 1.5 it.next().accept(qfinder); 86 cananian 1.1.2.1 // for each constructor: 87 cananian 1.8 for (CALL qC : qfinder.constructors) { 88 cananian 1.3.2.1 assert !qC.isVirtual(); 89 cananian 1.1.2.1 // match it to a 'NEW'. 90 cananian 1.5 NEW qN = qfinder.temp2new.get(qC.params(0)); 91 cananian 1.1.2.1 if (qN==null) continue; // typically call to super-constructor. 92 cananian 1.1.2.1 // if we know anything about this constructor... 93 cananian 1.1.2.1 if (!cc.isGood(qC.method())) continue; 94 cananian 1.3.2.1 assert qN.hclass().equals(qC.method().getDeclaringClass()) : qN+" / "+qC; 95 cananian 1.1.2.1 // fetch field list for this class. 96 cananian 1.6 List<PairList<HField,Number>> sortedFields = 97 cananian 1.5 listmap.get(qN.hclass()); 98 cananian 1.1.2.1 if (sortedFields==null) continue; // nothing known about this class 99 cananian 1.1.2.1 // delete the NEW. 100 cananian 1.1.2.1 qN.remove(); 101 cananian 1.1.2.1 // replace CALL with test-and-NEW-and-CALL. 102 cananian 1.1.2.1 refactor(qC.method(), qC, sortedFields); 103 cananian 1.1.2.1 } 104 cananian 1.1.2.1 return hc; 105 cananian 1.1.2.1 } 106 cananian 1.1.2.1 static class QuadFinder extends QuadVisitor { 107 cananian 1.1.2.1 /** map temps to 'NEW's where they are defined. */ 108 cananian 1.5 Map<Temp,NEW> temp2new = new HashMap<Temp,NEW>(); 109 cananian 1.1.2.1 /** set of constructor CALLs. */ 110 cananian 1.5 Set<CALL> constructors = new HashSet<CALL>(); 111 cananian 1.1.2.1 public void visit(Quad q) { /* not interesting */ } 112 cananian 1.1.2.1 public void visit(NEW q) { 113 cananian 1.3.2.1 assert !temp2new.containsKey(q.dst()) : "SSx form"; 114 cananian 1.1.2.1 temp2new.put(q.dst(), q); 115 cananian 1.1.2.1 } 116 cananian 1.1.2.1 public void visit(CALL q) { 117 cananian 1.1.2.1 if (isConstructor(q.method())) 118 cananian 1.1.2.1 constructors.add(q); 119 cananian 1.1.2.1 } 120 cananian 1.1.2.1 ///////// copied from harpoon.Analysis.Quads.DefiniteInitOracle. 121 cananian 1.1.2.1 /** return an approximation to whether this is a constructor 122 cananian 1.1.2.1 * or not. it's always safe to return false. */ 123 cananian 1.1.2.1 private static boolean isConstructor(HMethod hm) { 124 cananian 1.1.2.1 // this is tricky, because we want split constructors to 125 cananian 1.1.2.1 // count, too, even though renamed constructors (such as 126 cananian 1.1.2.1 // generated by initcheck, for instance) won't always be 127 cananian 1.1.2.1 // instanceof HConstructor. Look for names starting with 128 cananian 1.1.2.1 // '<init>', as well. 129 cananian 1.1.2.1 if (hm instanceof HConstructor) return true; 130 cananian 1.1.2.1 if (hm.getName().startsWith("<init>")) return true; 131 cananian 1.1.2.1 // XXX: what about methods generated by RuntimeMethod Cloner? 132 cananian 1.1.2.1 // we could try methods ending with <init>, but then the 133 cananian 1.1.2.1 // declaringclass information would be wrong. 134 cananian 1.1.2.1 //if (hm.getName().endsWidth("<init>")) return true;//not safe yet. 135 cananian 1.1.2.1 return false; 136 cananian 1.1.2.1 } 137 cananian 1.1.2.1 } 138 cananian 1.5 void refactor(HMethod constructor, CALL qC, 139 cananian 1.6 List<PairList<HField,Number>> sortedFields) { 140 cananian 1.1.2.2 QuadFactory qf = qC.getFactory(); 141 cananian 1.1.2.1 if (sortedFields.size()==0) { // base case. 142 cananian 1.1.2.2 Quad qN = new NEW(qf, qC, qC.params(0), 143 cananian 1.1.2.1 qC.method().getDeclaringClass()); 144 cananian 1.1.2.1 addAt(qC.prevEdge(0), qN); 145 cananian 1.1.2.1 return; 146 cananian 1.1.2.1 } 147 cananian 1.6 PairList<HField,Number> pair = sortedFields.get(0); 148 cananian 1.1.2.1 HField hf = (HField) pair.get(0); // field 149 cananian 1.1.2.1 Number num = (Number) pair.get(1); // 'mostly-what?' 150 cananian 1.1.2.2 // lookup 'spiffy constructor' 151 cananian 1.5 HClass newC = field2class.get(hf); 152 cananian 1.1.2.2 HMethod newM = newC.getDeclaredMethod 153 cananian 1.1.2.2 (constructor.getName(), constructor.getDescriptor()); 154 cananian 1.1.2.1 // check whether this field is constant w/ this constructor. 155 cananian 1.1.2.1 if (cc.isConstant(constructor, hf)) { 156 cananian 1.1.2.1 Object val = cc.constantValue(constructor, hf); 157 cananian 1.1.2.1 if (val==null ? num.longValue()==0 : 158 cananian 1.1.2.2 (val instanceof Number && /* no String, etc constants */ 159 cananian 1.1.2.2 ((Number)val).doubleValue()==num.doubleValue())) { 160 cananian 1.1.2.1 // okay, always a constant of the right value. 161 cananian 1.1.2.1 // we can replace original constructor with alternate. 162 cananian 1.1.2.2 CALL qCN = new CALL(qf, qC, newM, 163 cananian 1.1.2.1 qC.params(), qC.retval(), qC.retex(), 164 cananian 1.1.2.1 qC.isVirtual(), qC.isTailCall(), 165 cananian 1.1.2.1 qC.dst(), qC.src()); 166 cananian 1.1.2.1 Quad.replace(qC, qCN); 167 cananian 1.1.2.1 // now recursively invoke on rest of list. 168 cananian 1.1.2.1 refactor(constructor, qCN, 169 cananian 1.1.2.1 sortedFields.subList(1, sortedFields.size())); 170 cananian 1.1.2.1 return; 171 cananian 1.1.2.1 } 172 cananian 1.1.2.1 } 173 cananian 1.1.2.1 // check whether this field is a function of a param. 174 cananian 1.1.2.3 // (oh, it also can't be a function of param#0, which isn't 175 cananian 1.1.2.3 // defined yet) 176 cananian 1.1.2.3 if (cc.isParam(constructor, hf) && 177 cananian 1.1.2.3 0 != cc.paramNumber(constructor, hf)) { 178 cananian 1.1.2.1 int which = cc.paramNumber(constructor, hf); 179 cananian 1.1.2.2 // test whether param(which) is equal to 'num'. 180 cananian 1.1.2.1 // if so, use specialized class, else fall back. 181 cananian 1.1.2.2 Temp tZ = new Temp(qf.tempFactory(), "mostly"); 182 cananian 1.1.2.2 Temp tC = new Temp(qf.tempFactory(), "lucky"); 183 cananian 1.1.2.2 // tZ = CONST(mostlyN) 184 cananian 1.1.2.2 // tC = CMPEQ(tZ, param(which)) 185 cananian 1.1.2.2 // if (tC) 186 cananian 1.1.2.2 // call spiffy constructor (recurse here) 187 cananian 1.1.2.2 // else 188 cananian 1.1.2.2 // NEW boring class 189 cananian 1.1.2.2 // call new boring constructor. 190 cananian 1.1.2.2 // PHI/return (output is SSx?) PHI/throw 191 cananian 1.1.2.2 HClass ty = widen(hf.getType()); 192 cananian 1.1.2.2 Quad q0 = ty.isPrimitive() ? 193 cananian 1.1.2.2 new CONST(qf, qC, tZ, makeValue(ty, num), ty) : 194 cananian 1.1.2.2 new CONST(qf, qC, tZ, null, HClass.Void); 195 cananian 1.3.2.1 assert ty.isPrimitive()?true:num.intValue()==0; 196 cananian 1.1.2.2 Quad q1 = new OPER(qf, qC, makeEqOp(ty), tC, 197 cananian 1.1.2.2 new Temp[] { tZ, qC.params(which) }); 198 cananian 1.1.2.2 Quad q2 = new CJMP(qf, qC, tC, new Temp[0]); 199 cananian 1.1.2.2 CALL q3 = new CALL(qf, qC, newM /* spiffy */, 200 cananian 1.1.2.2 qC.params(), qC.retval(), qC.retex(), 201 cananian 1.1.2.2 qC.isVirtual(), qC.isTailCall(), 202 cananian 1.1.2.2 qC.dst(), qC.src()); 203 cananian 1.3.2.1 assert qC.retval()==null; // constructor should be void 204 cananian 1.1.2.2 Quad q4 = new NEW(qf, qC, qC.params(0), /* boring */ 205 cananian 1.1.2.2 qC.method().getDeclaringClass()); 206 cananian 1.1.2.2 Quad q5 = new PHI(qf, qC, new Temp[0], 2); //retval phi 207 cananian 1.1.2.2 Quad q6 = new PHI(qf, qC, new Temp[0], 2); //retex phi 208 cananian 1.1.2.2 Edge in = qC.prevEdge(0); 209 cananian 1.1.2.2 Edge retout=qC.nextEdge(0); 210 cananian 1.1.2.2 Edge exout=qC.nextEdge(1); 211 cananian 1.1.2.2 in = addAt(in, q0); 212 cananian 1.1.2.2 in = addAt(in, q1); 213 cananian 1.1.2.2 in = addAt(in, q2); 214 cananian 1.1.2.2 in = addAt(in, q4); 215 cananian 1.1.2.2 addAt(retout, q5); 216 cananian 1.1.2.2 addAt(exout, q6); 217 cananian 1.1.2.2 Quad.addEdge(q2, 1, q3, 0); 218 cananian 1.1.2.2 Quad.addEdge(q3, 0, q5, 1); 219 cananian 1.1.2.2 Quad.addEdge(q3, 1, q6, 1); 220 cananian 1.1.2.2 // now recursively invoke on rest of list. 221 cananian 1.1.2.2 refactor(constructor, q3, 222 cananian 1.1.2.2 sortedFields.subList(1, sortedFields.size())); 223 cananian 1.1.2.2 return; 224 cananian 1.1.2.1 } 225 cananian 1.1.2.1 // nothing known about this field w/ this constructor. 226 cananian 1.1.2.1 // clean up (add NEW) and go home. 227 cananian 1.1.2.2 Quad qN = new NEW(qf, qC, qC.params(0), 228 cananian 1.1.2.1 qC.method().getDeclaringClass()); 229 cananian 1.1.2.1 addAt(qC.prevEdge(0), qN); 230 cananian 1.1.2.1 return; 231 cananian 1.1.2.1 } 232 cananian 1.1.2.1 // private helper functions. 233 cananian 1.1.2.1 private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); } 234 cananian 1.1.2.1 private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) { 235 cananian 1.5 Quad frm = e.from(); int frm_succ = e.which_succ(); 236 cananian 1.5 Quad to = e.to(); int to_pred = e.which_pred(); 237 cananian 1.1.2.1 Quad.addEdge(frm, frm_succ, q, which_pred); 238 cananian 1.1.2.1 Quad.addEdge(q, which_succ, to, to_pred); 239 cananian 1.1.2.1 return to.prevEdge(to_pred); 240 cananian 1.1.2.2 } 241 cananian 1.1.2.2 // widen sub-int primitive types. 242 cananian 1.1.2.2 private static HClass widen(HClass hc) { 243 cananian 1.1.2.2 return MZFCompressor.widen(hc); 244 cananian 1.1.2.2 } 245 cananian 1.1.2.2 // wrap a value w/ an object of the appropriate type. 246 cananian 1.1.2.2 private static Object makeValue(HClass type, Number num) { 247 cananian 1.1.2.2 return MZFCompressor.wrap(type, num); 248 cananian 1.1.2.2 } 249 cananian 1.1.2.2 private static int makeEqOp(HClass type) { 250 cananian 1.1.2.2 if (!type.isPrimitive()) return Qop.ACMPEQ; 251 cananian 1.1.2.2 if (type==HClass.Int) return Qop.ICMPEQ; 252 cananian 1.1.2.2 if (type==HClass.Long) return Qop.LCMPEQ; 253 cananian 1.1.2.2 if (type==HClass.Float) return Qop.FCMPEQ; 254 cananian 1.1.2.2 if (type==HClass.Double) return Qop.DCMPEQ; 255 cananian 1.3.2.1 assert false : ("unknown type: "+type); 256 cananian 1.1.2.2 return -1; 257 cananian 1.1.2.1 } 258 cananian 1.2 }