All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.expr.ExprEditor Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * 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 com.feilong.lib.javassist.expr;

import com.feilong.lib.javassist.CannotCompileException;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ExceptionTable;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;

/**
 * A translator of method bodies.
 *
 * 

* 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. * *

* If instrument() is called in * CtMethod, the method body is scanned from the beginning * to the end. * Whenever an expression, such as a method call and a new * expression (object creation), * is found, edit() is called in ExprEdit. * edit() can inspect and modify the given expression. * The modification is reflected on the original method body. If * edit() does nothing, the original method body is not * changed. * *

* The following code is an example: * *

 * 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());
 *     }
 * });
 * 
* *

* This code inspects all method calls appearing in the method represented * by cm and it prints the names and the line numbers of the * methods declared in class Point. This code does not modify * the body of the method represented by cm. If the method * body must be modified, call replace() * in MethodCall. * * @see com.feilong.lib.javassist.CtClass#instrument(ExprEditor) * @see com.feilong.lib.javassist.CtMethod#instrument(ExprEditor) * @see com.feilong.lib.javassist.CtConstructor#instrument(ExprEditor) * @see MethodCall * @see NewExpr * @see FieldAccess * * @see com.feilong.lib.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){ 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){ /* 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; } return false; }catch (BadBytecode e){ throw new CannotCompileException(e); } } /** * Edits a new expression (overridable). * The default implementation performs nothing. * * @param e * the new 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 new 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 * super() or this() * 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{ } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy