KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > just4log > transform > Transform


1 /*
2  * ============================================================================
3  * The Apache Software License, Version 1.1
4  * ============================================================================
5  *
6  * Copyright (C) 2000-2003 Lucas Bruand. All
7  * rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "Just4Log" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  *
45  * This software consists of voluntary contributions made by many individuals
46  * on behalf of the Apache Software Foundation. For more information on the
47  * Apache Software Foundation, please see <http://www.apache.org/>.
48  *
49  */

50 package net.sf.just4log.transform;
51
52 import java.util.Iterator JavaDoc;
53 import java.util.LinkedList JavaDoc;
54
55 import net.sf.just4log.NoMatchingInvokeInterfaceInstruction;
56
57 import org.apache.bcel.classfile.Field;
58 import org.apache.bcel.classfile.JavaClass;
59 import org.apache.bcel.classfile.Method;
60 import org.apache.bcel.generic.ClassGen;
61 import org.apache.bcel.generic.ConstantPoolGen;
62 import org.apache.bcel.generic.GETSTATIC;
63 import org.apache.bcel.generic.Instruction;
64 import org.apache.bcel.generic.InstructionFactory;
65 import org.apache.bcel.generic.InstructionHandle;
66 import org.apache.bcel.generic.InstructionList;
67 import org.apache.bcel.generic.InvokeInstruction;
68 import org.apache.bcel.generic.MethodGen;
69 import org.apache.bcel.generic.ObjectType;
70 import org.apache.bcel.generic.ReturnInstruction;
71 import org.apache.bcel.generic.Type;
72 import org.apache.commons.logging.Log;
73 import org.apache.commons.logging.LogFactory;
74
75 /**
76  * @author Lucas Bruand
77  */

78
79 public abstract class Transform {
80     private static Log logger = LogFactory.getLog(Transform.class);
81     private static String JavaDoc CLASSID =
82         "$Id: Transform.java,v 1.15 2003/09/23 21:21:15 lbruand Exp $";
83
84     static {
85         ApacheCommonTransform.register();
86         Log4jTransform.register();
87         LogJDK14Transform.register();
88     }
89
90     InstructionFactory instFact;
91     private String JavaDoc classname;
92
93     /**
94      *
95      */

96     public Transform() {
97         super();
98     }
99
100     private static LinkedList JavaDoc transmap;
101     public static void register(Transform trans) {
102         if (transmap == null) {
103             transmap = new LinkedList JavaDoc();
104         }
105
106         synchronized (transmap) {
107             transmap.add(trans);
108         }
109
110     }
111
112     public static Transform getTransformationForJavaClass(
113         JavaClass claz,
114         ConstantPoolGen cp) {
115         Field[] fields = claz.getFields();
116         ObjectType fieldType;
117         Transform t;
118         for (int i = 0; i < fields.length; i++) {
119
120             try {
121                 fieldType = (ObjectType) fields[i].getType();
122             } catch (ClassCastException JavaDoc ex) {
123                 continue;
124             }
125             for (Iterator JavaDoc j = transmap.iterator(); j.hasNext();) {
126                 t = (Transform) j.next();
127                 if (fieldType.equals(t.getLogType())
128                     || fieldType.isCastableTo(t.getLogType())) {
129                     logger.info(
130                         "Found logger attribute: "
131                             + fieldType
132                             + " "
133                             + fields[i].getName());
134                     t.init(claz, fields[i], cp);
135                     return t;
136                 }
137             }
138
139         }
140         return null;
141     }
142     JavaClass clazz;
143     Field loggerAttribute;
144     public void init(JavaClass clazz, Field logger, ConstantPoolGen cp) {
145         this.clazz = clazz;
146         this.loggerAttribute = logger;
147         this.instFact = new InstructionFactory(cp);
148     }
149     public void done() {
150         this.loggerAttribute = null;
151         this.instFact = null;
152     }
153     public abstract InstructionHandle insertFork(
154         InstructionList il,
155         InstructionHandle getStaticHandle,
156         InstructionHandle invokeHandle,
157         ConstantPoolGen cp);
158
159     public abstract InstructionHandle insertEnter(
160         MethodGen orig,
161         InstructionList il,
162         InstructionHandle firstInstructionHandle,
163         ConstantPoolGen cp);
164
165     public abstract InstructionHandle insertExit(
166         MethodGen orig,
167         InstructionList il,
168         InstructionHandle returnInstructionHandle,
169         ConstantPoolGen cp);
170
171     public void transform(
172         MethodGen mg,
173         InstructionList il,
174         InstructionHandle handle,
175         ConstantPoolGen cp)
176         throws NoMatchingInvokeInterfaceInstruction {
177
178         logger.info("Found a logger instruction.");
179         InstructionHandle lastLogHandle = handle;
180
181         InvokeInstruction invokeInterface = null;
182         Instruction inst = null;
183         while (true) {
184             handle = handle.getNext();
185             if (handle == null) {
186                 logger.warn("No matching invokeInterface found.");
187                 throw new NoMatchingInvokeInterfaceInstruction("No matching invokeInterface found.");
188             }
189             inst = handle.getInstruction();
190             if (inst instanceof InvokeInstruction) {
191                 invokeInterface = (InvokeInstruction) inst;
192                 if (invokeInterface.getClassType(cp).equals(getLogType())) {
193                     logger.info("Found matching invokeInstruction.");
194                     if (level_logs == FORKLOGS) {
195                         InstructionHandle insertHandle =
196                             insertFork(il, lastLogHandle, handle, cp);
197                         if (insertHandle != null) {
198                             il.redirectBranches(lastLogHandle, insertHandle);
199                             il.redirectExceptionHandlers(
200                                 mg.getExceptionHandlers(),
201                                 lastLogHandle,
202                                 insertHandle);
203                             il.redirectLocalVariables(
204                                 mg.getLocalVariables(),
205                                 lastLogHandle,
206                                 insertHandle);
207                         }
208                     }
209
210                     break;
211                 }
212             }
213         }
214     }
215
216     /**
217      * This optimizes a method in particular.
218      * @param orig The original method to optimize.
219      * @param mg The MethodGen that is going to be used as a basis for generation.
220      * @param cp The ConstantPool that is going to be used as a basis for generation. This is going to be modified.
221      * @return the new optimized method.
222      * @throws NoMatchingInvokeInterfaceInstruction
223      */

224     public Method speedup(Method orig, MethodGen mg, ConstantPoolGen cp)
225         throws NoMatchingInvokeInterfaceInstruction {
226         logger.info("Entry speedup(Method " + mg.getName() + ")");
227         if (orig.getName().equals("<clinit>")
228             || orig.getName().equals("<init>")
229             || orig.getName().equals("class$")) {
230             logger.info(
231                 "This method "
232                     + mg.getName()
233                     + " is a special method and won't be modified.");
234             return orig;
235         }
236         InstructionList il = null;
237         InstructionHandle handle = null;
238         Instruction inst = null;
239
240         GETSTATIC getStatic = null;
241
242         Method m = null;
243
244         try {
245             il = mg.getInstructionList();
246             handle = il.getStart();
247             if (level_enters == SIMPLEENTER) {
248
249                 insertEnter(mg, il, handle, cp);
250                 insertFork(il, il.getStart(), handle.getPrev(), cp);
251             }
252
253             for (; handle != null; handle = handle.getNext()) {
254                 inst = handle.getInstruction();
255                 logger.info("next instruction: " + inst);
256                 if (level_exits == SIMPLEEXIT
257                     && inst instanceof ReturnInstruction) {
258                     InstructionHandle lastLogHandle = handle;
259                     logger.info(
260                         "Found a ReturnInstruction of type: "
261                             + inst.toString());
262                     int stackSize =
263                         inst.consumeStack(cp) - inst.produceStack(cp);
264                     while (stackSize != 0) {
265                         handle = handle.getPrev();
266                         inst = handle.getInstruction();
267                         logger.info("prev instruction: " + inst);
268                         stackSize += inst.consumeStack(cp)
269                             - inst.produceStack(cp);
270                     }
271
272                     InstructionHandle insertHandle =
273                         insertExit(mg, il, handle, cp);
274                     if (insertHandle != null) {
275                         // We need to redirect branches etc.... twice
276
// so that the if fork doesn't get erroneous modified.
277
il.redirectBranches(handle, insertHandle);
278                         il.redirectExceptionHandlers(
279                             mg.getExceptionHandlers(),
280                             handle,
281                             insertHandle);
282                         il.redirectLocalVariables(
283                             mg.getLocalVariables(),
284                             handle,
285                             insertHandle);
286                         handle =
287                             insertFork(il, insertHandle, handle.getPrev(), cp);
288                         il.redirectBranches(insertHandle, handle );
289                         il.redirectExceptionHandlers(
290                             mg.getExceptionHandlers(),
291                             insertHandle,
292                             handle);
293                         il.redirectLocalVariables(
294                             mg.getLocalVariables(),
295                             insertHandle,
296                             handle);
297                     }
298
299                     handle = lastLogHandle;
300                 }
301                 if (inst instanceof GETSTATIC) {
302                     getStatic = (GETSTATIC) inst;
303                     Type type = getStatic.getFieldType(cp);
304                     logger.info(
305                         "Found a GETSTATIC instruction of type: "
306                             + type.toString());
307
308                     if (getStatic
309                         .getFieldName(cp)
310                         .equals(loggerAttribute.getName())) {
311                         logger.info("This is a logger access");
312                         transform(mg, il, handle, cp);
313                     }
314                 }
315             }
316             if (orig.getLineNumberTable() == null) {
317                 logger.info("Removing line numbers");
318                 mg.removeLineNumbers();
319             }
320             if (orig.getLocalVariableTable() == null) {
321                 logger.info("Removing Local variables table");
322                 mg.removeLocalVariables();
323             }
324             m = mg.getMethod();
325         } finally {
326
327             il.dispose();
328         }
329         return m;
330     }
331     /**
332      * This method transforms a not optimized JavaClass into a new Log-optimised
333      * JavaClass
334      * @param source the JavaClass to optimize.
335      * @return the optimized JavaClass
336      */

337     public static JavaClass speedup(JavaClass source) {
338         try {
339             logger.info("Entry speedup(JavaClass)");
340             ClassGen cg = new ClassGen(source);
341             Method[] methods = cg.getMethods();
342             ConstantPoolGen cp = cg.getConstantPool();
343
344             Transform trans = getTransformationForJavaClass(source, cp);
345             if (trans == null) {
346                 logger.warn(
347                     "No transformer found for class " + source.getClassName());
348                 return source;
349             }
350             for (int i = 0; i < methods.length; i++) {
351                 if (!(methods[i].isAbstract() || methods[i].isNative())) {
352                     MethodGen mg =
353                         new MethodGen(methods[i], source.getClassName(), cp);
354                     Method stripped = trans.speedup(methods[i], mg, cp);
355                     if (stripped != null)
356                         cg.replaceMethod(methods[i], stripped);
357                 }
358             }
359             trans.done();
360             JavaClass target = cg.getJavaClass();
361             target.setFileName(source.getFileName());
362             return target;
363         } catch (Exception JavaDoc e) {
364             e.printStackTrace();
365         }
366         return source;
367
368     }
369     public static String JavaDoc getMethodRepr(MethodGen mg) {
370         StringBuffer JavaDoc sb =
371             new StringBuffer JavaDoc(mg.getReturnType() + " " + mg.getName() + "(");
372         Type[] types = mg.getArgumentTypes();
373         for (int i = 0; i < types.length; i++) {
374             if (i != 0) {
375                 sb.append(", ");
376             }
377             sb.append(types[i].toString());
378         }
379         sb.append(")");
380         logger.info("Method representation to enter: " + sb.toString());
381         return sb.toString();
382     }
383     /**
384      * @return
385      */

386     public abstract ObjectType getLogType();
387
388     public static final int NOEXIT = 0;
389     public static final int SIMPLEEXIT = 1;
390     public static final int PARAMETEREXIT = 2;
391
392     public static int level_exits = NOEXIT;
393
394     public static final int REMOVELOGS = 0;
395     public static final int LEAVELOGS = 1;
396     public static final int FORKLOGS = 2;
397     public static int level_logs = FORKLOGS;
398
399     public static final int NOENTER = 0;
400     public static final int SIMPLEENTER = 1;
401     public static final int PARAMETERENTER = 2;
402     public static int level_enters = NOENTER;
403     public static final String JavaDoc ENTER_STRING = "enters: ";
404     public static final String JavaDoc EXIT_STRING = "exits: ";
405 }
406
Popular Tags