001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.expr;
017:
018: import javassist.bytecode.*;
019: import javassist.CtClass;
020: import javassist.CannotCompileException;
021:
022: /**
023: * A translator of method bodies.
024: *
025: * <p>The users can define a subclass of this class to customize how to
026: * modify a method body. The overall architecture is similar to the
027: * strategy pattern.
028: *
029: * <p>If <code>instrument()</code> is called in
030: * <code>CtMethod</code>, the method body is scanned from the beginning
031: * to the end.
032: * Whenever an expression, such as a method call and a <tt>new</tt>
033: * expression (object creation),
034: * is found, <code>edit()</code> is called in <code>ExprEdit</code>.
035: * <code>edit()</code> can inspect and modify the given expression.
036: * The modification is reflected on the original method body. If
037: * <code>edit()</code> does nothing, the original method body is not
038: * changed.
039: *
040: * <p>The following code is an example:
041: *
042: * <ul><pre>
043: * CtMethod cm = ...;
044: * cm.instrument(new ExprEditor() {
045: * public void edit(MethodCall m) throws CannotCompileException {
046: * if (m.getClassName().equals("Point")) {
047: * System.out.println(m.getMethodName() + " line: "
048: * + m.getLineNumber());
049: * }
050: * });
051: * </pre></ul>
052: *
053: * <p>This code inspects all method calls appearing in the method represented
054: * by <code>cm</code> and it prints the names and the line numbers of the
055: * methods declared in class <code>Point</code>. This code does not modify
056: * the body of the method represented by <code>cm</code>. If the method
057: * body must be modified, call <code>replace()</code>
058: * in <code>MethodCall</code>.
059: *
060: * @see javassist.CtClass#instrument(ExprEditor)
061: * @see javassist.CtMethod#instrument(ExprEditor)
062: * @see javassist.CtConstructor#instrument(ExprEditor)
063: * @see MethodCall
064: * @see NewExpr
065: * @see FieldAccess
066: *
067: * @see javassist.CodeConverter
068: */
069: public class ExprEditor {
070: /**
071: * Default constructor. It does nothing.
072: */
073: public ExprEditor() {
074: }
075:
076: static class NewOp {
077: NewOp next;
078: int pos;
079: String type;
080:
081: NewOp(NewOp n, int p, String t) {
082: next = n;
083: pos = p;
084: type = t;
085: }
086: }
087:
088: /**
089: * Undocumented method. Do not use; internal-use only.
090: */
091: public boolean doit(CtClass clazz, MethodInfo minfo)
092: throws CannotCompileException {
093: CodeAttribute codeAttr = minfo.getCodeAttribute();
094: if (codeAttr == null)
095: return false;
096:
097: CodeIterator iterator = codeAttr.iterator();
098: boolean edited = false;
099: int maxLocals = codeAttr.getMaxLocals();
100: int maxStack = 0;
101:
102: NewOp newList = null;
103: ConstPool cp = minfo.getConstPool();
104: int prevOp = Opcode.NOP;
105:
106: while (iterator.hasNext())
107: try {
108: Expr expr = null;
109: int pos = iterator.next();
110: int c = iterator.byteAt(pos);
111:
112: if (c == Opcode.INVOKESTATIC
113: || c == Opcode.INVOKEINTERFACE
114: || c == Opcode.INVOKEVIRTUAL) {
115: expr = new MethodCall(pos, iterator, clazz, minfo);
116: edit((MethodCall) expr);
117: } else if (c == Opcode.GETFIELD
118: || c == Opcode.GETSTATIC
119: || c == Opcode.PUTFIELD
120: || c == Opcode.PUTSTATIC) {
121: expr = new FieldAccess(pos, iterator, clazz, minfo,
122: c, prevOp);
123: edit((FieldAccess) expr);
124: } else if (c == Opcode.NEW) {
125: int index = iterator.u16bitAt(pos + 1);
126: newList = new NewOp(newList, pos, cp
127: .getClassInfo(index));
128: } else if (c == Opcode.INVOKESPECIAL) {
129: if (newList != null
130: && cp.isConstructor(newList.type, iterator
131: .u16bitAt(pos + 1)) > 0) {
132: expr = new NewExpr(pos, iterator, clazz, minfo,
133: newList.type, newList.pos);
134: edit((NewExpr) expr);
135: newList = newList.next;
136: } else {
137: expr = new MethodCall(pos, iterator, clazz,
138: minfo);
139: MethodCall mcall = (MethodCall) expr;
140: if (!mcall.getMethodName().equals(
141: MethodInfo.nameInit))
142: edit(mcall);
143: }
144: } else if (c == Opcode.INSTANCEOF) {
145: expr = new Instanceof(pos, iterator, clazz, minfo);
146: edit((Instanceof) expr);
147: } else if (c == Opcode.CHECKCAST) {
148: expr = new Cast(pos, iterator, clazz, minfo);
149: edit((Cast) expr);
150: }
151: prevOp = c;
152: if (expr != null && expr.edited()) {
153: edited = true;
154: maxLocals = max(maxLocals, expr.locals());
155: maxStack = max(maxStack, expr.stack());
156: }
157: } catch (BadBytecode e) {
158: throw new CannotCompileException(e);
159: }
160:
161: ExceptionTable et = codeAttr.getExceptionTable();
162: int n = et.size();
163: for (int i = 0; i < n; ++i) {
164: Handler h = new Handler(et, i, iterator, clazz, minfo);
165: edit(h);
166: if (h.edited()) {
167: edited = true;
168: maxLocals = max(maxLocals, h.locals());
169: maxStack = max(maxStack, h.stack());
170: }
171: }
172:
173: codeAttr.setMaxLocals(maxLocals);
174: codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack);
175: return edited;
176: }
177:
178: private int max(int i, int j) {
179: return i > j ? i : j;
180: }
181:
182: /**
183: * Edits a <tt>new</tt> expression (overridable).
184: * The default implementation performs nothing.
185: *
186: * @param e the <tt>new</tt> expression creating an object.
187: */
188: public void edit(NewExpr e) throws CannotCompileException {
189: }
190:
191: /**
192: * Edits a method call (overridable).
193: * The default implementation performs nothing.
194: */
195: public void edit(MethodCall m) throws CannotCompileException {
196: }
197:
198: /**
199: * Edits a field-access expression (overridable).
200: * Field access means both read and write.
201: * The default implementation performs nothing.
202: */
203: public void edit(FieldAccess f) throws CannotCompileException {
204: }
205:
206: /**
207: * Edits an instanceof expression (overridable).
208: * The default implementation performs nothing.
209: */
210: public void edit(Instanceof i) throws CannotCompileException {
211: }
212:
213: /**
214: * Edits an expression for explicit type casting (overridable).
215: * The default implementation performs nothing.
216: */
217: public void edit(Cast c) throws CannotCompileException {
218: }
219:
220: /**
221: * Edits a catch clause (overridable).
222: * The default implementation performs nothing.
223: */
224: public void edit(Handler h) throws CannotCompileException {
225: }
226: }
|