1 cananian 1.1.2.1 // FieldReducer.java, created Thu Jul 19 18:55:44 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.ClassHierarchy; 7 cananian 1.1.2.2 import harpoon.Analysis.Maps.ConstMap; 8 cananian 1.1.2.2 import harpoon.Analysis.Maps.ExactTypeMap; 9 cananian 1.1.2.2 import harpoon.Analysis.Maps.ExecMap; 10 cananian 1.1.2.2 import harpoon.Analysis.Quads.SCC.SCCOptimize; 11 cananian 1.1.2.2 import harpoon.Analysis.Transformation.MethodMutator; 12 cananian 1.1.2.4 import harpoon.Backend.Generic.Frame; 13 cananian 1.1.2.2 import harpoon.ClassFile.CachingCodeFactory; 14 cananian 1.1.2.2 import harpoon.ClassFile.HClass; 15 cananian 1.1.2.2 import harpoon.ClassFile.HClassMutator; 16 cananian 1.1.2.2 import harpoon.ClassFile.HCode; 17 cananian 1.1.2.2 import harpoon.ClassFile.HCodeAndMaps; 18 cananian 1.1.2.2 import harpoon.ClassFile.HCodeEdge; 19 cananian 1.1.2.2 import harpoon.ClassFile.HCodeElement; 20 cananian 1.1.2.2 import harpoon.ClassFile.HCodeFactory; 21 cananian 1.1.2.2 import harpoon.ClassFile.HField; 22 cananian 1.1.2.2 import harpoon.ClassFile.HFieldMutator; 23 cananian 1.1.2.2 import harpoon.ClassFile.HMethod; 24 cananian 1.1.2.2 import harpoon.ClassFile.Linker; 25 cananian 1.1.2.3 import harpoon.IR.Quads.CALL; 26 cananian 1.1.2.2 import harpoon.IR.Quads.CONST; 27 cananian 1.1.2.2 import harpoon.IR.Quads.Edge; 28 cananian 1.1.2.2 import harpoon.IR.Quads.FOOTER; 29 cananian 1.1.2.2 import harpoon.IR.Quads.GET; 30 cananian 1.1.2.2 import harpoon.IR.Quads.HEADER; 31 cananian 1.1.2.3 import harpoon.IR.Quads.METHOD; 32 cananian 1.1.2.3 import harpoon.IR.Quads.NEW; 33 cananian 1.1.2.3 import harpoon.IR.Quads.PHI; 34 cananian 1.1.2.2 import harpoon.IR.Quads.Quad; 35 cananian 1.1.2.3 import harpoon.IR.Quads.QuadFactory; 36 cananian 1.1.2.2 import harpoon.IR.Quads.QuadSSI; 37 cananian 1.1.2.2 import harpoon.IR.Quads.SET; 38 cananian 1.1.2.3 import harpoon.IR.Quads.THROW; 39 cananian 1.1.2.2 import harpoon.Temp.Temp; 40 cananian 1.1.2.2 import harpoon.Temp.TempMap; 41 cananian 1.7 import net.cscott.jutil.SnapshotIterator; 42 cananian 1.1.2.2 import harpoon.Util.Util; 43 cananian 1.1.2.1 44 cananian 1.1.2.2 import java.util.Arrays; 45 cananian 1.1.2.3 import java.util.HashMap; 46 cananian 1.1.2.2 import java.util.HashSet; 47 cananian 1.1.2.2 import java.util.Iterator; 48 cananian 1.1.2.2 import java.util.Map; 49 cananian 1.1.2.2 import java.util.Set; 50 cananian 1.1.2.1 /** 51 cananian 1.1.2.1 * The <code>FieldReducer</code> code factory uses the results of a 52 cananian 1.1.2.1 * <code>BitWidthAnalysis</code> to shrink field types and eliminate 53 cananian 1.1.2.1 * unused and constant fields from objects. 54 cananian 1.1.2.1 * 55 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 56 cananian 1.8 * @version $Id: FieldReducer.java,v 1.8 2004/02/08 03:20:22 cananian Exp $ 57 cananian 1.1.2.1 */ 58 cananian 1.5 public class FieldReducer extends MethodMutator<Quad> { 59 cananian 1.1.2.5 private static final boolean no_mutate = 60 cananian 1.1.2.5 Boolean.getBoolean("harpoon.sizeopt.no-field-reducer"); 61 cananian 1.1.2.3 private static final boolean DEBUG = false; 62 cananian 1.1.2.1 final BitWidthAnalysis bwa; 63 cananian 1.1.2.3 final Linker linker; 64 cananian 1.1.2.1 65 cananian 1.1.2.1 /** Creates a <code>FieldReducer</code>. */ 66 cananian 1.1.2.4 public FieldReducer(HCodeFactory parent, Frame frame, ClassHierarchy ch, 67 cananian 1.1.2.3 Set roots, String fieldRootResourceName) { 68 cananian 1.1.2.1 this(new CachingCodeFactory(QuadSSI.codeFactory(parent)), 69 cananian 1.1.2.4 frame, ch, roots, fieldRootResourceName); 70 cananian 1.1.2.1 } 71 cananian 1.1.2.4 private FieldReducer(CachingCodeFactory parent, Frame frame, 72 cananian 1.1.2.3 ClassHierarchy ch, Set roots, String frrn) { 73 cananian 1.1.2.1 super(parent); 74 cananian 1.1.2.4 this.bwa = new BitWidthAnalysis(frame.getLinker(), parent, 75 cananian 1.1.2.4 ch, roots, frrn); 76 cananian 1.1.2.4 this.linker = frame.getLinker(); 77 cananian 1.1.2.1 // pull all our classes through the mutator. 78 cananian 1.1.2.4 this.hcf = super.codeFactory(); 79 cananian 1.5 for (Iterator<HMethod> it=ch.callableMethods().iterator(); 80 cananian 1.5 it.hasNext(); ) 81 cananian 1.5 hcf.convert(it.next()); 82 cananian 1.1.2.1 // now munge class fields (after we've rewritten all field references) 83 cananian 1.1.2.1 84 cananian 1.1.2.1 // first, collect all non-static fields of this application. 85 cananian 1.5 Set<HField> flds = new HashSet<HField>(7*ch.classes().size()); 86 cananian 1.5 for (Iterator<HClass> it=ch.classes().iterator(); it.hasNext(); ) 87 cananian 1.5 flds.addAll(Arrays.asList(it.next().getFields())); 88 cananian 1.5 for (Iterator<HField> it=flds.iterator(); it.hasNext(); ) 89 cananian 1.5 if (it.next().isStatic()) it.remove(); 90 cananian 1.1.2.1 // now munge fields! 91 cananian 1.8 for (HField hf : flds) { 92 cananian 1.1.2.5 if (no_mutate) continue; 93 cananian 1.1.2.1 // remove all unread and constant fields. 94 cananian 1.1.2.1 // (which should have no more references in any HCode) 95 cananian 1.1.2.1 if (bwa.isConst(hf) || !bwa.isRead(hf)) { 96 cananian 1.1.2.3 if (DEBUG) 97 cananian 1.1.2.3 System.err.println("REMOVING "+hf+" BECAUSE "+ 98 cananian 1.1.2.3 (bwa.isConst(hf)?"it is constant ":"")+ 99 cananian 1.1.2.3 (bwa.isRead(hf)?"":"it is unread")); 100 cananian 1.1.2.1 hf.getDeclaringClass().getMutator().removeDeclaredField(hf); 101 cananian 1.1.2.1 continue; 102 cananian 1.1.2.1 } 103 cananian 1.1.2.1 // shrink field sizes 104 cananian 1.1.2.1 HClass hc = hf.getType(); 105 cananian 1.1.2.1 if (!hc.isPrimitive()) continue; 106 cananian 1.1.2.1 if (hc==HClass.Float || hc==HClass.Double) continue; 107 cananian 1.1.2.1 int p = bwa.plusWidthMap(hf), m = bwa.minusWidthMap(hf); 108 cananian 1.1.2.1 // (pick a size) 109 cananian 1.1.2.1 HClass nhc = null; 110 cananian 1.1.2.1 if (hc==HClass.Long || (m<64 && p<=63)) nhc = HClass.Long; 111 cananian 1.1.2.1 if (hc==HClass.Int || (m<32 && p<=31)) nhc = HClass.Int; 112 cananian 1.1.2.1 if (hc==HClass.Char || (m==0 && p<=16)) nhc = HClass.Char; 113 cananian 1.1.2.1 if (hc==HClass.Short || (m<16 && p<=15)) nhc = HClass.Short; 114 cananian 1.1.2.1 if (hc==HClass.Byte || (m< 8 && p<= 7)) nhc = HClass.Byte; 115 cananian 1.1.2.1 if (hc==HClass.Boolean|| (m==0 && p<= 1)) nhc = HClass.Boolean; 116 cananian 1.3.2.1 assert nhc!=null; // one of these cases must have matched 117 cananian 1.1.2.3 if (DEBUG && hc!=nhc) System.err.print("REDUCING "+hf); 118 cananian 1.1.2.1 hf.getMutator().setType(nhc); 119 cananian 1.1.2.3 if (DEBUG && hc!=nhc) System.err.println(" TO "+hf); 120 cananian 1.1.2.1 } 121 cananian 1.1.2.5 // update field sizes in frame. (this is a bit of a hack) 122 cananian 1.1.2.5 frame.setClassHierarchy(ch); 123 cananian 1.1.2.4 // wrap a size counter around everything (maybe). 124 cananian 1.1.2.4 if (Boolean.getBoolean("harpoon.sizeopt.bitcounters")) { 125 cananian 1.1.2.4 this.hcf = new CachingCodeFactory 126 cananian 1.1.2.4 (new SizeCounters(this.hcf, frame, bwa).codeFactory()); 127 cananian 1.1.2.4 // pull everything through. 128 cananian 1.5 for (Iterator<HMethod> it=ch.callableMethods().iterator(); 129 cananian 1.5 it.hasNext(); ) 130 cananian 1.5 hcf.convert(it.next()); 131 cananian 1.1.2.4 } 132 cananian 1.1.2.1 // done! 133 cananian 1.1.2.1 } 134 cananian 1.1.2.4 // allow us to override the hcf. 135 cananian 1.1.2.4 private HCodeFactory hcf; 136 cananian 1.1.2.4 public HCodeFactory codeFactory() { return hcf; } 137 cananian 1.1.2.4 138 cananian 1.5 protected HCode<Quad> mutateHCode(HCodeAndMaps<Quad> input) { 139 cananian 1.5 HCode<Quad> hc = input.hcode(); 140 cananian 1.1.2.3 final Wrapper w = new Wrapper(input); 141 cananian 1.1.2.3 142 cananian 1.1.2.3 // optimize only methods which this analysis knows are callable. 143 cananian 1.1.2.3 // (non-callable methods will be entirely eliminated by dead-code 144 cananian 1.1.2.3 // elimination, resulting in invalid quad hcodes) 145 cananian 1.1.2.3 boolean isCallable = 146 cananian 1.5 w.execMap((METHOD)hc.getRootElement().next(1)); 147 cananian 1.1.2.3 if (!isCallable) return eviscerate(hc); 148 cananian 1.1.2.1 new SCCOptimize(w, w, w).optimize(hc); 149 cananian 1.1.2.5 if (no_mutate) return hc; 150 cananian 1.1.2.3 151 cananian 1.6 for (Iterator<Quad> it=new SnapshotIterator<Quad> 152 cananian 1.6 (hc.getElementsI()); it.hasNext(); ) { 153 cananian 1.6 Quad aquad = it.next(); 154 cananian 1.6 if (aquad instanceof GET) { 155 cananian 1.6 GET q = (GET) aquad; 156 cananian 1.1.2.3 // if this GET is not dead, then the field is read. 157 cananian 1.3.2.1 assert bwa.isRead(q.field()); 158 cananian 1.1.2.1 if (bwa.isConst(q.field())) { 159 cananian 1.1.2.1 // replace reads of constant fields with constant. 160 cananian 1.1.2.1 Quad.replace(q, new CONST 161 cananian 1.1.2.1 (q.getFactory(), q, q.dst(), 162 cananian 1.1.2.1 bwa.constMap(q.field()), 163 cananian 1.1.2.1 (bwa.constMap(q.field())==null) ? 164 cananian 1.1.2.1 HClass.Void : 165 cananian 1.1.2.1 toInternal(q.field().getType()))); 166 cananian 1.1.2.1 } 167 cananian 1.1.2.1 } 168 cananian 1.6 if (aquad instanceof SET) { 169 cananian 1.6 SET q = (SET) aquad; 170 cananian 1.1.2.1 if (!bwa.isRead(q.field())) { 171 cananian 1.1.2.1 // throw away writes to unread fields. 172 cananian 1.1.2.1 q.remove(); 173 cananian 1.1.2.3 } else if (bwa.isConst(q.field())) 174 cananian 1.1.2.3 // throw away writes to compile-time constant fields. 175 cananian 1.1.2.3 q.remove(); 176 cananian 1.1.2.1 } 177 cananian 1.1.2.1 } 178 cananian 1.1.2.1 return hc; 179 cananian 1.1.2.1 } 180 cananian 1.1.2.3 // Eviscerate this uncallable method, replacing with a simple throw. 181 cananian 1.5 private HCode<Quad> eviscerate(HCode<Quad> hc) { 182 cananian 1.1.2.3 HEADER header = (HEADER) hc.getRootElement(); 183 cananian 1.1.2.3 FOOTER footer = (FOOTER) header.next(0); 184 cananian 1.1.2.3 METHOD method = (METHOD) header.next(1); 185 cananian 1.1.2.3 footer = footer.resize(1); //eliminate all non-HEADER edges into footer 186 cananian 1.3.2.1 assert footer.prevLength()==1; 187 cananian 1.3.2.1 assert footer.prev(0)==header; 188 cananian 1.3.2.1 assert method.nextLength()==1; 189 cananian 1.1.2.3 // create new 'throw new RuntimeException()' body. 190 cananian 1.1.2.3 HClass HCrex = linker.forName("java.lang.RuntimeException"); 191 cananian 1.1.2.3 QuadFactory qf = header.getFactory(); 192 cananian 1.1.2.3 HCodeElement src = method; 193 cananian 1.1.2.3 Temp t0 = new Temp(qf.tempFactory()); 194 cananian 1.1.2.3 Temp t1 = new Temp(qf.tempFactory()); 195 cananian 1.1.2.3 Temp t2 = new Temp(qf.tempFactory()); 196 cananian 1.1.2.3 // create new RuntimeException object. 197 cananian 1.1.2.3 Quad q0 = new NEW(qf, src, t0, HCrex); 198 cananian 1.1.2.3 // initialize it. 199 cananian 1.1.2.3 Quad q1 = new CALL(qf, src, HCrex.getConstructor(new HClass[0]), 200 cananian 1.1.2.3 new Temp[] { t0 }, null, t1, false, false, 201 cananian 1.1.2.3 new Temp[0]); 202 cananian 1.1.2.3 // merge all exceptions from call 203 cananian 1.1.2.3 Quad q2 = new PHI(qf, src, new Temp[] { t2 }, 204 cananian 1.1.2.3 new Temp[][] { new Temp[] { t0, t1 } }, 2); 205 cananian 1.1.2.3 // throw! 206 cananian 1.1.2.3 Quad q3 = new THROW(qf, src, t2); 207 cananian 1.1.2.3 // link everything together. 208 cananian 1.1.2.3 Quad.addEdges(new Quad[] { method, q0, q1, q2, q3 }); 209 cananian 1.1.2.3 Quad.addEdge(q1, 1, q2, 1); 210 cananian 1.1.2.3 footer = footer.attach(q3, 0); 211 cananian 1.1.2.3 return hc; 212 cananian 1.1.2.3 } 213 cananian 1.1.2.3 214 cananian 1.1.2.1 // Deal with the fact that external Byte/Short/Char/Boolean classes 215 cananian 1.1.2.1 // are represented internally as ints. 216 cananian 1.1.2.1 static HClass toInternal(HClass c) { 217 cananian 1.1.2.1 if (c.equals(HClass.Byte) || c.equals(HClass.Short) || 218 cananian 1.1.2.1 c.equals(HClass.Char) || c.equals(HClass.Boolean)) 219 cananian 1.1.2.1 return HClass.Int; 220 cananian 1.1.2.1 return c; 221 cananian 1.1.2.1 } 222 cananian 1.1.2.1 // wrapper to redirect maps through the hcodeandmaps 223 cananian 1.5 class Wrapper implements ExactTypeMap<Quad>, ConstMap<Quad>, ExecMap<Quad>{ 224 cananian 1.5 final Map<Quad,Quad> aem; final TempMap atm; 225 cananian 1.5 Wrapper(HCodeAndMaps<Quad> hcam) { 226 cananian 1.1.2.1 this.aem = hcam.ancestorElementMap(); 227 cananian 1.1.2.1 this.atm = hcam.ancestorTempMap(); 228 cananian 1.1.2.1 } 229 cananian 1.5 Quad map(Quad hce) { 230 cananian 1.5 return aem.get(hce); 231 cananian 1.1.2.1 } 232 cananian 1.1.2.1 Temp map(Temp t) { return atm.tempMap(t); } 233 cananian 1.1.2.1 // ExactTypeMap 234 cananian 1.5 public boolean isExactType(Quad hce, Temp t) { 235 cananian 1.1.2.1 return bwa.isExactType(map(hce), map(t)); 236 cananian 1.1.2.1 } 237 cananian 1.1.2.1 // TypeMap 238 cananian 1.5 public HClass typeMap(Quad hce, Temp t) { 239 cananian 1.1.2.1 return bwa.typeMap(map(hce), map(t)); 240 cananian 1.1.2.1 } 241 cananian 1.1.2.1 // ConstMap 242 cananian 1.5 public boolean isConst(Quad hce, Temp t) { 243 cananian 1.1.2.1 return bwa.isConst(map(hce), map(t)); 244 cananian 1.1.2.1 } 245 cananian 1.5 public Object constMap(Quad hce, Temp t) { 246 cananian 1.1.2.1 return bwa.constMap(map(hce), map(t)); 247 cananian 1.1.2.1 } 248 cananian 1.1.2.1 // ExecMap 249 cananian 1.5 public boolean execMap(Quad hce) { 250 cananian 1.1.2.1 if (hce instanceof HEADER || hce instanceof FOOTER) return true; 251 cananian 1.1.2.1 return bwa.execMap(map(hce)); 252 cananian 1.1.2.1 } 253 cananian 1.5 public boolean execMap(HCodeEdge<Quad> edge) { 254 cananian 1.1.2.1 Edge e = (Edge) edge; 255 cananian 1.1.2.1 if (e.from() instanceof HEADER) return true; 256 cananian 1.5 Edge ne = map(e.from()).nextEdge(e.which_succ()); 257 cananian 1.1.2.1 return bwa.execMap(ne); 258 cananian 1.1.2.1 } 259 cananian 1.1.2.1 } 260 cananian 1.2 }