1 /* MethodTransformer.java */
2 package org.quilt.cl;
3
4 import java.util.Hashtable;
5 import java.util.List;
6
7 import org.apache.bcel.classfile.*;
8 import org.apache.bcel.Constants;
9 import org.apache.bcel.generic.*;
10 import org.quilt.graph.*;
11
12 /***
13 * Optionally preprocesses a method, optionally transforms
14 * its control flow graph, optionally postprocesses it. The list of
15 * preprocessors is applied in forward order before graph transformation.
16 * The corresponding list of postprocessors is applied in reverse order
17 * after graph transformation.
18 *
19 * @author <a href="jddixon@users.sourceforge.net">Jim Dixon</a>
20 */
21 public class MethodTransformer {
22
23 /*** For passing application-specific data. XXX Not used, probably
24 * best dropped. */
25 private Hashtable methodHash = new Hashtable();
26
27 /*** Ordered list of method pre- and post-processors.*/
28 private List mxf;
29
30 /*** Graph processors. */
31 private List gxf;
32
33 /*** Main graph processor. */
34 private GraphTransformer xformer;
35
36 /***
37 * Sets up method transformer, saving MethodXformer vector here
38 * and passing GraphXformer vector to that transformer.
39 */
40 public MethodTransformer( List mxf, List gxf) {
41 this.mxf = mxf;
42 this.gxf = gxf;
43 xformer = new GraphTransformer (gxf);
44 }
45
46 /***
47 * Get a reference to the hash used to share data between this
48 * and other transformers.
49 */
50 public Hashtable getMethodHash() {
51 return methodHash;
52 }
53 /***
54 * Zero out a badly-behaved method Xformer.
55 * @param mxf The tranformer being killed.
56 * @param e The exception responsible.
57 */
58 private void zapMethodXformer ( MethodXformer mxf, Exception e) {
59 System.err.println("WARNING: exception in "
60 + mxf.getName() + ": transformation will not be applied" );
61 e.printStackTrace();
62 mxf = null;
63 }
64 /***
65 * <p>Transform a specific method, first applying preprocessors,
66 * then transforming the graph, then applying method postprocessors.</p>
67 *
68 * @param clazz The class to which the method belongs
69 * @param method The MethodGen being transformed.
70 */
71 public MethodGen xform ( ClassGen clazz, Method orig ) {
72 if (orig == null) {
73 throw new IllegalArgumentException("null method");
74 }
75 MethodGen method = new MethodGen (orig, clazz.getClassName(),
76 clazz.getConstantPool());
77 // New instances of the MethodXformers.
78 MethodXformer [] xf = new MethodXformer[ mxf.size() ];
79
80 // apply preprocessors in order
81 for (int i = 0; i < xf.length; i++) {
82 try {
83 xf[i] = (MethodXformer) (
84 (mxf.get(i)).getClass().newInstance() );
85 } catch (IllegalAccessException e) {
86 zapMethodXformer (xf[i], e);
87 } catch (InstantiationException e) {
88 zapMethodXformer (xf[i], e);
89 }
90 if (xf[i] != null && method != null) {
91 xf[i].preGraph (clazz, method);
92 }
93 }
94 // transform the graph
95 if (gxf.size() > 0 && method != null) {
96 InstructionList ilist = xformer.xform (clazz, method);
97 if (ilist == null) {
98 System.out.println("MethodTransformer.xformer: WARNING: "
99 + "xformer returned null instruction list");
100 return null;
101 }
102 // Quilt 0.5 approach, turns out to be unnecessary; the
103 // exception handlers are based on instruction handles,
104 // which in turn contain references to the method's instructions,
105 // which remain valid while the graph is being transformed.
106 //
107 // XXX But we may want to allow handlers to be added or changed.
108
109 method.removeExceptionHandlers(); // new ones come from graph
110
111 //checkAndSetPos(ilist);
112 ilist.setPositions(true);
113 method.setInstructionList (ilist);
114
115 CodeExceptionGen [] cgs = xformer.getExceptionHandlers();
116 for (int i = 0; i < cgs.length; i++) {
117 // DEBUG
118 System.out.println("adding exception " + i
119 + " to method " + method.getName()
120 + ": [" + cgs[i].getStartPC().getPosition()
121 + ".." + cgs[i].getEndPC().getPosition()
122 + "] --> " + cgs[i].getHandlerPC().getPosition()
123 );
124 // END
125
126 method.addExceptionHandler (
127 cgs[i].getStartPC(), cgs[i].getEndPC(),
128 cgs[i].getHandlerPC(), cgs[i].getCatchType() );
129 }
130 method.removeNOPs();
131 method.update(); // to be called after editing MethodGen
132 // during development, exceptions were thrown in setMaxStack
133 try {
134 method.setMaxStack();
135 method.setMaxLocals();
136 // method.stripAttributes(true); // Quilt 0.5 legacy
137 } catch (RuntimeException e) {
138 e.printStackTrace();
139 System.out.println("GraphTransformer.xformer:\n"
140 + " EXCEPTION finishing method " + e);
141 throw e;
142 }
143 // // DEBUG ONLY ///////////////////////////////////////////
144 // dumpIList (method, "after fixups");
145 // cgs = method.getExceptionHandlers();
146 // dumpExceptionHandlers(method, "after fixups", cgs.length);
147 // /////////////////////////////////////////////////////////
148 }
149
150 // apply postprocessors in reverse order
151 for (int i = xf.length-1; i >= 0; i--) {
152 if (xf[i] != null && method != null) {
153 xf[i].postGraph (clazz, method);
154 }
155 }
156 // IF THERE HAVE BEEN ANY FATAL ERRORS, SHOULD RETURN NULL
157 return method;
158 }
159 // UTILITY METHODS //////////////////////////////////////////////
160 void dumpExceptionHandlers (MethodGen method, String where, int len) {
161 CodeExceptionGen handlers[] = method.getExceptionHandlers();
162 if (handlers.length != len) {
163 System.out.println("EXPECTED " + len
164 + " exception handlers, found " + handlers.length);
165 }
166 if (handlers.length > 0) {
167 System.out.println("Exception handlers for method "
168 + method.getName() + " " + where + ":");
169
170 for (int j = 0; j < handlers.length; j++) {
171 System.out.println(" " + j
172 + ": [" + handlers[j].getStartPC().getPosition()
173 + ".." + handlers[j].getEndPC().getPosition()
174 + "] --> " + handlers[j].getHandlerPC().getPosition()
175 );
176 }
177 }
178 }
179 void dumpIList(MethodGen method, String where) {
180 InstructionList myList = method.getInstructionList();
181 System.out.println(
182 "MethodTransformer: instruction list " + where + ":");
183 int i = 0;
184 for (InstructionHandle ih = myList.getStart(); ih != null;
185 ih = ih.getNext() ) {
186 System.out.println( " " + (i++) + " " + ih);
187 }
188 }
189 }
This page was automatically generated by Maven