Package net.sf.just4log.transform

Source Code of net.sf.just4log.transform.Transform

/*
* ============================================================================
*                   The Apache Software License, Version 1.1
* ============================================================================
*
*    Copyright (C) 2000-2003 Lucas Bruand. All
*    rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of  source code must  retain the above copyright  notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
*    include  the following  acknowledgment:  "This product includes  software
*    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
*    Alternately, this  acknowledgment may  appear in the software itself,  if
*    and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Just4Log" and  "Apache Software Foundation"  must not be used to
*    endorse  or promote  products derived  from this  software without  prior
*    written permission. For written permission, please contact
*    apache@apache.org.
*
* 5. Products  derived from this software may not  be called "Apache", nor may
*    "Apache" appear  in their name,  without prior written permission  of the
*    Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
* APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
* ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
* (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software  consists of voluntary contributions made  by many individuals
* on behalf of the  Apache Software Foundation.  For more  information  on the
* Apache Software Foundation, please see <http://www.apache.org/>.
*
*/
package net.sf.just4log.transform;

import java.util.Iterator;
import java.util.LinkedList;

import net.sf.just4log.NoMatchingInvokeInterfaceInstruction;

import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReturnInstruction;
import org.apache.bcel.generic.Type;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* @author Lucas Bruand
*/

public abstract class Transform {
    private static Log logger = LogFactory.getLog(Transform.class);
    private static String CLASSID =
        "$Id: Transform.java,v 1.15 2003/09/23 21:21:15 lbruand Exp $";

    static {
        ApacheCommonTransform.register();
        Log4jTransform.register();
        LogJDK14Transform.register();
    }

    InstructionFactory instFact;
    private String classname;

    /**
     *
     */
    public Transform() {
        super();
    }

    private static LinkedList transmap;
    public static void register(Transform trans) {
        if (transmap == null) {
            transmap = new LinkedList();
        }

        synchronized (transmap) {
            transmap.add(trans);
        }

    }

    public static Transform getTransformationForJavaClass(
        JavaClass claz,
        ConstantPoolGen cp) {
        Field[] fields = claz.getFields();
        ObjectType fieldType;
        Transform t;
        for (int i = 0; i < fields.length; i++) {

            try {
                fieldType = (ObjectType) fields[i].getType();
            } catch (ClassCastException ex) {
                continue;
            }
            for (Iterator j = transmap.iterator(); j.hasNext();) {
                t = (Transform) j.next();
                if (fieldType.equals(t.getLogType())
                    || fieldType.isCastableTo(t.getLogType())) {
                    logger.info(
                        "Found logger attribute: "
                            + fieldType
                            + " "
                            + fields[i].getName());
                    t.init(claz, fields[i], cp);
                    return t;
                }
            }

        }
        return null;
    }
    JavaClass clazz;
    Field loggerAttribute;
    public void init(JavaClass clazz, Field logger, ConstantPoolGen cp) {
        this.clazz = clazz;
        this.loggerAttribute = logger;
        this.instFact = new InstructionFactory(cp);
    }
    public void done() {
        this.loggerAttribute = null;
        this.instFact = null;
    }
    public abstract InstructionHandle insertFork(
        InstructionList il,
        InstructionHandle getStaticHandle,
        InstructionHandle invokeHandle,
        ConstantPoolGen cp);

    public abstract InstructionHandle insertEnter(
        MethodGen orig,
        InstructionList il,
        InstructionHandle firstInstructionHandle,
        ConstantPoolGen cp);

    public abstract InstructionHandle insertExit(
        MethodGen orig,
        InstructionList il,
        InstructionHandle returnInstructionHandle,
        ConstantPoolGen cp);

    public void transform(
        MethodGen mg,
        InstructionList il,
        InstructionHandle handle,
        ConstantPoolGen cp)
        throws NoMatchingInvokeInterfaceInstruction {

        logger.info("Found a logger instruction.");
        InstructionHandle lastLogHandle = handle;

        InvokeInstruction invokeInterface = null;
        Instruction inst = null;
        while (true) {
            handle = handle.getNext();
            if (handle == null) {
                logger.warn("No matching invokeInterface found.");
                throw new NoMatchingInvokeInterfaceInstruction("No matching invokeInterface found.");
            }
            inst = handle.getInstruction();
            if (inst instanceof InvokeInstruction) {
                invokeInterface = (InvokeInstruction) inst;
                if (invokeInterface.getClassType(cp).equals(getLogType())) {
                    logger.info("Found matching invokeInstruction.");
                    if (level_logs == FORKLOGS) {
                        InstructionHandle insertHandle =
                            insertFork(il, lastLogHandle, handle, cp);
                        if (insertHandle != null) {
                            il.redirectBranches(lastLogHandle, insertHandle);
                            il.redirectExceptionHandlers(
                                mg.getExceptionHandlers(),
                                lastLogHandle,
                                insertHandle);
                            il.redirectLocalVariables(
                                mg.getLocalVariables(),
                                lastLogHandle,
                                insertHandle);
                        }
                    }

                    break;
                }
            }
        }
    }

    /**
     * This optimizes a method in particular.
     * @param orig The original method to optimize.
     * @param mg The MethodGen that is going to be used as a basis for generation.
     * @param cp The ConstantPool that is going to be used as a basis for generation. This is going to be modified.
     * @return the new optimized method.
     * @throws NoMatchingInvokeInterfaceInstruction
     */
    public Method speedup(Method orig, MethodGen mg, ConstantPoolGen cp)
        throws NoMatchingInvokeInterfaceInstruction {
        logger.info("Entry speedup(Method " + mg.getName() + ")");
        if (orig.getName().equals("<clinit>")
            || orig.getName().equals("<init>")
            || orig.getName().equals("class$")) {
            logger.info(
                "This method "
                    + mg.getName()
                    + " is a special method and won't be modified.");
            return orig;
        }
        InstructionList il = null;
        InstructionHandle handle = null;
        Instruction inst = null;

        GETSTATIC getStatic = null;

        Method m = null;

        try {
            il = mg.getInstructionList();
            handle = il.getStart();
            if (level_enters == SIMPLEENTER) {

                insertEnter(mg, il, handle, cp);
                insertFork(il, il.getStart(), handle.getPrev(), cp);
            }

            for (; handle != null; handle = handle.getNext()) {
                inst = handle.getInstruction();
                logger.info("next instruction: " + inst);
                if (level_exits == SIMPLEEXIT
                    && inst instanceof ReturnInstruction) {
                    InstructionHandle lastLogHandle = handle;
                    logger.info(
                        "Found a ReturnInstruction of type: "
                            + inst.toString());
                    int stackSize =
                        inst.consumeStack(cp) - inst.produceStack(cp);
                    while (stackSize != 0) {
                        handle = handle.getPrev();
                        inst = handle.getInstruction();
                        logger.info("prev instruction: " + inst);
                        stackSize += inst.consumeStack(cp)
                            - inst.produceStack(cp);
                    }

                    InstructionHandle insertHandle =
                        insertExit(mg, il, handle, cp);
                    if (insertHandle != null) {
                      // We need to redirect branches etc.... twice
                      // so that the if fork doesn't get erroneous modified.
                        il.redirectBranches(handle, insertHandle);
                        il.redirectExceptionHandlers(
                            mg.getExceptionHandlers(),
                            handle,
                            insertHandle);
                        il.redirectLocalVariables(
                            mg.getLocalVariables(),
                            handle,
                            insertHandle);
                        handle =
                            insertFork(il, insertHandle, handle.getPrev(), cp);
                        il.redirectBranches(insertHandle, handle );
                        il.redirectExceptionHandlers(
                            mg.getExceptionHandlers(),
              insertHandle,
                            handle);
                        il.redirectLocalVariables(
                            mg.getLocalVariables(),
                            insertHandle,
              handle);
                    }

                    handle = lastLogHandle;
                }
                if (inst instanceof GETSTATIC) {
                    getStatic = (GETSTATIC) inst;
                    Type type = getStatic.getFieldType(cp);
                    logger.info(
                        "Found a GETSTATIC instruction of type: "
                            + type.toString());

                    if (getStatic
                        .getFieldName(cp)
                        .equals(loggerAttribute.getName())) {
                        logger.info("This is a logger access");
                        transform(mg, il, handle, cp);
                    }
                }
            }
            if (orig.getLineNumberTable() == null) {
                logger.info("Removing line numbers");
                mg.removeLineNumbers();
            }
            if (orig.getLocalVariableTable() == null) {
                logger.info("Removing Local variables table");
                mg.removeLocalVariables();
            }
            m = mg.getMethod();
        } finally {

            il.dispose();
        }
        return m;
    }
    /**
     * This method transforms a not optimized JavaClass into a new Log-optimised
     * JavaClass
     * @param source the JavaClass to optimize.
     * @return the optimized JavaClass
     */
    public static JavaClass speedup(JavaClass source) {
        try {
            logger.info("Entry speedup(JavaClass)");
            ClassGen cg = new ClassGen(source);
            Method[] methods = cg.getMethods();
            ConstantPoolGen cp = cg.getConstantPool();

            Transform trans = getTransformationForJavaClass(source, cp);
            if (trans == null) {
                logger.warn(
                    "No transformer found for class " + source.getClassName());
                return source;
            }
            for (int i = 0; i < methods.length; i++) {
                if (!(methods[i].isAbstract() || methods[i].isNative())) {
                    MethodGen mg =
                        new MethodGen(methods[i], source.getClassName(), cp);
                    Method stripped = trans.speedup(methods[i], mg, cp);
                    if (stripped != null)
                        cg.replaceMethod(methods[i], stripped);
                }
            }
            trans.done();
            JavaClass target = cg.getJavaClass();
            target.setFileName(source.getFileName());
            return target;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return source;

    }
    public static String getMethodRepr(MethodGen mg) {
        StringBuffer sb =
            new StringBuffer(mg.getReturnType() + " " + mg.getName() + "(");
        Type[] types = mg.getArgumentTypes();
        for (int i = 0; i < types.length; i++) {
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(types[i].toString());
        }
        sb.append(")");
        logger.info("Method representation to enter: " + sb.toString());
        return sb.toString();
    }
    /**
     * @return
     */
    public abstract ObjectType getLogType();

    public static final int NOEXIT = 0;
    public static final int SIMPLEEXIT = 1;
    public static final int PARAMETEREXIT = 2;

    public static int level_exits = NOEXIT;

    public static final int REMOVELOGS = 0;
    public static final int LEAVELOGS = 1;
    public static final int FORKLOGS = 2;
    public static int level_logs = FORKLOGS;

    public static final int NOENTER = 0;
    public static final int SIMPLEENTER = 1;
    public static final int PARAMETERENTER = 2;
    public static int level_enters = NOENTER;
    public static final String ENTER_STRING = "enters: ";
    public static final String EXIT_STRING = "exits: ";
}
TOP

Related Classes of net.sf.just4log.transform.Transform

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.