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  import org.objectweb.asm.Constants;
11  import org.objectweb.asm.ClassAdapter;
12  import org.objectweb.asm.ClassVisitor;
13  import org.objectweb.asm.CodeVisitor;
14  import org.objectweb.asm.Type;
15  import org.objectweb.asm.Attribute;
16  import org.codehaus.aspectwerkz.transform.Context;
17  import org.codehaus.aspectwerkz.transform.TransformationUtil;
18  import org.codehaus.aspectwerkz.transform.TransformationConstants;
19  import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
20  import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
21  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
22  import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
23  
24  import java.util.List;
25  import java.util.Iterator;
26  import java.util.Set;
27  import java.lang.reflect.Modifier;
28  
29  /***
30   * Adds field and method wrappers when there has been at least one joinpoint emitted.
31   *
32   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
33   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
34   */
35  public class AddWrapperVisitor extends ClassAdapter implements Constants, TransformationConstants {
36  
37      private ContextImpl m_context;
38  
39      private Set m_addedMethods;
40  
41  
42      public AddWrapperVisitor(ClassVisitor classVisitor, Context context, Set alreadyAddedMethods) {
43          super(classVisitor);
44          m_context = (ContextImpl) context;
45          m_addedMethods = alreadyAddedMethods;
46      }
47  
48      /***
49       * Visits the class.
50       *
51       * @param access
52       * @param name
53       * @param superName
54       * @param interfaces
55       * @param sourceFile
56       */
57      public void visit(final int version, final int access,
58                        final String name,
59                        final String superName,
60                        final String[] interfaces,
61                        final String sourceFile) {
62          // iterate on the emitted joinpoints
63          // we don't need to filter more since the joinpoint type and the weaving phase did that for us
64          List jps = m_context.getEmittedJoinPoints();
65          for (Iterator iterator = jps.iterator(); iterator.hasNext();) {
66              EmittedJoinPoint emittedJoinPoint = (EmittedJoinPoint) iterator.next();
67              int jpType = emittedJoinPoint.getJoinPointType();
68              String calleeName = emittedJoinPoint.getCalleeMemberName();
69              if (Modifier.isPublic(emittedJoinPoint.getCalleeMemberModifiers())
70                  || !name.equals(emittedJoinPoint.getCalleeClassName())) {//TODO ?
71                  continue;
72              }
73              switch (jpType) {
74                  case (JoinPointType.FIELD_GET_INT) :
75                      createGetFieldWrapperMethod(
76                              Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()),
77                              name,
78                              emittedJoinPoint.getCalleeMemberName(),
79                              emittedJoinPoint.getCalleeMemberDesc()
80                      );
81                      break;
82                  case (JoinPointType.FIELD_SET_INT) :
83                          createPutFieldWrapperMethod(
84                                  Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()),
85                                  name,
86                                  emittedJoinPoint.getCalleeMemberName(),
87                                  emittedJoinPoint.getCalleeMemberDesc()
88                          );
89                      break;
90                  case (JoinPointType.METHOD_EXECUTION_INT) :
91                  case (JoinPointType.METHOD_CALL_INT) :
92                      createMethodWrapperMethod(
93                              emittedJoinPoint.getCalleeMemberModifiers(),
94                              name,
95                              emittedJoinPoint.getCalleeMemberName(),
96                              emittedJoinPoint.getCalleeMemberDesc(),
97                              new String[0],//TODO should throw Throwable ??
98                              null//TODO do we need the attr ??
99                      );
100                     break;
101             }
102         }
103 
104         super.visit(version, access, name, superName, interfaces, sourceFile);
105     }
106 
107     /***
108      * Creates a public wrapper method that delegates to the GETFIELD instruction of the non-public field.
109      *
110      * @param isStaticField
111      * @param declaringTypeName
112      * @param name
113      * @param desc
114      */
115     private void createGetFieldWrapperMethod(final boolean isStaticField,
116                                              final String declaringTypeName,
117                                              final String name,
118                                              final String desc) {
119         String wrapperName = TransformationUtil.getWrapperMethodName(
120                 name, desc, declaringTypeName, GETFIELD_WRAPPER_METHOD_PREFIX
121         );
122 
123         StringBuffer signature = new StringBuffer();
124         signature.append('(');
125         signature.append(')');
126         signature.append(desc);
127 
128         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, signature.toString());
129         if (m_addedMethods.contains(wrapperKey)) {
130             return;
131         }
132         m_addedMethods.add(wrapperKey);
133 
134         int modifiers = ACC_SYNTHETIC;
135         if (isStaticField) {
136             modifiers |= ACC_STATIC;
137         }
138 
139         CodeVisitor mv = cv.visitMethod(
140                 modifiers,
141                 wrapperName,
142                 signature.toString(),
143                 new String[]{},
144                 null
145         );
146 
147         if (isStaticField) {
148             mv.visitFieldInsn(GETSTATIC, declaringTypeName, name, desc);
149         } else {
150             mv.visitVarInsn(ALOAD, 0);
151             mv.visitFieldInsn(GETFIELD, declaringTypeName, name, desc);
152         }
153 
154         AsmHelper.addReturnStatement(mv, Type.getType(desc));
155         mv.visitMaxs(0, 0);
156     }
157 
158     /***
159      * Creates a public wrapper method that delegates to the PUTFIELD instruction of the non-public field.
160      * Static method if field is static (PUTSTATIC instr)
161      *
162      * @param isStaticField
163      * @param declaringTypeName
164      * @param name
165      * @param desc
166      */
167     private void createPutFieldWrapperMethod(boolean isStaticField,
168                                              final String declaringTypeName,
169                                              final String name,
170                                              final String desc) {
171         String wrapperName = TransformationUtil.getWrapperMethodName(
172                 name, desc, declaringTypeName, PUTFIELD_WRAPPER_METHOD_PREFIX
173         );
174 
175         StringBuffer signature = new StringBuffer();
176         signature.append('(');
177         signature.append(desc);
178         signature.append(')');
179         signature.append('V');
180 
181         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, signature.toString());
182         if (m_addedMethods.contains(wrapperKey)) {
183             return;
184         }
185         m_addedMethods.add(wrapperKey);
186 
187         int modifiers = ACC_SYNTHETIC;
188         if (isStaticField) {
189             modifiers |= ACC_STATIC;
190         }
191 
192         CodeVisitor mv = cv.visitMethod(
193                 modifiers,
194                 wrapperName,
195                 signature.toString(),
196                 new String[]{},
197                 null
198         );
199 
200         Type fieldType = Type.getType(desc);
201         if (isStaticField) {
202             AsmHelper.loadArgumentTypes(mv, new Type[]{fieldType}, true);
203             mv.visitFieldInsn(PUTSTATIC, declaringTypeName, name, desc);
204         } else {
205             mv.visitVarInsn(ALOAD, 0);
206             AsmHelper.loadArgumentTypes(mv, new Type[]{fieldType}, false);
207             mv.visitFieldInsn(PUTFIELD, declaringTypeName, name, desc);
208         }
209 
210         AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
211         mv.visitMaxs(0, 0);
212     }
213 
214     /***
215      * Creates a public wrapper method that delegates to the non-public target method.
216      *
217      * @param access
218      * @param declaringTypeName
219      * @param name
220      * @param desc
221      * @param exceptions
222      * @param attrs
223      */
224     private void createMethodWrapperMethod(final int access,
225                                            final String declaringTypeName,
226                                            final String name,
227                                            final String desc,
228                                            final String[] exceptions,
229                                            final Attribute attrs) {
230         final String wrapperName = TransformationUtil.getWrapperMethodName(
231                 name, desc, declaringTypeName, INVOKE_WRAPPER_METHOD_PREFIX
232         );
233 
234         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, desc);
235         if (m_addedMethods.contains(wrapperKey)) {
236             return;
237         }
238         m_addedMethods.add(wrapperKey);
239 
240         int modifiers = ACC_SYNTHETIC;
241         if (Modifier.isStatic(access)) {
242             modifiers |= ACC_STATIC;
243         }
244 
245         CodeVisitor mv = super.visitMethod(
246                 modifiers,
247                 wrapperName,
248                 desc,
249                 exceptions,
250                 attrs
251         );
252 
253         if (Modifier.isStatic(access)) {
254             AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
255             mv.visitMethodInsn(INVOKESTATIC, declaringTypeName, name, desc);
256         } else {
257             mv.visitVarInsn(ALOAD, 0);
258             AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
259             mv.visitMethodInsn(INVOKEVIRTUAL, declaringTypeName, name, desc);
260         }
261 
262         AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
263 
264         mv.visitMaxs(0, 0);
265     }
266 
267 }