Package org.codehaus.aspectwerkz.transform.inlining

Source Code of org.codehaus.aspectwerkz.transform.inlining.WrapperMethodClassAdapter

/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved.                 *
* http://aspectwerkz.codehaus.org                                                    *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license      *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package org.codehaus.aspectwerkz.transform.inlining;

import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;

import org.objectweb.asm.*;
import org.codehaus.aspectwerkz.transform.Context;
import org.codehaus.aspectwerkz.transform.TransformationUtil;
import org.codehaus.aspectwerkz.definition.SystemDefinition;
import org.codehaus.aspectwerkz.expression.ExpressionContext;
import org.codehaus.aspectwerkz.expression.PointcutType;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.reflect.MethodInfo;
import org.codehaus.aspectwerkz.reflect.FieldInfo;

/**
* Creates a public wrapper methods that delegates to the non-public target methods.
* <p/>
* TODO: the inner class model is broken since Inner classes are impl thru a java compiler trick
* with wrapper method (package private static access$100(Outer) etc). We thus need to add equivalent
* wrapper methods, which means a huge penalty for RW.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
*/
public class WrapperMethodClassAdapter extends ClassAdapter implements Constants, TransformationConstants {

    private final ContextImpl m_ctx;
    private String m_declaringTypeName;
    private final ClassInfo m_classInfo;
    private int m_sequence = 1;

    /**
     * Creates a new class adapter.
     *
     * @param cv
     * @param classInfo
     * @param ctx
     */
    public WrapperMethodClassAdapter(final ClassVisitor cv, final ClassInfo classInfo, final Context ctx) {
        super(cv);
        m_classInfo = classInfo;
        m_ctx = (ContextImpl) ctx;
    }

    /**
     * Visits the class.
     *
     * @param access
     * @param name
     * @param superName
     * @param interfaces
     * @param sourceFile
     */
    public void visit(final int access,
                      final String name,
                      final String superName,
                      final String[] interfaces,
                      final String sourceFile) {
        m_declaringTypeName = name;
        super.visit(access, name, superName, interfaces, sourceFile);
    }

    /**
     * Visits the fields. Changes the signature for matching fields to public.
     *
     * @param access
     * @param name
     * @param desc
     * @param value
     * @param attrs
     */
    public void visitField(final int access,
                           final String name,
                           final String desc,
                           final Object value,
                           final Attribute attrs) {

        if (m_declaringTypeName.endsWith(JoinPointCompiler.JOIN_POINT_CLASS_SUFFIX) ||
            name.startsWith(TransformationUtil.ASPECTWERKZ_PREFIX)) {
            super.visitField(access, name, desc, value, attrs);
            return;
        }
        int hash = AsmHelper.calculateFieldHash(name, desc);
        FieldInfo fieldInfo = m_classInfo.getField(hash);
        if (fieldInfo == null) {
            throw new Error(
                    "field info metadata structure could not be build for field: " + m_declaringTypeName + '.' + name +
                    ':' +
                    desc
            );
        }

        ExpressionContext ctx = new ExpressionContext(PointcutType.SET, fieldInfo, null);

        if (fieldFilter(m_ctx.getDefinitions(), ctx, fieldInfo) || Modifier.isPublic(access)) {
            super.visitField(access, name, desc, value, attrs);
        } else {
            int modifiers = ACC_PUBLIC;
            if (Modifier.isStatic(access)) {
                modifiers |= ACC_STATIC;
            }
            super.visitField(modifiers, name, desc, value, attrs);
        }
    }

    /**
     * Visits the methods.
     *
     * @param access
     * @param name
     * @param desc
     * @param exceptions
     * @param attrs
     * @return
     */
    public CodeVisitor visitMethod(final int access,
                                   final String name,
                                   final String desc,
                                   final String[] exceptions,
                                   final Attribute attrs) {
        if (Modifier.isPublic(access) ||
            INIT_METHOD_NAME.equals(name) ||
            CLINIT_METHOD_NAME.equals(name) ||
            name.startsWith(TransformationUtil.ASPECTWERKZ_PREFIX) ||
            name.startsWith("access$")) {//TODO filter on synthetic method ?
            return super.visitMethod(access, name, desc, exceptions, attrs);
        }

        int hash = AsmHelper.calculateMethodHash(name, desc);
        MethodInfo methodInfo = m_classInfo.getMethod(hash);
        if (methodInfo == null) {
            throw new Error(
                    "method info metadata structure could not be build for method: " + m_declaringTypeName + '.' +
                    name +
                    ':' +
                    desc
            );
        }

        ExpressionContext ctx = new ExpressionContext(PointcutType.EXECUTION, methodInfo, methodInfo);
        //FIXME - match for CALL pc as well ??

        if (methodFilter(m_ctx.getDefinitions(), ctx, methodInfo)) {
            return cv.visitMethod(access, name, desc, exceptions, attrs);
        } else {
            m_sequence++; // single place of incrementation, is used in multiple places
            m_ctx.markAsAdvised();
            createWrapperMethod(access, name, desc, exceptions, attrs);
            return cv.visitMethod(access, name, desc, exceptions, attrs);
        }
    }


    /**
     * Creates a public wrapper method that delegates to the non-public target method.
     *
     * @param access
     * @param name
     * @param desc
     * @param exceptions
     * @param attrs
     */
    private void createWrapperMethod(final int access,
                                     final String name,
                                     final String desc,
                                     final String[] exceptions,
                                     final Attribute attrs) {

        int modifiers = ACC_SYNTHETIC;
        if (Modifier.isStatic(access)) {
            modifiers |= ACC_STATIC;
        }
        CodeVisitor mv = super.visitMethod(
                modifiers,
                TransformationUtil.getWrapperMethodName(name, m_sequence, m_declaringTypeName),
                desc,
                exceptions,
                attrs
        );

        if (Modifier.isStatic(access)) {
            AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
            mv.visitMethodInsn(INVOKESTATIC, m_declaringTypeName, name, desc);
        } else {
            mv.visitVarInsn(ALOAD, 0);
            AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
            mv.visitMethodInsn(INVOKEVIRTUAL, m_declaringTypeName, name, desc);
        }

        AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));

        mv.visitMaxs(0, 0);
    }

    /**
     * Filters out the methods that are not eligible for transformation.
     *
     * @param definitions
     * @param ctx
     * @param methodInfo
     * @return boolean true if the method should be filtered out
     */
    public static boolean methodFilter(final List definitions,
                                       final ExpressionContext ctx,
                                       final MethodInfo methodInfo) {
        if (Modifier.isAbstract(methodInfo.getModifiers())
            || Modifier.isNative(methodInfo.getModifiers())
            || methodInfo.getName().equals(INIT_METHOD_NAME)
            || methodInfo.getName().equals(CLINIT_METHOD_NAME)
            || methodInfo.getName().startsWith(TransformationUtil.ORIGINAL_METHOD_PREFIX)) {
            return true;
        }
        for (Iterator it = definitions.iterator(); it.hasNext();) {
            if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
                return false;
            } else {
                continue;
            }
        }
        return true;
    }

    /**
     * Filters out the fields that are not eligible for transformation.
     *
     * @param definitions
     * @param ctx
     * @param fieldInfo
     * @return boolean true if the field should be filtered out
     */
    public boolean fieldFilter(final List definitions,
                               final ExpressionContext ctx,
                               final FieldInfo fieldInfo) {
        if (fieldInfo.getName().startsWith(TransformationUtil.ORIGINAL_METHOD_PREFIX)) {
            return true;
        }
        for (Iterator it = definitions.iterator(); it.hasNext();) {
            if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
                return false;
            } else {
                continue;
            }
        }
        return true;
    }
}
TOP

Related Classes of org.codehaus.aspectwerkz.transform.inlining.WrapperMethodClassAdapter

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.