View Javadoc

    1   /***************************************************************************************
    2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
    3    * http://aspectwerkz.codehaus.org                                                    *
    4    * ---------------------------------------------------------------------------------- *
    5    * The software in this package is published under the terms of the LGPL license      *
    6    * a copy of which has been included with this distribution in the license.txt file.  *
    7    **************************************************************************************/
    8   package org.codehaus.aspectwerkz.transform.inlining.weaver;
    9
    10
    11  import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
    12  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    13  import org.codehaus.aspectwerkz.transform.Context;
    14  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    15  import org.codehaus.aspectwerkz.transform.TransformationUtil;
    16  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    17  import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
    18  import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
    19  import org.objectweb.asm.Attribute;
    20  import org.objectweb.asm.ClassAdapter;
    21  import org.objectweb.asm.ClassVisitor;
    22  import org.objectweb.asm.CodeVisitor;
    23  import org.objectweb.asm.Type;
    24
    25  import java.util.Set;
    26
    27  /***
    28   * Adds a "proxy method" to the <tt>&lt;clinit&gt;</tt> that matches an
    29   * <tt>staticinitialization</tt> pointcut as well as prefixing the "original method"
    30   * (see {@link org.codehaus.aspectwerkz.transform.TransformationUtil#getPrefixedOriginalClinitName(String)}).
    31   * <br/>
    32   *
    33   * @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
    34   */
    35  public class StaticInitializationVisitor extends ClassAdapter implements TransformationConstants {
    36
    37  	private final ContextImpl m_ctx;
    38  	private String m_declaringTypeName;
    39      private final Set m_addedMethods;
    40
    41  	/***
    42  	 * Creates a new class adapter.
    43  	 *
    44  	 * @param cv
    45  	 * @param ctx
    46       * @param addedMethods already added methods by AW
    47  	 */
    48  	public StaticInitializationVisitor(	final ClassVisitor cv,
    49  										final Context ctx,
    50                                          final Set addedMethods) {
    51  		super(cv);
    52  		m_ctx = (ContextImpl) ctx;
    53          m_addedMethods = addedMethods;
    54  	}
    55
    56  	/***
    57  	 * Visits the class.
    58  	 *
    59  	 * @param access
    60  	 * @param name
    61  	 * @param superName
    62  	 * @param interfaces
    63  	 * @param sourceFile
    64  	 */
    65  	public void visit(	final int version,
    66  						final int access,
    67  						final String name,
    68  						final String superName,
    69  						final String[] interfaces,
    70  						final String sourceFile) {
    71  		m_declaringTypeName = name;
    72  		super.visit(version, access, name, superName, interfaces, sourceFile);
    73  	}
    74
    75  	/***
    76  	 * Visits the methods.
    77  	 *
    78  	 * @param access
    79  	 * @param name
    80  	 * @param desc
    81  	 * @param exceptions
    82  	 * @param attrs
    83  	 * @return
    84  	 */
    85  	public CodeVisitor visitMethod(	final int access,
    86  									final String name,
    87  									final String desc,
    88  									final String[] exceptions,
    89  									final Attribute attrs) {
    90  		if(!CLINIT_METHOD_NAME.equals(name)) {
    91  			return super.visitMethod(access, name, desc, exceptions, attrs);
    92  		}
    93
    94  		String prefixedOriginalName = TransformationUtil.getPrefixedOriginalClinitName(m_declaringTypeName);
    95          if (m_addedMethods.contains(AlreadyAddedMethodAdapter.getMethodKey(prefixedOriginalName, CLINIT_METHOD_SIGNATURE))) {
    96              return super.visitMethod(access, name, desc, exceptions, attrs);
    97          }
    98
    99  		m_ctx.markAsAdvised();
    100
    101 		// create the proxy for the original method
    102 		createProxyMethod(access, name, desc, exceptions, attrs);
    103
    104 		// prefix the original method
    105 		return cv.visitMethod(access + ACC_PUBLIC, prefixedOriginalName, desc, exceptions, attrs);
    106 	}
    107
    108 	/***
    109 	 * Creates the "proxy method", e.g. the method that has the same name and
    110 	 * signature as the original method but a completely other implementation.
    111 	 *
    112 	 * @param access
    113 	 * @param name
    114 	 * @param desc
    115 	 * @param exceptions
    116 	 * @param attrs
    117 	 */
    118 	private void createProxyMethod(	final int access,
    119 									final String name,
    120 									final String desc,
    121 									final String[] exceptions,
    122 									final Attribute attrs) {
    123 		CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions, attrs);
    124
    125         //caller instance is null
    126 		mv.visitInsn(ACONST_NULL);
    127
    128 		int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
    129 		String joinPointClassName = TransformationUtil
    130 				.getJoinPointClassName(	m_declaringTypeName,
    131 										name,
    132 										desc,
    133 										m_declaringTypeName,
    134 										JoinPointType.STATIC_INITIALIZATION_INT,
    135 										joinPointHash);
    136
    137 		mv.visitMethodInsn(INVOKESTATIC,
    138 		        joinPointClassName,
    139 		        INVOKE_METHOD_NAME,
    140 		        TransformationUtil.getInvokeSignatureForCodeJoinPoints(	access,
    141 																		desc,
    142 																		m_declaringTypeName,
    143 																		m_declaringTypeName));
    144
    145 		AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
    146 		mv.visitMaxs(0, 0);
    147
    148 		// emit the joinpoint
    149 		m_ctx.addEmittedJoinPoint(
    150 		        new EmittedJoinPoint(JoinPointType.STATIC_INITIALIZATION_INT,
    151 		                             m_declaringTypeName,
    152 		                             name,
    153 		                             desc,
    154 		                             access,
    155 		                             m_declaringTypeName,
    156 		                             name,
    157 		                             desc,
    158 		                             access,
    159 		                             joinPointHash,
    160 		                             joinPointClassName,
    161 		                             EmittedJoinPoint.NO_LINE_NUMBER
    162 		        )
    163 		);
    164 	}
    165 }