/Users/lyon/j4p/src/javassist/expr/ExprEditor.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 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
76 static class NewOp {
77 NewOp next;
78 int pos;
79 String type;
80
81 NewOp(NewOp n, int p, String t) {
82 next = n;
83 pos = p;
84 type = t;
85 }
86 }
87
88 /**
89 * Undocumented method. Do not use; internal-use only.
90 */
91 public boolean doit(CtClass clazz, MethodInfo minfo)
92 throws CannotCompileException {
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.INVOKESTATIC || c == Opcode.INVOKEINTERFACE
112 || c == Opcode.INVOKEVIRTUAL) {
113 expr = new MethodCall(pos, iterator, clazz, minfo);
114 edit((MethodCall) expr);
115 } else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC
116 || c == Opcode.PUTFIELD || c == Opcode.PUTSTATIC) {
117 expr = new FieldAccess(pos, iterator, clazz, minfo, c);
118 edit((FieldAccess) expr);
119 } else if (c == Opcode.NEW) {
120 int index = iterator.u16bitAt(pos + 1);
121 newList = new NewOp(newList, pos,
122 cp.getClassInfo(index));
123 } else if (c == Opcode.INVOKESPECIAL) {
124 if (newList != null && cp.isConstructor(newList.type,
125 iterator.u16bitAt(pos + 1)) > 0) {
126 expr = new NewExpr(pos, iterator, clazz, minfo,
127 newList.type, newList.pos);
128 edit((NewExpr) expr);
129 newList = newList.next;
130 } else {
131 expr = new MethodCall(pos, iterator, clazz, minfo);
132 MethodCall mcall = (MethodCall) expr;
133 if (!mcall.getMethodName().equals(
134 MethodInfo.nameInit))
135 edit(mcall);
136 }
137 } else if (c == Opcode.INSTANCEOF) {
138 expr = new Instanceof(pos, iterator, clazz, minfo);
139 edit((Instanceof) expr);
140 } else if (c == Opcode.CHECKCAST) {
141 expr = new Cast(pos, iterator, clazz, minfo);
142 edit((Cast) expr);
143 }
144
145 if (expr != null && expr.edited()) {
146 edited = true;
147 maxLocals = max(maxLocals, expr.locals());
148 maxStack = max(maxStack, expr.stack());
149 }
150 } catch (BadBytecode e) {
151 throw new CannotCompileException(e);
152 }
153
154 ExceptionTable et = codeAttr.getExceptionTable();
155 int n = et.size();
156 for (int i = 0; i < n; ++i) {
157 Handler h = new Handler(et, i, iterator, clazz, minfo);
158 edit(h);
159 if (h.edited()) {
160 edited = true;
161 maxLocals = max(maxLocals, h.locals());
162 maxStack = max(maxStack, h.stack());
163 }
164 }
165
166 codeAttr.setMaxLocals(maxLocals);
167 codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack);
168 return edited;
169 }
170
171 private int max(int i, int j) {
172 return i > j ? i : j;
173 }
174
175 /**
176 * Edits a <tt>new</tt> expression (overridable).
177 * The default implementation performs nothing.
178 *
179 * @param e the <tt>new</tt> expression creating an object.
180 */
181 public void edit(NewExpr e) throws CannotCompileException {
182 }
183
184 /**
185 * Edits a method call (overridable).
186 * The default implementation performs nothing.
187 */
188 public void edit(MethodCall m) throws CannotCompileException {
189 }
190
191 /**
192 * Edits a field-access expression (overridable).
193 * Field access means both read and write.
194 * The default implementation performs nothing.
195 */
196 public void edit(FieldAccess f) throws CannotCompileException {
197 }
198
199 /**
200 * Edits an instanceof expression (overridable).
201 * The default implementation performs nothing.
202 */
203 public void edit(Instanceof i) throws CannotCompileException {
204 }
205
206 /**
207 * Edits an expression for explicit type casting (overridable).
208 * The default implementation performs nothing.
209 */
210 public void edit(Cast c) throws CannotCompileException {
211 }
212
213 /**
214 * Edits a catch clause (overridable).
215 * The default implementation performs nothing.
216 */
217 public void edit(Handler h) throws CannotCompileException {
218 }
219 }
220