123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.expr;
-
- import javassist.bytecode.*;
- import javassist.CtClass;
- import javassist.CannotCompileException;
-
- /**
- * A translator of method bodies.
- *
- * <p>The users can define a subclass of this class to customize how to
- * modify a method body. The overall architecture is similar to the
- * strategy pattern.
- *
- * <p>If <code>instrument()</code> is called in
- * <code>CtMethod</code>, the method body is scanned from the beginning
- * to the end.
- * Whenever an expression, such as a method call and a <tt>new</tt>
- * expression (object creation),
- * is found, <code>edit()</code> is called in <code>ExprEdit</code>.
- * <code>edit()</code> can inspect and modify the given expression.
- * The modification is reflected on the original method body. If
- * <code>edit()</code> does nothing, the original method body is not
- * changed.
- *
- * <p>The following code is an example:
- *
- * <pre>
- * CtMethod cm = ...;
- * cm.instrument(new ExprEditor() {
- * public void edit(MethodCall m) throws CannotCompileException {
- * if (m.getClassName().equals("Point")) {
- * System.out.println(m.getMethodName() + " line: "
- * + m.getLineNumber());
- * }
- * });
- * </pre>
- *
- * <p>This code inspects all method calls appearing in the method represented
- * by <code>cm</code> and it prints the names and the line numbers of the
- * methods declared in class <code>Point</code>. This code does not modify
- * the body of the method represented by <code>cm</code>. If the method
- * body must be modified, call <code>replace()</code>
- * in <code>MethodCall</code>.
- *
- * @see javassist.CtClass#instrument(ExprEditor)
- * @see javassist.CtMethod#instrument(ExprEditor)
- * @see javassist.CtConstructor#instrument(ExprEditor)
- * @see MethodCall
- * @see NewExpr
- * @see FieldAccess
- *
- * @see javassist.CodeConverter
- */
- public class ExprEditor {
- /**
- * Default constructor. It does nothing.
- */
- public ExprEditor() {}
-
- /**
- * Undocumented method. Do not use; internal-use only.
- */
- public boolean doit(CtClass clazz, MethodInfo minfo)
- throws CannotCompileException
- {
- CodeAttribute codeAttr = minfo.getCodeAttribute();
- if (codeAttr == null)
- return false;
-
- CodeIterator iterator = codeAttr.iterator();
- boolean edited = false;
- LoopContext context = new LoopContext(codeAttr.getMaxLocals());
-
- while (iterator.hasNext())
- if (loopBody(iterator, clazz, minfo, context))
- edited = true;
-
- ExceptionTable et = codeAttr.getExceptionTable();
- int n = et.size();
- for (int i = 0; i < n; ++i) {
- Handler h = new Handler(et, i, iterator, clazz, minfo);
- edit(h);
- if (h.edited()) {
- edited = true;
- context.updateMax(h.locals(), h.stack());
- }
- }
-
- // codeAttr might be modified by other partiess
- // so I check the current value of max-locals.
- if (codeAttr.getMaxLocals() < context.maxLocals)
- codeAttr.setMaxLocals(context.maxLocals);
-
- codeAttr.setMaxStack(codeAttr.getMaxStack() + context.maxStack);
- try {
- if (edited)
- minfo.rebuildStackMapIf6(clazz.getClassPool(),
- clazz.getClassFile2());
- }
- catch (BadBytecode b) {
- throw new CannotCompileException(b.getMessage(), b);
- }
-
- return edited;
- }
-
- /**
- * Visits each bytecode in the given range.
- */
- boolean doit(CtClass clazz, MethodInfo minfo, LoopContext context,
- CodeIterator iterator, int endPos)
- throws CannotCompileException
- {
- boolean edited = false;
- while (iterator.hasNext() && iterator.lookAhead() < endPos) {
- int size = iterator.getCodeLength();
- if (loopBody(iterator, clazz, minfo, context)) {
- edited = true;
- int size2 = iterator.getCodeLength();
- if (size != size2) // the body was modified.
- endPos += size2 - size;
- }
- }
-
- return edited;
- }
-
- final static class NewOp {
- NewOp next;
- int pos;
- String type;
-
- NewOp(NewOp n, int p, String t) {
- next = n;
- pos = p;
- type = t;
- }
- }
-
- final static class LoopContext {
- NewOp newList;
- int maxLocals;
- int maxStack;
-
- LoopContext(int locals) {
- maxLocals = locals;
- maxStack = 0;
- newList = null;
- }
-
- void updateMax(int locals, int stack) {
- if (maxLocals < locals)
- maxLocals = locals;
-
- if (maxStack < stack)
- maxStack = stack;
- }
- }
-
- final boolean loopBody(CodeIterator iterator, CtClass clazz,
- MethodInfo minfo, LoopContext context)
- throws CannotCompileException
- {
- try {
- Expr expr = null;
- int pos = iterator.next();
- int c = iterator.byteAt(pos);
-
- if (c < Opcode.GETSTATIC) // c < 178
- /* skip */;
- else if (c < Opcode.NEWARRAY) { // c < 188
- if (c == Opcode.INVOKESTATIC
- || c == Opcode.INVOKEINTERFACE
- || c == Opcode.INVOKEVIRTUAL) {
- expr = new MethodCall(pos, iterator, clazz, minfo);
- edit((MethodCall)expr);
- }
- else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC
- || c == Opcode.PUTFIELD
- || c == Opcode.PUTSTATIC) {
- expr = new FieldAccess(pos, iterator, clazz, minfo, c);
- edit((FieldAccess)expr);
- }
- else if (c == Opcode.NEW) {
- int index = iterator.u16bitAt(pos + 1);
- context.newList = new NewOp(context.newList, pos,
- minfo.getConstPool().getClassInfo(index));
- }
- else if (c == Opcode.INVOKESPECIAL) {
- NewOp newList = context.newList;
- if (newList != null
- && minfo.getConstPool().isConstructor(newList.type,
- iterator.u16bitAt(pos + 1)) > 0) {
- expr = new NewExpr(pos, iterator, clazz, minfo,
- newList.type, newList.pos);
- edit((NewExpr)expr);
- context.newList = newList.next;
- }
- else {
- MethodCall mcall = new MethodCall(pos, iterator, clazz, minfo);
- if (mcall.getMethodName().equals(MethodInfo.nameInit)) {
- ConstructorCall ccall = new ConstructorCall(pos, iterator, clazz, minfo);
- expr = ccall;
- edit(ccall);
- }
- else {
- expr = mcall;
- edit(mcall);
- }
- }
- }
- }
- else { // c >= 188
- if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY
- || c == Opcode.MULTIANEWARRAY) {
- expr = new NewArray(pos, iterator, clazz, minfo, c);
- edit((NewArray)expr);
- }
- else if (c == Opcode.INSTANCEOF) {
- expr = new Instanceof(pos, iterator, clazz, minfo);
- edit((Instanceof)expr);
- }
- else if (c == Opcode.CHECKCAST) {
- expr = new Cast(pos, iterator, clazz, minfo);
- edit((Cast)expr);
- }
- }
-
- if (expr != null && expr.edited()) {
- context.updateMax(expr.locals(), expr.stack());
- return true;
- }
- else
- return false;
- }
- catch (BadBytecode e) {
- throw new CannotCompileException(e);
- }
- }
-
- /**
- * Edits a <tt>new</tt> expression (overridable).
- * The default implementation performs nothing.
- *
- * @param e the <tt>new</tt> expression creating an object.
- */
- public void edit(NewExpr e) throws CannotCompileException {}
-
- /**
- * Edits an expression for array creation (overridable).
- * The default implementation performs nothing.
- *
- * @param a the <tt>new</tt> expression for creating an array.
- * @throws CannotCompileException
- */
- public void edit(NewArray a) throws CannotCompileException {}
-
- /**
- * Edits a method call (overridable).
- *
- * The default implementation performs nothing.
- */
- public void edit(MethodCall m) throws CannotCompileException {}
-
- /**
- * Edits a constructor call (overridable).
- * The constructor call is either
- * <code>super()</code> or <code>this()</code>
- * included in a constructor body.
- *
- * The default implementation performs nothing.
- *
- * @see #edit(NewExpr)
- */
- public void edit(ConstructorCall c) throws CannotCompileException {}
-
- /**
- * Edits a field-access expression (overridable).
- * Field access means both read and write.
- * The default implementation performs nothing.
- */
- public void edit(FieldAccess f) throws CannotCompileException {}
-
- /**
- * Edits an instanceof expression (overridable).
- * The default implementation performs nothing.
- */
- public void edit(Instanceof i) throws CannotCompileException {}
-
- /**
- * Edits an expression for explicit type casting (overridable).
- * The default implementation performs nothing.
- */
- public void edit(Cast c) throws CannotCompileException {}
-
- /**
- * Edits a catch clause (overridable).
- * The default implementation performs nothing.
- */
- public void edit(Handler h) throws CannotCompileException {}
- }
|