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 }