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 }