Package org.hotswap.agent.javassist.expr

Source Code of org.hotswap.agent.javassist.expr.ExprEditor$LoopContext

/*
* 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 org.hotswap.agent.javassist.expr;

import org.hotswap.agent.javassist.CannotCompileException;

/**
* A translator of method bodies.
* <p/>
* <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/>
* <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/>
* <p>The following code is an example:
* <p/>
* <ul><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></ul>
* <p/>
* <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 org.hotswap.agent.javassist.CtClass#instrument(ExprEditor)
* @see org.hotswap.agent.javassist.CtMethod#instrument(ExprEditor)
* @see org.hotswap.agent.javassist.CtConstructor#instrument(ExprEditor)
* @see MethodCall
* @see NewExpr
* @see FieldAccess
* @see org.hotswap.agent.javassist.CodeConverter
*/
public class ExprEditor {
    /**
     * Default constructor.  It does nothing.
     */
    public ExprEditor() {
    }

    /**
     * Undocumented method.  Do not use; internal-use only.
     */
    public boolean doit(org.hotswap.agent.javassist.CtClass clazz, org.hotswap.agent.javassist.bytecode.MethodInfo minfo)
            throws CannotCompileException {
        org.hotswap.agent.javassist.bytecode.CodeAttribute codeAttr = minfo.getCodeAttribute();
        if (codeAttr == null)
            return false;

        org.hotswap.agent.javassist.bytecode.CodeIterator iterator = codeAttr.iterator();
        boolean edited = false;
        LoopContext context = new LoopContext(codeAttr.getMaxLocals());

        while (iterator.hasNext())
            if (loopBody(iterator, clazz, minfo, context))
                edited = true;

        org.hotswap.agent.javassist.bytecode.ExceptionTable et = codeAttr.getExceptionTable();
        int n = et.size();
        for (int i = 0; i < n; ++i) {
            org.hotswap.agent.javassist.expr.Handler h = new org.hotswap.agent.javassist.expr.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 (org.hotswap.agent.javassist.bytecode.BadBytecode b) {
            throw new CannotCompileException(b.getMessage(), b);
        }

        return edited;
    }

    /**
     * Visits each bytecode in the given range.
     */
    boolean doit(org.hotswap.agent.javassist.CtClass clazz, org.hotswap.agent.javassist.bytecode.MethodInfo minfo, LoopContext context,
                 org.hotswap.agent.javassist.bytecode.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(org.hotswap.agent.javassist.bytecode.CodeIterator iterator, org.hotswap.agent.javassist.CtClass clazz,
                           org.hotswap.agent.javassist.bytecode.MethodInfo minfo, LoopContext context)
            throws CannotCompileException {
        try {
            Expr expr = null;
            int pos = iterator.next();
            int c = iterator.byteAt(pos);

            if (c < org.hotswap.agent.javassist.bytecode.Opcode.GETSTATIC)   // c < 178
                /* skip */ ;
            else if (c < org.hotswap.agent.javassist.bytecode.Opcode.NEWARRAY) { // c < 188
                if (c == org.hotswap.agent.javassist.bytecode.Opcode.INVOKESTATIC
                        || c == org.hotswap.agent.javassist.bytecode.Opcode.INVOKEINTERFACE
                        || c == org.hotswap.agent.javassist.bytecode.Opcode.INVOKEVIRTUAL) {
                    expr = new MethodCall(pos, iterator, clazz, minfo);
                    edit((MethodCall) expr);
                } else if (c == org.hotswap.agent.javassist.bytecode.Opcode.GETFIELD || c == org.hotswap.agent.javassist.bytecode.Opcode.GETSTATIC
                        || c == org.hotswap.agent.javassist.bytecode.Opcode.PUTFIELD
                        || c == org.hotswap.agent.javassist.bytecode.Opcode.PUTSTATIC) {
                    expr = new FieldAccess(pos, iterator, clazz, minfo, c);
                    edit((FieldAccess) expr);
                } else if (c == org.hotswap.agent.javassist.bytecode.Opcode.NEW) {
                    int index = iterator.u16bitAt(pos + 1);
                    context.newList = new NewOp(context.newList, pos,
                            minfo.getConstPool().getClassInfo(index));
                } else if (c == org.hotswap.agent.javassist.bytecode.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(org.hotswap.agent.javassist.bytecode.MethodInfo.nameInit)) {
                            ConstructorCall ccall = new ConstructorCall(pos, iterator, clazz, minfo);
                            expr = ccall;
                            edit(ccall);
                        } else {
                            expr = mcall;
                            edit(mcall);
                        }
                    }
                }
            } else // c >= 188
                if (c == org.hotswap.agent.javassist.bytecode.Opcode.NEWARRAY || c == org.hotswap.agent.javassist.bytecode.Opcode.ANEWARRAY
                        || c == org.hotswap.agent.javassist.bytecode.Opcode.MULTIANEWARRAY) {
                    expr = new NewArray(pos, iterator, clazz, minfo, c);
                    edit((NewArray) expr);
                } else if (c == org.hotswap.agent.javassist.bytecode.Opcode.INSTANCEOF) {
                    expr = new Instanceof(pos, iterator, clazz, minfo);
                    edit((Instanceof) expr);
                } else if (c == org.hotswap.agent.javassist.bytecode.Opcode.CHECKCAST) {
                    expr = new org.hotswap.agent.javassist.expr.Cast(pos, iterator, clazz, minfo);
                    edit((org.hotswap.agent.javassist.expr.Cast) expr);
                }
            }

            if (expr != null && expr.edited()) {
                context.updateMax(expr.locals(), expr.stack());
                return true;
            } else
                return false;
        } catch (org.hotswap.agent.javassist.bytecode.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).
     * <p/>
     * 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.
     * <p/>
     * 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(org.hotswap.agent.javassist.expr.Cast c) throws CannotCompileException {
    }

    /**
     * Edits a catch clause (overridable).
     * The default implementation performs nothing.
     */
    public void edit(org.hotswap.agent.javassist.expr.Handler h) throws CannotCompileException {
    }
}
TOP

Related Classes of org.hotswap.agent.javassist.expr.ExprEditor$LoopContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.