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.compiler;
9
10 import org.objectweb.asm.CodeVisitor;
11 import org.objectweb.asm.Type;
12
13 import org.codehaus.aspectwerkz.transform.TransformationUtil;
14 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
15
16 import java.lang.reflect.Modifier;
17
18 /***
19 * A compiler that compiles/generates a class that represents a specific join point, a class which invokes the advices
20 * and the target join point statically.
21 *
22 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
23 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
24 */
25 public class MethodCallJoinPointCompiler extends AbstractJoinPointCompiler {
26
27 /***
28 * Creates a new join point compiler instance.
29 *
30 * @param model
31 */
32 MethodCallJoinPointCompiler(final CompilationInfo.Model model) {
33 super(model);
34 }
35
36 /***
37 * Creates join point specific fields.
38 */
39 protected void createJoinPointSpecificFields() {
40 String[] fieldNames = null;
41
42 Type[] argumentTypes = Type.getArgumentTypes(m_calleeMemberDesc);
43 fieldNames = new String[argumentTypes.length];
44 for (int i = 0; i < argumentTypes.length; i++) {
45 Type argumentType = argumentTypes[i];
46 String fieldName = ARGUMENT_FIELD + i;
47 fieldNames[i] = fieldName;
48 m_cw.visitField(ACC_PRIVATE, fieldName, argumentType.getDescriptor(), null, null);
49 }
50 m_fieldNames = fieldNames;
51
52 m_cw.visitField(
53 ACC_PRIVATE + ACC_STATIC,
54 SIGNATURE_FIELD_NAME,
55 METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE,
56 null,
57 null
58 );
59 }
60
61 /***
62 * Creates the signature for the join point.
63 * <p/>
64 * FIXME signature field should NOT be of type Signature but of the specific type (update all refs as well)
65 *
66 * @param cv
67 */
68 protected void createSignature(final CodeVisitor cv) {
69 cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
70 cv.visitLdcInsn(new Integer(m_joinPointHash));
71
72
73 cv.visitMethodInsn(
74 INVOKESTATIC,
75 SIGNATURE_FACTORY_CLASS,
76 NEW_METHOD_SIGNATURE_METHOD_NAME,
77 NEW_METHOD_SIGNATURE_METHOD_SIGNATURE
78 );
79 cv.visitFieldInsn(
80 PUTSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
81 );
82
83 }
84
85 /***
86 * Optimized implementation that does not retrieve the parameters from the join point instance but is passed
87 * directly to the method from the input parameters in the 'invoke' method. Can only be used if no around advice
88 * exists.
89 *
90 * @param cv
91 * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
92 */
93 protected void createInlinedJoinPointInvocation(final CodeVisitor cv, final boolean isOptimizedJoinPoint,
94 final int argStartIndex, final int joinPointIndex) {
95
96
97 if (!Modifier.isStatic(m_calleeMemberModifiers)) {
98 cv.visitVarInsn(ALOAD, 0);
99 }
100
101 String joinPointName = null;
102
103 loadArgumentMemberFields(cv, argStartIndex);
104
105
106 if (!Modifier.isPublic(m_calleeMemberModifiers)) {
107 joinPointName = TransformationUtil.getWrapperMethodName(
108 m_calleeMemberName,
109 m_calleeMemberDesc,
110 m_calleeClassName,
111 INVOKE_WRAPPER_METHOD_PREFIX
112 );
113 } else {
114 joinPointName = m_calleeMemberName;
115 }
116
117 if (Modifier.isStatic(m_calleeMemberModifiers)) {
118 cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
119 } else if (isInvokeInterface(m_calleeMemberModifiers)) {
120
121 cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName, joinPointName, m_calleeMemberDesc);
122 } else {
123 cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
124 }
125 }
126
127 /***
128 * Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
129 * local join point instance.
130 *
131 * @param cv
132 */
133 protected void createJoinPointInvocation(final CodeVisitor cv) {
134
135
136 if (!Modifier.isStatic(m_calleeMemberModifiers)) {
137 cv.visitVarInsn(ALOAD, 0);
138 cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
139 }
140
141 String joinPointName;
142 loadArguments(cv);
143 if (!Modifier.isPublic(m_calleeMemberModifiers)) {
144 joinPointName = TransformationUtil.getWrapperMethodName(
145 m_calleeMemberName,
146 m_calleeMemberDesc,
147 m_calleeClassName,
148 INVOKE_WRAPPER_METHOD_PREFIX
149 );
150 } else {
151 joinPointName = m_calleeMemberName;
152 }
153
154 if (Modifier.isStatic(m_calleeMemberModifiers)) {
155 cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
156 } else if (isInvokeInterface(m_calleeMemberModifiers)) {
157
158 cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName, joinPointName, m_calleeMemberDesc);
159 } else {
160 cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
161 }
162 }
163
164 /***
165 * Returns the join points return type.
166 *
167 * @return
168 */
169 protected Type getJoinPointReturnType() {
170 return Type.getReturnType(m_calleeMemberDesc);
171 }
172
173 /***
174 * Returns the join points argument type(s).
175 *
176 * @return
177 */
178 protected Type[] getJoinPointArgumentTypes() {
179 return Type.getArgumentTypes(m_calleeMemberDesc);
180 }
181
182 /***
183 * Creates the getRtti method
184 */
185 protected void createGetRttiMethod() {
186 CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC, GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null, null);
187
188
189 cv.visitTypeInsn(NEW, METHOD_RTTI_IMPL_CLASS_NAME);
190 cv.visitInsn(DUP);
191 cv.visitFieldInsn(
192 GETSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
193 );
194 cv.visitVarInsn(ALOAD, 0);
195 cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
196 cv.visitVarInsn(ALOAD, 0);
197 cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
198 cv.visitMethodInsn(
199 INVOKESPECIAL, METHOD_RTTI_IMPL_CLASS_NAME, INIT_METHOD_NAME, METHOD_RTTI_IMPL_INIT_SIGNATURE
200 );
201
202
203 cv.visitInsn(DUP);
204 createArgumentArrayAt(cv, 1);
205 cv.visitVarInsn(ALOAD, 1);
206 cv.visitMethodInsn(
207 INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_PARAMETER_VALUES_METHOD_NAME,
208 SET_PARAMETER_VALUES_METHOD_SIGNATURE
209 );
210
211
212 if (m_returnType.getSort() != Type.VOID) {
213 cv.visitInsn(DUP);
214 if (AsmHelper.isPrimitive(m_returnType)) {
215 AsmHelper.prepareWrappingOfPrimitiveType(cv, m_returnType);
216 cv.visitVarInsn(ALOAD, 0);
217 cv.visitFieldInsn(
218 GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
219 );
220 AsmHelper.wrapPrimitiveType(cv, m_returnType);
221 } else {
222 cv.visitVarInsn(ALOAD, 0);
223 cv.visitFieldInsn(
224 GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
225 );
226 }
227 cv.visitMethodInsn(
228 INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_RETURN_VALUE_METHOD_NAME,
229 SET_RETURN_VALUE_METHOD_SIGNATURE
230 );
231 }
232
233 cv.visitInsn(ARETURN);
234 cv.visitMaxs(0, 0);
235 }
236
237 /***
238 * Creates the getSignature method.
239 */
240 protected void createGetSignatureMethod() {
241 CodeVisitor cv = m_cw.visitMethod(
242 ACC_PUBLIC,
243 GET_SIGNATURE_METHOD_NAME,
244 GET_SIGNATURE_METHOD_SIGNATURE,
245 null,
246 null
247 );
248
249 cv.visitFieldInsn(
250 GETSTATIC, m_joinPointClassName,
251 SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
252 );
253 cv.visitInsn(ARETURN);
254 cv.visitMaxs(0, 0);
255 }
256
257 /***
258 * See AW-253
259 * For INVOKE INTERFACE, we are using a custom modifier to track it down in order to avoid to do the
260 * hierarchy resolution ourself here
261 */
262 private boolean isInvokeInterface(int modifier) {
263 return (modifier & MODIFIER_INVOKEINTERFACE) != 0;
264 }
265 }