001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.transform.inlining.weaver;
005:
006: import com.tc.asm.Opcodes;
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
009: import com.tc.asm.MethodVisitor;
010: import com.tc.asm.Type;
011:
012: import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
013: import com.tc.aspectwerkz.transform.InstrumentationContext;
014: import com.tc.aspectwerkz.transform.TransformationConstants;
015: import com.tc.aspectwerkz.transform.TransformationUtil;
016: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
017: import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
018:
019: import java.util.List;
020: import java.util.Iterator;
021: import java.util.Set;
022: import java.lang.reflect.Modifier;
023:
024: /**
025: * Adds field and method and ctor wrappers when there has been at least one joinpoint emitted.
026: *
027: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
028: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
029: */
030: public class AddWrapperVisitor extends ClassAdapter implements Opcodes,
031: TransformationConstants {
032:
033: private InstrumentationContext m_context;
034:
035: private Set m_addedMethods;
036:
037: public AddWrapperVisitor(ClassVisitor classVisitor,
038: InstrumentationContext context, Set alreadyAddedMethods) {
039: super (classVisitor);
040: m_context = (InstrumentationContext) context;
041: m_addedMethods = alreadyAddedMethods;
042: }
043:
044: /**
045: * Visits the class.
046: *
047: * @param access
048: * @param name
049: * @param signature
050: * @param superName
051: * @param interfaces
052: */
053: public void visit(final int version, final int access,
054: final String name, final String signature,
055: final String super Name, final String[] interfaces) {
056: // iterate on the emitted joinpoints
057: // we don't need to filter more since the joinpoint type and the weaving phase did that for us
058: List jps = m_context.getEmittedJoinPoints();
059: for (Iterator iterator = jps.iterator(); iterator.hasNext();) {
060: EmittedJoinPoint emittedJoinPoint = (EmittedJoinPoint) iterator
061: .next();
062: int jpType = emittedJoinPoint.getJoinPointType();
063: if (Modifier.isPublic(emittedJoinPoint
064: .getCalleeMemberModifiers())
065: || !name.equals(emittedJoinPoint
066: .getCalleeClassName())) {//TODO ?
067: continue;
068: }
069: switch (jpType) {
070: case (JoinPointType.FIELD_GET_INT):
071: createGetFieldWrapperMethod(Modifier
072: .isStatic(emittedJoinPoint
073: .getCalleeMemberModifiers()), name,
074: emittedJoinPoint.getCalleeMemberName(),
075: emittedJoinPoint.getCalleeMemberDesc(), null//TODO generic is that ok ?
076: );
077: break;
078: case (JoinPointType.FIELD_SET_INT):
079: createPutFieldWrapperMethod(Modifier
080: .isStatic(emittedJoinPoint
081: .getCalleeMemberModifiers()), name,
082: emittedJoinPoint.getCalleeMemberName(),
083: emittedJoinPoint.getCalleeMemberDesc(), null//TODO generic is that ok ?
084: );
085: break;
086: case (JoinPointType.METHOD_EXECUTION_INT):
087: case (JoinPointType.METHOD_CALL_INT):
088: createMethodWrapperMethod(emittedJoinPoint
089: .getCalleeMemberModifiers(), name,
090: emittedJoinPoint.getCalleeMemberName(),
091: emittedJoinPoint.getCalleeMemberDesc(), null,//TODO generic is that ok ?
092: EMPTY_STRING_ARRAY//TODO should throw Throwable ??
093: );
094: break;
095: case (JoinPointType.CONSTRUCTOR_CALL_INT):
096: case (JoinPointType.CONSTRUCTOR_EXECUTION_INT):
097: createConstructorWrapperMethod(emittedJoinPoint
098: .getCalleeMemberModifiers(), name,
099: emittedJoinPoint.getCalleeMemberName(),
100: emittedJoinPoint.getCalleeMemberDesc(), null,//TODO generic is that ok ?
101: EMPTY_STRING_ARRAY//TODO should throw Throwable ??
102: );
103: break;
104: }
105: }
106:
107: super .visit(version, access, name, signature, super Name,
108: interfaces);
109: }
110:
111: /**
112: * Creates a public wrapper method that delegates to the GETFIELD instruction of the non-public field.
113: *
114: * @param isStaticField
115: * @param declaringTypeName
116: * @param name
117: * @param desc
118: * @param signature
119: */
120: private void createGetFieldWrapperMethod(
121: final boolean isStaticField,
122: final String declaringTypeName, final String name,
123: final String desc, final String signature) {
124: String wrapperName = TransformationUtil.getWrapperMethodName(
125: name, desc, declaringTypeName,
126: GETFIELD_WRAPPER_METHOD_PREFIX);
127:
128: StringBuffer wsignature = new StringBuffer();
129: wsignature.append('(');
130: wsignature.append(')');
131: wsignature.append(desc);
132:
133: final String wrapperKey = AlreadyAddedMethodAdapter
134: .getMethodKey(wrapperName, wsignature.toString());
135: if (m_addedMethods.contains(wrapperKey)) {
136: return;
137: }
138: m_addedMethods.add(wrapperKey);
139:
140: int modifiers = ACC_SYNTHETIC;
141: if (isStaticField) {
142: modifiers |= ACC_STATIC;
143: }
144:
145: MethodVisitor mv = cv.visitMethod(modifiers, wrapperName,
146: wsignature.toString(), signature, EMPTY_STRING_ARRAY);
147:
148: if (isStaticField) {
149: mv.visitFieldInsn(GETSTATIC, declaringTypeName, name, desc);
150: } else {
151: mv.visitVarInsn(ALOAD, 0);
152: mv.visitFieldInsn(GETFIELD, declaringTypeName, name, desc);
153: }
154:
155: AsmHelper.addReturnStatement(mv, Type.getType(desc));
156: mv.visitMaxs(0, 0);
157: }
158:
159: /**
160: * Creates a public wrapper method that delegates to the PUTFIELD instruction of the non-public field.
161: * Static method if field is static (PUTSTATIC instr)
162: *
163: * @param isStaticField
164: * @param declaringTypeName
165: * @param name
166: * @param desc
167: * @param signature
168: */
169: private void createPutFieldWrapperMethod(boolean isStaticField,
170: final String declaringTypeName, final String name,
171: final String desc, final String signature) {
172: String wrapperName = TransformationUtil.getWrapperMethodName(
173: name, desc, declaringTypeName,
174: PUTFIELD_WRAPPER_METHOD_PREFIX);
175:
176: StringBuffer wsignature = new StringBuffer();
177: wsignature.append('(');
178: wsignature.append(desc);
179: wsignature.append(')');
180: wsignature.append('V');
181:
182: final String wrapperKey = AlreadyAddedMethodAdapter
183: .getMethodKey(wrapperName, wsignature.toString());
184: if (m_addedMethods.contains(wrapperKey)) {
185: return;
186: }
187: m_addedMethods.add(wrapperKey);
188:
189: int modifiers = ACC_SYNTHETIC;
190: if (isStaticField) {
191: modifiers |= ACC_STATIC;
192: }
193:
194: MethodVisitor mv = cv.visitMethod(modifiers, wrapperName,
195: wsignature.toString(), signature, EMPTY_STRING_ARRAY);
196:
197: Type fieldType = Type.getType(desc);
198: if (isStaticField) {
199: AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType },
200: true);
201: mv.visitFieldInsn(PUTSTATIC, declaringTypeName, name, desc);
202: } else {
203: mv.visitVarInsn(ALOAD, 0);
204: AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType },
205: false);
206: mv.visitFieldInsn(PUTFIELD, declaringTypeName, name, desc);
207: }
208:
209: AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
210: mv.visitMaxs(0, 0);
211: }
212:
213: /**
214: * Creates a public wrapper method that delegates to the non-public target method.
215: *
216: * @param access
217: * @param declaringTypeName
218: * @param name
219: * @param desc
220: * @param signature
221: * @param exceptions
222: */
223: private void createMethodWrapperMethod(final int access,
224: final String declaringTypeName, final String name,
225: final String desc, final String signature,
226: final String[] exceptions) {
227: final String wrapperName = TransformationUtil
228: .getWrapperMethodName(name, desc, declaringTypeName,
229: INVOKE_WRAPPER_METHOD_PREFIX);
230:
231: final String wrapperKey = AlreadyAddedMethodAdapter
232: .getMethodKey(wrapperName, desc);
233: if (m_addedMethods.contains(wrapperKey)) {
234: return;
235: }
236: m_addedMethods.add(wrapperKey);
237:
238: int modifiers = ACC_SYNTHETIC;
239: if (Modifier.isStatic(access)) {
240: modifiers |= ACC_STATIC;
241: }
242:
243: MethodVisitor mv = super .visitMethod(modifiers, wrapperName,
244: desc, signature, exceptions);
245:
246: if (Modifier.isStatic(access)) {
247: AsmHelper.loadArgumentTypes(mv,
248: Type.getArgumentTypes(desc), Modifier
249: .isStatic(access));
250: mv.visitMethodInsn(INVOKESTATIC, declaringTypeName, name,
251: desc);
252: } else {
253: mv.visitVarInsn(ALOAD, 0);
254: AsmHelper.loadArgumentTypes(mv,
255: Type.getArgumentTypes(desc), Modifier
256: .isStatic(access));
257: mv.visitMethodInsn(INVOKEVIRTUAL, declaringTypeName, name,
258: desc);
259: }
260:
261: AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
262:
263: mv.visitMaxs(0, 0);
264: }
265:
266: /**
267: * Creates a public wrapper static method that delegates to the non-public target ctor.
268: *
269: * @param access
270: * @param declaringTypeName
271: * @param name
272: * @param desc
273: * @param signature
274: * @param exceptions
275: */
276: private void createConstructorWrapperMethod(final int access,
277: final String declaringTypeName, final String name,
278: final String desc, final String signature,
279: final String[] exceptions) {
280: final String wrapperName = TransformationUtil
281: .getWrapperMethodName(name, desc, declaringTypeName,
282: INVOKE_WRAPPER_METHOD_PREFIX);
283:
284: final String wrapperKey = AlreadyAddedMethodAdapter
285: .getMethodKey(wrapperName, desc);
286: if (m_addedMethods.contains(wrapperKey)) {
287: return;
288: }
289: m_addedMethods.add(wrapperKey);
290:
291: int modifiers = ACC_SYNTHETIC;
292: modifiers |= ACC_STATIC;
293:
294: Type declaringType = Type
295: .getType('L' + declaringTypeName + ';');
296: String ctorDesc = Type.getMethodDescriptor(declaringType, Type
297: .getArgumentTypes(desc));
298:
299: MethodVisitor mv = super .visitMethod(modifiers, wrapperName,
300: ctorDesc, signature, exceptions);
301:
302: mv.visitTypeInsn(NEW, declaringTypeName);
303: mv.visitInsn(DUP);
304: AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc),
305: true);
306: mv
307: .visitMethodInsn(INVOKESPECIAL, declaringTypeName,
308: name, desc);
309: AsmHelper.addReturnStatement(mv, declaringType);
310:
311: mv.visitMaxs(0, 0);
312: }
313:
314: }
|