1 cananian 1.1.2.3 // ClassReplacer.java, created Fri Mar 23 10:31:56 2001 by wbeebee 2 wbeebee 1.1.2.1 // Copyright (C) 2000 Wes Beebee <wbeebee@mit.edu> 3 wbeebee 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 wbeebee 1.1.2.1 package harpoon.Analysis.Realtime; 5 wbeebee 1.1.2.1 6 wbeebee 1.1.2.1 import java.io.PrintWriter; 7 wbeebee 1.1.2.1 8 wbeebee 1.1.2.1 import java.util.HashMap; 9 wbeebee 1.1.2.1 import java.util.HashSet; 10 wbeebee 1.1.2.1 import java.util.Iterator; 11 wbeebee 1.1.2.1 import java.util.Set; 12 wbeebee 1.1.2.1 13 wbeebee 1.1.2.1 import harpoon.Analysis.ClassHierarchy; 14 wbeebee 1.1.2.1 import harpoon.Analysis.Transformation.MethodMutator; 15 wbeebee 1.1.2.1 16 wbeebee 1.1.2.1 import harpoon.ClassFile.HClass; 17 wbeebee 1.1.2.1 import harpoon.ClassFile.HCode; 18 wbeebee 1.1.2.1 import harpoon.ClassFile.HCodeAndMaps; 19 wbeebee 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 20 wbeebee 1.1.2.1 import harpoon.ClassFile.HConstructor; 21 wbeebee 1.1.2.1 import harpoon.ClassFile.HMethod; 22 wbeebee 1.1.2.1 import harpoon.ClassFile.Linker; 23 wbeebee 1.1.2.1 24 wbeebee 1.1.2.1 import harpoon.IR.Quads.CALL; 25 wbeebee 1.1.2.1 import harpoon.IR.Quads.NEW; 26 wbeebee 1.1.2.1 import harpoon.IR.Quads.Quad; 27 wbeebee 1.1.2.1 import harpoon.IR.Quads.QuadVisitor; 28 wbeebee 1.1.2.1 import harpoon.IR.Quads.QuadWithTry; 29 wbeebee 1.1.2.2 import harpoon.IR.Quads.QuadNoSSA; 30 wbeebee 1.1.2.1 31 cananian 1.7 import net.cscott.jutil.SnapshotIterator; 32 cananian 1.6 33 wbeebee 1.1.2.1 import harpoon.Util.Util; 34 wbeebee 1.1.2.1 35 wbeebee 1.1.2.1 /** 36 wbeebee 1.1.2.1 * <code>ClassReplacer</code> is a <code>MethodMutator</code> which 37 wbeebee 1.1.2.1 * works on any QuadForm and replaces NEW's and CALL's to one class with 38 wbeebee 1.1.2.1 * NEW's and CALL's to another class using a mapping function to map methods 39 wbeebee 1.1.2.1 * of one to methods of the other. It can also ignore (not update) listed 40 wbeebee 1.1.2.1 * classes or packages. This class allows you to write a wrapper for a 41 wbeebee 1.1.2.1 * class for which you don't have the code, and have other code selectively 42 wbeebee 1.1.2.1 * point to the wrapper. 43 wbeebee 1.1.2.2 * 44 wbeebee 1.1.2.2 * Currently, only QuadNoSSA and QuadWithTry are supported. This may change 45 wbeebee 1.1.2.2 * in the future. 46 wbeebee 1.1.2.1 */ 47 wbeebee 1.1.2.1 48 wbeebee 1.1.2.1 public class ClassReplacer extends MethodMutator { 49 wbeebee 1.1.2.1 private HashMap methodMap; 50 wbeebee 1.1.2.1 private HClass fromClass, toClass; 51 wbeebee 1.1.2.1 private Set ignorePackages; 52 wbeebee 1.1.2.1 private Set ignoreClasses; 53 wbeebee 1.1.2.1 private String codeName; 54 wbeebee 1.1.2.1 private static final boolean debugOutput = false; 55 wbeebee 1.1.2.1 56 wbeebee 1.1.2.1 /** 57 wbeebee 1.1.2.1 * Construct a <code>ClassReplacer</code> with an <code>HCodeFactory</code> 58 wbeebee 1.1.2.1 * that will replace the <code>HClass</code> <code>from</code> with 59 wbeebee 1.1.2.1 * <code>to</code>. 60 wbeebee 1.1.2.1 */ 61 wbeebee 1.1.2.1 62 wbeebee 1.1.2.1 public ClassReplacer(HCodeFactory parent, HClass from, HClass to) { 63 wbeebee 1.1.2.1 super(parent); 64 wbeebee 1.1.2.1 fromClass = from; 65 wbeebee 1.1.2.1 toClass = to; 66 wbeebee 1.1.2.1 methodMap = new HashMap(); 67 wbeebee 1.1.2.1 ignorePackages = new HashSet(); 68 wbeebee 1.1.2.1 ignoreClasses = new HashSet(); 69 wbeebee 1.1.2.1 codeName = parent.getCodeName(); 70 cananian 1.3.2.1 assert codeName.equals(QuadWithTry.codename)|| 71 cananian 1.3.2.1 codeName.equals(QuadNoSSA.codename) : ("currently only QuadWithTry and QuadNoSSA are supported: " + 72 wbeebee 1.1.2.2 codeName + " cannot be used as a parent for a ClassReplacer"); 73 wbeebee 1.1.2.1 } 74 wbeebee 1.1.2.1 75 wbeebee 1.1.2.1 /** 76 wbeebee 1.1.2.1 * Do not replace references to <code>from</code> in the package 77 wbeebee 1.1.2.1 * <code>pkg</code>. 78 wbeebee 1.1.2.1 */ 79 wbeebee 1.1.2.1 80 wbeebee 1.1.2.1 public void addIgnorePackage(String pkg) { 81 wbeebee 1.1.2.1 ignorePackages.add(pkg); 82 wbeebee 1.1.2.1 } 83 wbeebee 1.1.2.1 84 wbeebee 1.1.2.1 /** 85 wbeebee 1.1.2.1 * Do not replace references to <code>from</code> in the class 86 wbeebee 1.1.2.1 * <code>claz</code>. <code>from</code> is automatically ignored. 87 wbeebee 1.1.2.1 */ 88 wbeebee 1.1.2.1 89 wbeebee 1.1.2.1 public void addIgnoreClasses(HClass claz) { 90 wbeebee 1.1.2.1 ignoreClasses.add(claz); 91 wbeebee 1.1.2.1 } 92 wbeebee 1.1.2.1 93 wbeebee 1.1.2.1 /** 94 wbeebee 1.1.2.1 * Map a method on the original class to a method on the "to" class. 95 wbeebee 1.1.2.1 * Only mapped method referencesd will be replaced. 96 wbeebee 1.1.2.1 */ 97 wbeebee 1.1.2.1 98 wbeebee 1.1.2.1 public void map(HMethod from, HMethod to) { 99 cananian 1.3.2.1 assert from.getReturnType() == to.getReturnType(); 100 wbeebee 1.1.2.1 101 wbeebee 1.1.2.1 HClass[] types = from.getParameterTypes(); 102 wbeebee 1.1.2.1 HClass[] types2 = to.getParameterTypes(); 103 wbeebee 1.1.2.1 104 wbeebee 1.1.2.1 for (int i=0; i<types.length; i++) { 105 cananian 1.3.2.1 assert types[i].equals(types2[i]); 106 wbeebee 1.1.2.1 } 107 wbeebee 1.1.2.1 108 wbeebee 1.1.2.1 methodMap.put(from, to); 109 wbeebee 1.1.2.1 } 110 wbeebee 1.1.2.1 111 wbeebee 1.1.2.1 /** 112 wbeebee 1.1.2.1 * Map all of the methods from <code>HClass<code> <code>from</code> 113 wbeebee 1.1.2.1 * to <code>to</code> that share the same name and method signature. 114 wbeebee 1.1.2.1 * Warning: slow for big classes. 115 wbeebee 1.1.2.1 */ 116 wbeebee 1.1.2.1 117 wbeebee 1.1.2.1 public void mapAll(HClass from, HClass to) { 118 wbeebee 1.1.2.1 HMethod[] fromMethods = from.getMethods(); 119 wbeebee 1.1.2.1 HMethod[] toMethods = to.getMethods(); 120 wbeebee 1.1.2.1 for (int i=0; i<fromMethods.length; i++) { 121 wbeebee 1.1.2.1 HClass[] types = fromMethods[i].getParameterTypes(); 122 wbeebee 1.1.2.1 for (int j=0; j<toMethods.length; j++) { 123 wbeebee 1.1.2.1 HClass[] types2 = toMethods[j].getParameterTypes(); 124 wbeebee 1.1.2.1 if (fromMethods[i].getReturnType() 125 wbeebee 1.1.2.1 .equals(toMethods[j].getReturnType())&& 126 wbeebee 1.1.2.1 (types.length == types2.length)&& 127 wbeebee 1.5 fromMethods[i].getName().equals(toMethods[j].getName())&& 128 wbeebee 1.5 (!fromMethods[i].getDeclaringClass().equals(toMethods[j].getDeclaringClass()))) { 129 wbeebee 1.1.2.1 boolean mapMethod = true; 130 wbeebee 1.1.2.1 for (int k=0; k<types.length; k++) { 131 wbeebee 1.1.2.1 if (!types[k].equals(types2[k])) { 132 wbeebee 1.1.2.1 mapMethod = false; 133 wbeebee 1.1.2.1 break; 134 wbeebee 1.1.2.1 } 135 wbeebee 1.1.2.1 } 136 wbeebee 1.1.2.1 137 wbeebee 1.1.2.1 if (mapMethod) { 138 wbeebee 1.1.2.1 if (debugOutput) { 139 wbeebee 1.1.2.1 System.out.println("Mapping methods: " + 140 wbeebee 1.1.2.1 fromMethods[i].toString() + 141 wbeebee 1.1.2.1 " to: " + toMethods[j].toString()); 142 wbeebee 1.1.2.1 } 143 wbeebee 1.1.2.1 methodMap.put(fromMethods[i], toMethods[j]); 144 wbeebee 1.1.2.1 } 145 wbeebee 1.1.2.1 } 146 wbeebee 1.1.2.1 } 147 wbeebee 1.1.2.1 } 148 wbeebee 1.1.2.1 } 149 wbeebee 1.1.2.1 150 wbeebee 1.1.2.1 /** 151 wbeebee 1.1.2.2 * Get the <code>QuadVisitor</code> that will make the replacements to the code, 152 wbeebee 1.1.2.2 * parameterized by <code>codeName</code>. Currently only <code>QuadNoSSA</code> and 153 wbeebee 1.1.2.2 * <code>QuadWithTry</code> are supported. Change this method if you want to 154 wbeebee 1.1.2.2 * support more. 155 wbeebee 1.1.2.1 */ 156 wbeebee 1.1.2.1 157 wbeebee 1.1.2.1 private QuadVisitor getQuadVisitor(final String codeName) { 158 wbeebee 1.1.2.1 final HClass from = fromClass; 159 wbeebee 1.1.2.1 final HClass to = toClass; 160 wbeebee 1.1.2.1 return new QuadVisitor() { 161 wbeebee 1.1.2.1 public void visit(CALL q) { 162 wbeebee 1.1.2.1 HMethod method = q.method(); 163 wbeebee 1.1.2.1 HClass claz = method.getDeclaringClass(); 164 wbeebee 1.1.2.1 165 wbeebee 1.5 if ((claz == to) || // Current class automatically on 166 wbeebee 1.1.2.1 // ignore list. 167 wbeebee 1.5 (!methodMap.containsKey(method))) return; 168 wbeebee 1.1.2.1 169 wbeebee 1.1.2.1 CALL newCALL = 170 wbeebee 1.1.2.1 new CALL(q.getFactory(), q, 171 wbeebee 1.1.2.1 (HMethod)methodMap.get(method), 172 wbeebee 1.1.2.1 q.params(), q.retval(), q.retex(), 173 wbeebee 1.1.2.1 q.isVirtual(), q.isTailCall(), 174 wbeebee 1.1.2.1 q.dst(), q.src()); 175 wbeebee 1.5 if (debugOutput) { 176 wbeebee 1.5 System.out.println("Replacing "+q+" with "+newCALL); 177 wbeebee 1.5 } 178 wbeebee 1.1.2.1 Quad.replace(q, newCALL); 179 wbeebee 1.1.2.1 if (codeName.equals(QuadWithTry.codename)) { 180 wbeebee 1.1.2.1 Quad.transferHandlers(q, newCALL); 181 wbeebee 1.1.2.1 } 182 wbeebee 1.1.2.1 } 183 wbeebee 1.1.2.1 184 wbeebee 1.1.2.1 public void visit(NEW q) { 185 wbeebee 1.1.2.1 186 wbeebee 1.1.2.1 if (q.hclass() != from) { 187 wbeebee 1.1.2.1 return; 188 wbeebee 1.1.2.1 } 189 wbeebee 1.1.2.1 190 wbeebee 1.1.2.1 NEW newNEW = new NEW(q.getFactory(), 191 wbeebee 1.1.2.1 q, q.dst(), to); 192 wbeebee 1.5 if (debugOutput) { 193 wbeebee 1.5 System.out.println("Replacing "+q+" with "+newNEW); 194 wbeebee 1.5 } 195 wbeebee 1.1.2.1 Quad.replace(q, newNEW); 196 wbeebee 1.1.2.1 if (codeName.equals(QuadWithTry.codename)) { 197 wbeebee 1.1.2.1 Quad.transferHandlers(q, newNEW); 198 wbeebee 1.1.2.1 } 199 wbeebee 1.1.2.1 } 200 wbeebee 1.1.2.1 201 wbeebee 1.1.2.1 public void visit(Quad q) {} 202 wbeebee 1.1.2.1 }; 203 wbeebee 1.1.2.1 } 204 wbeebee 1.1.2.1 205 wbeebee 1.1.2.1 /** 206 wbeebee 1.1.2.1 * Make the actual changes to the HCode. 207 wbeebee 1.1.2.1 */ 208 wbeebee 1.1.2.1 209 wbeebee 1.1.2.1 protected HCode mutateHCode(HCodeAndMaps input) { 210 wbeebee 1.1.2.1 HCode hc = input.hcode(); 211 wbeebee 1.1.2.1 HClass hclass = hc.getMethod().getDeclaringClass(); 212 wbeebee 1.1.2.1 if ((hc == null)|| 213 wbeebee 1.1.2.1 (ignoreClasses.contains(hclass))|| 214 wbeebee 1.1.2.1 (ignorePackages.contains(hclass.getPackage()))) { 215 wbeebee 1.1.2.1 return hc; 216 wbeebee 1.1.2.1 } 217 wbeebee 1.1.2.1 218 wbeebee 1.1.2.1 QuadVisitor visitor = getQuadVisitor(codeName); 219 wbeebee 1.1.2.1 220 wbeebee 1.1.2.1 if (debugOutput) { 221 wbeebee 1.5 System.out.println("Before replacing " + fromClass.getName() + 222 wbeebee 1.5 " with " + toClass.getName() + ":"); 223 wbeebee 1.5 hc.print(new PrintWriter(System.out)); 224 wbeebee 1.1.2.1 } 225 wbeebee 1.1.2.1 226 cananian 1.6 // note that we use a SnapshotIterator so that qi is 'static'; 227 cananian 1.6 // i.e. the underlying list of elements to iterate over does not 228 cananian 1.6 // change as the visitor mutates the hcode. 229 cananian 1.6 Iterator qi = new SnapshotIterator(hc.getElementsI()); 230 wbeebee 1.5 while (qi.hasNext()) ((Quad)(qi.next())).accept(visitor); 231 wbeebee 1.1.2.1 232 wbeebee 1.1.2.1 if (debugOutput) { 233 wbeebee 1.5 System.out.println("After replacing " + fromClass.getName() + 234 wbeebee 1.5 " with " + toClass.getName() + ":"); 235 wbeebee 1.5 hc.print(new PrintWriter(System.out)); 236 wbeebee 1.1.2.1 } 237 wbeebee 1.1.2.1 return hc; 238 wbeebee 1.1.2.1 } 239 cananian 1.2 }