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><clinit></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
102 createProxyMethod(access, name, desc, exceptions, attrs);
103
104
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
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
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 }