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