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.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 MethodExecutionJoinPointCompiler extends AbstractJoinPointCompiler {
26  
27      /***
28       * Creates a new join point compiler instance.
29       *
30       * @param model
31       */
32      MethodExecutionJoinPointCompiler(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          // create the method argument fields
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  
51          m_fieldNames = fieldNames;
52  
53          m_cw.visitField(
54                  ACC_PRIVATE + ACC_STATIC,
55                  SIGNATURE_FIELD_NAME,
56                  METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE,
57                  null,
58                  null
59          );
60      }
61  
62      /***
63       * Creates the signature for the join point.
64       * <p/>
65       * FIXME signature field should NOT be of type Signature but of the specific type (update all refs as well)
66       *
67       * @param cv
68       */
69      protected void createSignature(final CodeVisitor cv) {
70          cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
71          cv.visitLdcInsn(new Integer(m_joinPointHash));
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          // load the target instance (arg0 else not available for static target)
97          if (!Modifier.isStatic(m_calleeMemberModifiers)) {
98              cv.visitVarInsn(ALOAD, 0);
99          }
100 
101         String joinPointName = null; // can be prefixed
102 
103         loadArgumentMemberFields(cv, argStartIndex);
104         joinPointName = TransformationUtil.getPrefixedOriginalMethodName(
105                 m_calleeMemberName,
106                 m_calleeClassName
107         );
108         if (Modifier.isStatic(m_calleeMemberModifiers)) {
109             cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
110         } else {
111             cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
112         }
113 
114     }
115 
116     /***
117      * Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
118      * local join point instance.
119      *
120      * @param cv
121      */
122     protected void createJoinPointInvocation(final CodeVisitor cv) {
123 
124         // load the target instance member field unless calleeMember is static
125         if (!Modifier.isStatic(m_calleeMemberModifiers)) {
126             cv.visitVarInsn(ALOAD, 0);
127             cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
128         }
129 
130         String joinPointName;
131         loadArguments(cv);
132         joinPointName = TransformationUtil.getPrefixedOriginalMethodName(
133                 m_calleeMemberName,
134                 m_calleeClassName
135         );
136         if (Modifier.isStatic(m_calleeMemberModifiers)) {
137             cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
138         } else {
139             cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
140         }
141     }
142 
143     /***
144      * Returns the join points return type.
145      *
146      * @return
147      */
148     protected Type getJoinPointReturnType() {
149         return Type.getReturnType(m_calleeMemberDesc);
150     }
151 
152     /***
153      * Returns the join points argument type(s).
154      *
155      * @return
156      */
157     protected Type[] getJoinPointArgumentTypes() {
158         return Type.getArgumentTypes(m_calleeMemberDesc);
159     }
160 
161     /***
162      * Creates the getRtti method
163      */
164     protected void createGetRttiMethod() {
165         CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC, GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null, null);
166 
167         // new MethodRttiImpl( .. )
168         cv.visitTypeInsn(NEW, METHOD_RTTI_IMPL_CLASS_NAME);
169         cv.visitInsn(DUP);
170         cv.visitFieldInsn(
171                 GETSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
172         );
173         cv.visitVarInsn(ALOAD, 0);
174         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
175         cv.visitVarInsn(ALOAD, 0);
176         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
177         cv.visitMethodInsn(
178                 INVOKESPECIAL, METHOD_RTTI_IMPL_CLASS_NAME, INIT_METHOD_NAME, METHOD_RTTI_IMPL_INIT_SIGNATURE
179         );
180 
181         // set the arguments
182         cv.visitInsn(DUP);
183         createArgumentArrayAt(cv, 1);
184         cv.visitVarInsn(ALOAD, 1);
185         cv.visitMethodInsn(
186                 INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_PARAMETER_VALUES_METHOD_NAME,
187                 SET_PARAMETER_VALUES_METHOD_SIGNATURE
188         );
189 
190         // set the Returned instance
191         if (m_returnType.getSort() != Type.VOID) {
192             cv.visitInsn(DUP);
193             if (AsmHelper.isPrimitive(m_returnType)) {
194                 AsmHelper.prepareWrappingOfPrimitiveType(cv, m_returnType);
195                 cv.visitVarInsn(ALOAD, 0);
196                 cv.visitFieldInsn(
197                         GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
198                 );
199                 AsmHelper.wrapPrimitiveType(cv, m_returnType);
200             } else {
201                 cv.visitVarInsn(ALOAD, 0);
202                 cv.visitFieldInsn(
203                         GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
204                 );
205             }
206             cv.visitMethodInsn(
207                     INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_RETURN_VALUE_METHOD_NAME,
208                     SET_RETURN_VALUE_METHOD_SIGNATURE
209             );
210         }
211 
212         cv.visitInsn(ARETURN);
213         cv.visitMaxs(0, 0);
214     }
215 
216     /***
217      * Creates the getSignature method.
218      */
219     protected void createGetSignatureMethod() {
220         CodeVisitor cv = m_cw.visitMethod(
221                 ACC_PUBLIC,
222                 GET_SIGNATURE_METHOD_NAME,
223                 GET_SIGNATURE_METHOD_SIGNATURE,
224                 null,
225                 null
226         );
227 
228         cv.visitFieldInsn(
229                 GETSTATIC, m_joinPointClassName,
230                 SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
231         );
232         cv.visitInsn(ARETURN);
233         cv.visitMaxs(0, 0);
234     }
235 }