001: /**************************************************************************************
002: * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.transform.inlining.weaver;
008:
009: import org.objectweb.asm.Constants;
010: import org.objectweb.asm.ClassAdapter;
011: import org.objectweb.asm.ClassVisitor;
012: import org.objectweb.asm.CodeVisitor;
013: import org.objectweb.asm.Type;
014: import org.objectweb.asm.Attribute;
015: import org.codehaus.aspectwerkz.transform.Context;
016: import org.codehaus.aspectwerkz.transform.TransformationUtil;
017: import org.codehaus.aspectwerkz.transform.TransformationConstants;
018: import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
019: import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
020: import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
021: import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
022:
023: import java.util.List;
024: import java.util.Iterator;
025: import java.util.Set;
026: import java.lang.reflect.Modifier;
027:
028: /**
029: * Adds field and method wrappers when there has been at least one joinpoint emitted.
030: *
031: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
032: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
033: */
034: public class AddWrapperVisitor extends ClassAdapter implements
035: Constants, TransformationConstants {
036:
037: private ContextImpl m_context;
038:
039: private Set m_addedMethods;
040:
041: public AddWrapperVisitor(ClassVisitor classVisitor,
042: Context context, Set alreadyAddedMethods) {
043: super (classVisitor);
044: m_context = (ContextImpl) context;
045: m_addedMethods = alreadyAddedMethods;
046: }
047:
048: /**
049: * Visits the class.
050: *
051: * @param access
052: * @param name
053: * @param superName
054: * @param interfaces
055: * @param sourceFile
056: */
057: public void visit(final int version, final int access,
058: final String name, final String super Name,
059: final String[] interfaces, final String sourceFile) {
060: // iterate on the emitted joinpoints
061: // we don't need to filter more since the joinpoint type and the weaving phase did that for us
062: List jps = m_context.getEmittedJoinPoints();
063: for (Iterator iterator = jps.iterator(); iterator.hasNext();) {
064: EmittedJoinPoint emittedJoinPoint = (EmittedJoinPoint) iterator
065: .next();
066: int jpType = emittedJoinPoint.getJoinPointType();
067: String calleeName = emittedJoinPoint.getCalleeMemberName();
068: if (Modifier.isPublic(emittedJoinPoint
069: .getCalleeMemberModifiers())
070: || !name.equals(emittedJoinPoint
071: .getCalleeClassName())) {//TODO ?
072: continue;
073: }
074: switch (jpType) {
075: case (JoinPointType.FIELD_GET_INT):
076: createGetFieldWrapperMethod(Modifier
077: .isStatic(emittedJoinPoint
078: .getCalleeMemberModifiers()), name,
079: emittedJoinPoint.getCalleeMemberName(),
080: emittedJoinPoint.getCalleeMemberDesc());
081: break;
082: case (JoinPointType.FIELD_SET_INT):
083: createPutFieldWrapperMethod(Modifier
084: .isStatic(emittedJoinPoint
085: .getCalleeMemberModifiers()), name,
086: emittedJoinPoint.getCalleeMemberName(),
087: emittedJoinPoint.getCalleeMemberDesc());
088: break;
089: case (JoinPointType.METHOD_EXECUTION_INT):
090: case (JoinPointType.METHOD_CALL_INT):
091: createMethodWrapperMethod(emittedJoinPoint
092: .getCalleeMemberModifiers(), name,
093: emittedJoinPoint.getCalleeMemberName(),
094: emittedJoinPoint.getCalleeMemberDesc(),
095: new String[0],//TODO should throw Throwable ??
096: null//TODO do we need the attr ??
097: );
098: break;
099: }
100: }
101:
102: super .visit(version, access, name, super Name, interfaces,
103: sourceFile);
104: }
105:
106: /**
107: * Creates a public wrapper method that delegates to the GETFIELD instruction of the non-public field.
108: *
109: * @param isStaticField
110: * @param declaringTypeName
111: * @param name
112: * @param desc
113: */
114: private void createGetFieldWrapperMethod(
115: final boolean isStaticField,
116: final String declaringTypeName, final String name,
117: final String desc) {
118: String wrapperName = TransformationUtil.getWrapperMethodName(
119: name, desc, declaringTypeName,
120: GETFIELD_WRAPPER_METHOD_PREFIX);
121:
122: StringBuffer signature = new StringBuffer();
123: signature.append('(');
124: signature.append(')');
125: signature.append(desc);
126:
127: final String wrapperKey = AlreadyAddedMethodAdapter
128: .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(modifiers, wrapperName,
140: signature.toString(), new String[] {}, null);
141:
142: if (isStaticField) {
143: mv.visitFieldInsn(GETSTATIC, declaringTypeName, name, desc);
144: } else {
145: mv.visitVarInsn(ALOAD, 0);
146: mv.visitFieldInsn(GETFIELD, declaringTypeName, name, desc);
147: }
148:
149: AsmHelper.addReturnStatement(mv, Type.getType(desc));
150: mv.visitMaxs(0, 0);
151: }
152:
153: /**
154: * Creates a public wrapper method that delegates to the PUTFIELD instruction of the non-public field.
155: * Static method if field is static (PUTSTATIC instr)
156: *
157: * @param isStaticField
158: * @param declaringTypeName
159: * @param name
160: * @param desc
161: */
162: private void createPutFieldWrapperMethod(boolean isStaticField,
163: final String declaringTypeName, final String name,
164: final String desc) {
165: String wrapperName = TransformationUtil.getWrapperMethodName(
166: name, desc, declaringTypeName,
167: PUTFIELD_WRAPPER_METHOD_PREFIX);
168:
169: StringBuffer signature = new StringBuffer();
170: signature.append('(');
171: signature.append(desc);
172: signature.append(')');
173: signature.append('V');
174:
175: final String wrapperKey = AlreadyAddedMethodAdapter
176: .getMethodKey(wrapperName, signature.toString());
177: if (m_addedMethods.contains(wrapperKey)) {
178: return;
179: }
180: m_addedMethods.add(wrapperKey);
181:
182: int modifiers = ACC_SYNTHETIC;
183: if (isStaticField) {
184: modifiers |= ACC_STATIC;
185: }
186:
187: CodeVisitor mv = cv.visitMethod(modifiers, wrapperName,
188: signature.toString(), new String[] {}, null);
189:
190: Type fieldType = Type.getType(desc);
191: if (isStaticField) {
192: AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType },
193: true);
194: mv.visitFieldInsn(PUTSTATIC, declaringTypeName, name, desc);
195: } else {
196: mv.visitVarInsn(ALOAD, 0);
197: AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType },
198: false);
199: mv.visitFieldInsn(PUTFIELD, declaringTypeName, name, desc);
200: }
201:
202: AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
203: mv.visitMaxs(0, 0);
204: }
205:
206: /**
207: * Creates a public wrapper method that delegates to the non-public target method.
208: *
209: * @param access
210: * @param declaringTypeName
211: * @param name
212: * @param desc
213: * @param exceptions
214: * @param attrs
215: */
216: private void createMethodWrapperMethod(final int access,
217: final String declaringTypeName, final String name,
218: final String desc, final String[] exceptions,
219: final Attribute attrs) {
220: final String wrapperName = TransformationUtil
221: .getWrapperMethodName(name, desc, declaringTypeName,
222: INVOKE_WRAPPER_METHOD_PREFIX);
223:
224: final String wrapperKey = AlreadyAddedMethodAdapter
225: .getMethodKey(wrapperName, desc);
226: if (m_addedMethods.contains(wrapperKey)) {
227: return;
228: }
229: m_addedMethods.add(wrapperKey);
230:
231: int modifiers = ACC_SYNTHETIC;
232: if (Modifier.isStatic(access)) {
233: modifiers |= ACC_STATIC;
234: }
235:
236: CodeVisitor mv = super .visitMethod(modifiers, wrapperName,
237: desc, exceptions, attrs);
238:
239: if (Modifier.isStatic(access)) {
240: AsmHelper.loadArgumentTypes(mv,
241: Type.getArgumentTypes(desc), Modifier
242: .isStatic(access));
243: mv.visitMethodInsn(INVOKESTATIC, declaringTypeName, name,
244: desc);
245: } else {
246: mv.visitVarInsn(ALOAD, 0);
247: AsmHelper.loadArgumentTypes(mv,
248: Type.getArgumentTypes(desc), Modifier
249: .isStatic(access));
250: mv.visitMethodInsn(INVOKEVIRTUAL, declaringTypeName, name,
251: desc);
252: }
253:
254: AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
255:
256: mv.visitMaxs(0, 0);
257: }
258:
259: }
|