KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > expr > ExprEditor


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.expr;
17
18 import javassist.bytecode.*;
19 import javassist.CtClass;
20 import javassist.CannotCompileException;
21
22 /**
23  * A translator of method bodies.
24  *
25  * <p>The users can define a subclass of this class to customize how to
26  * modify a method body. The overall architecture is similar to the
27  * strategy pattern.
28  *
29  * <p>If <code>instrument()</code> is called in
30  * <code>CtMethod</code>, the method body is scanned from the beginning
31  * to the end.
32  * Whenever an expression, such as a method call and a <tt>new</tt>
33  * expression (object creation),
34  * is found, <code>edit()</code> is called in <code>ExprEdit</code>.
35  * <code>edit()</code> can inspect and modify the given expression.
36  * The modification is reflected on the original method body. If
37  * <code>edit()</code> does nothing, the original method body is not
38  * changed.
39  *
40  * <p>The following code is an example:
41  *
42  * <ul><pre>
43  * CtMethod cm = ...;
44  * cm.instrument(new ExprEditor() {
45  * public void edit(MethodCall m) throws CannotCompileException {
46  * if (m.getClassName().equals("Point")) {
47  * System.out.println(m.getMethodName() + " line: "
48  * + m.getLineNumber());
49  * }
50  * });
51  * </pre></ul>
52  *
53  * <p>This code inspects all method calls appearing in the method represented
54  * by <code>cm</code> and it prints the names and the line numbers of the
55  * methods declared in class <code>Point</code>. This code does not modify
56  * the body of the method represented by <code>cm</code>. If the method
57  * body must be modified, call <code>replace()</code>
58  * in <code>MethodCall</code>.
59  *
60  * @see javassist.CtClass#instrument(ExprEditor)
61  * @see javassist.CtMethod#instrument(ExprEditor)
62  * @see javassist.CtConstructor#instrument(ExprEditor)
63  * @see MethodCall
64  * @see NewExpr
65  * @see FieldAccess
66  *
67  * @see javassist.CodeConverter
68  */

69 public class ExprEditor {
70     /**
71      * Default constructor. It does nothing.
72      */

73     public ExprEditor() {}
74
75     static class NewOp {
76         NewOp next;
77         int pos;
78         String JavaDoc type;
79
80         NewOp(NewOp n, int p, String JavaDoc t) {
81             next = n;
82             pos = p;
83             type = t;
84         }
85     }
86
87     /**
88      * Undocumented method. Do not use; internal-use only.
89      */

90     public boolean doit(CtClass clazz, MethodInfo minfo)
91         throws CannotCompileException
92     {
93         CodeAttribute codeAttr = minfo.getCodeAttribute();
94         if (codeAttr == null)
95             return false;
96
97         CodeIterator iterator = codeAttr.iterator();
98         boolean edited = false;
99         int maxLocals = codeAttr.getMaxLocals();
100         int maxStack = 0;
101
102         NewOp newList = null;
103         ConstPool cp = minfo.getConstPool();
104
105         while (iterator.hasNext())
106             try {
107                 Expr expr = null;
108                 int pos = iterator.next();
109                 int c = iterator.byteAt(pos);
110
111                 if (c < Opcode.GETSTATIC) // c < 178
112
/* skip */;
113                 else if (c < Opcode.NEWARRAY) { // c < 188
114
if (c == Opcode.INVOKESTATIC
115                         || c == Opcode.INVOKEINTERFACE
116                         || c == Opcode.INVOKEVIRTUAL) {
117                         expr = new MethodCall(pos, iterator, clazz, minfo);
118                         edit((MethodCall)expr);
119                     }
120                     else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC
121                              || c == Opcode.PUTFIELD
122                              || c == Opcode.PUTSTATIC) {
123                         expr = new FieldAccess(pos, iterator, clazz, minfo, c);
124                         edit((FieldAccess)expr);
125                     }
126                     else if (c == Opcode.NEW) {
127                         int index = iterator.u16bitAt(pos + 1);
128                         newList = new NewOp(newList, pos,
129                                             cp.getClassInfo(index));
130                     }
131                     else if (c == Opcode.INVOKESPECIAL) {
132                         if (newList != null && cp.isConstructor(newList.type,
133                                 iterator.u16bitAt(pos + 1)) > 0) {
134                             expr = new NewExpr(pos, iterator, clazz, minfo,
135                                                newList.type, newList.pos);
136                             edit((NewExpr)expr);
137                             newList = newList.next;
138                         }
139                         else {
140                             expr = new MethodCall(pos, iterator, clazz, minfo);
141                             MethodCall mcall = (MethodCall)expr;
142                             if (!mcall.getMethodName().equals(
143                                                 MethodInfo.nameInit))
144                                 edit(mcall);
145                         }
146                     }
147                 }
148                 else { // c >= 188
149
if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY
150                         || c == Opcode.MULTIANEWARRAY) {
151                         expr = new NewArray(pos, iterator, clazz, minfo, c);
152                         edit((NewArray)expr);
153                     }
154                     else if (c == Opcode.INSTANCEOF) {
155                         expr = new Instanceof(pos, iterator, clazz, minfo);
156                         edit((Instanceof)expr);
157                     }
158                     else if (c == Opcode.CHECKCAST) {
159                         expr = new Cast(pos, iterator, clazz, minfo);
160                         edit((Cast)expr);
161                     }
162                 }
163
164                 if (expr != null && expr.edited()) {
165                     edited = true;
166                     maxLocals = max(maxLocals, expr.locals());
167                     maxStack = max(maxStack, expr.stack());
168                 }
169             }
170             catch (BadBytecode e) {
171                 throw new CannotCompileException(e);
172             }
173
174         ExceptionTable et = codeAttr.getExceptionTable();
175         int n = et.size();
176         for (int i = 0; i < n; ++i) {
177             Handler h = new Handler(et, i, iterator, clazz, minfo);
178             edit(h);
179             if (h.edited()) {
180                 edited = true;
181                 maxLocals = max(maxLocals, h.locals());
182                 maxStack = max(maxStack, h.stack());
183             }
184         }
185
186         codeAttr.setMaxLocals(maxLocals);
187         codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack);
188         return edited;
189     }
190
191     private int max(int i, int j) {
192         return i > j ? i : j;
193     }
194
195     /**
196      * Edits a <tt>new</tt> expression (overridable).
197      * The default implementation performs nothing.
198      *
199      * @param e the <tt>new</tt> expression creating an object.
200      */

201     public void edit(NewExpr e) throws CannotCompileException {}
202
203     /**
204      * Edits an expression for array creation (overridable).
205      * The default implementation performs nothing.
206      *
207      * @param a the <tt>new</tt> expression for creating an array.
208      * @throws CannotCompileException
209      */

210     public void edit(NewArray a) throws CannotCompileException {}
211
212     /**
213      * Edits a method call (overridable).
214      * The default implementation performs nothing.
215      */

216     public void edit(MethodCall m) throws CannotCompileException {}
217
218     /**
219      * Edits a field-access expression (overridable).
220      * Field access means both read and write.
221      * The default implementation performs nothing.
222      */

223     public void edit(FieldAccess f) throws CannotCompileException {}
224
225     /**
226      * Edits an instanceof expression (overridable).
227      * The default implementation performs nothing.
228      */

229     public void edit(Instanceof i) throws CannotCompileException {}
230
231     /**
232      * Edits an expression for explicit type casting (overridable).
233      * The default implementation performs nothing.
234      */

235     public void edit(Cast c) throws CannotCompileException {}
236
237     /**
238      * Edits a catch clause (overridable).
239      * The default implementation performs nothing.
240      */

241     public void edit(Handler h) throws CannotCompileException {}
242 }
243
Popular Tags