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     }