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.model;
005:
006: import com.tc.asm.ClassVisitor;
007: import com.tc.asm.ClassWriter;
008: import com.tc.asm.MethodVisitor;
009: import com.tc.asm.Opcodes;
010: import com.tc.asm.Label;
011: import com.tc.asm.Type;
012:
013: import com.tc.aspectwerkz.DeploymentModel;
014: import com.tc.aspectwerkz.aspect.AdviceInfo;
015: import com.tc.aspectwerkz.aspect.AdviceType;
016: import com.tc.aspectwerkz.cflow.CflowCompiler;
017: import com.tc.aspectwerkz.definition.AspectDefinition;
018: import com.tc.aspectwerkz.exception.DefinitionException;
019: import com.tc.aspectwerkz.joinpoint.management.AdviceInfoContainer;
020: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
021: import com.tc.aspectwerkz.reflect.ClassInfo;
022: import com.tc.aspectwerkz.reflect.MethodInfo;
023: import com.tc.aspectwerkz.reflect.ClassInfoHelper;
024: import com.tc.aspectwerkz.transform.JoinPointCompiler;
025: import com.tc.aspectwerkz.transform.TransformationConstants;
026: import com.tc.aspectwerkz.transform.inlining.AdviceMethodInfo;
027: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
028: import com.tc.aspectwerkz.transform.inlining.AspectInfo;
029: import com.tc.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
030: import com.tc.aspectwerkz.transform.inlining.compiler.CompilationInfo;
031: import com.tc.aspectwerkz.transform.inlining.compiler.CompilerInput;
032: import com.tc.aspectwerkz.transform.inlining.spi.AspectModel;
033:
034: import java.util.ArrayList;
035: import java.util.HashSet;
036: import java.util.Iterator;
037: import java.util.List;
038: import java.util.Set;
039:
040: /**
041: * TODO doc
042: *
043: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
044: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
045: */
046: public class AspectWerkzAspectModel implements AspectModel, Opcodes,
047: TransformationConstants {
048:
049: protected final List m_customProceedMethodStructs;
050:
051: public AspectWerkzAspectModel() {
052: m_customProceedMethodStructs = null;
053: //prototype
054: }
055:
056: private AspectWerkzAspectModel(
057: CompilationInfo.Model compilationModel) {
058: m_customProceedMethodStructs = new ArrayList(0);
059: collectCustomProceedMethods(compilationModel, compilationModel
060: .getAdviceInfoContainer());
061: }
062:
063: public static final String TYPE = AspectWerkzAspectModel.class
064: .getName();
065:
066: public AspectModel getInstance(
067: CompilationInfo.Model compilationModel) {
068: // return a new instance to handle custom proceed
069: return new AspectWerkzAspectModel(compilationModel);
070: }
071:
072: public String getAspectModelType() {
073: return TYPE;
074: }
075:
076: public void defineAspect(ClassInfo aspectClassInfo,
077: AspectDefinition aspectDef, ClassLoader loader) {
078: }
079:
080: public AroundClosureClassInfo getAroundClosureClassInfo() {
081: if (m_customProceedMethodStructs.isEmpty()) {
082: //let the compiler deal with JP / SJP interface
083: return new AroundClosureClassInfo(OBJECT_CLASS_NAME,
084: new String[0]);
085: } else {
086: // getDefault the custom join point interfaces
087: Set interfaces = new HashSet();
088: for (Iterator it = m_customProceedMethodStructs.iterator(); it
089: .hasNext();) {
090: MethodInfo methodInfo = ((CustomProceedMethodStruct) it
091: .next()).customProceed;
092: interfaces.add(methodInfo.getDeclaringType().getName()
093: .replace('.', '/'));
094: }
095: return new AroundClosureClassInfo(OBJECT_CLASS_NAME,
096: (String[]) interfaces.toArray(new String[] {}));
097: }
098: }
099:
100: public void createMandatoryMethods(ClassWriter cw,
101: JoinPointCompiler compiler) {
102: createCustomProceedMethods(cw,
103: (AbstractJoinPointCompiler) compiler);
104: }
105:
106: public void createInvocationOfAroundClosureSuperClass(
107: MethodVisitor cv) {
108: ;// AW model has no super class apart Object, which is handled by the compiler
109: }
110:
111: /**
112: * Create and initialize the aspect field for a specific aspect (qualified since it depends
113: * on the param, deployment model, container etc).
114: * And creates instantiation of aspects using the Aspects.aspectOf() methods which uses the AspectContainer impls.
115: * We are using the THIS_CLASS classloader since the aspect can be visible from that one only f.e. for getDefault/set/call
116: * <p/>
117: * TODO for perJVM and perClass aspect this means we eagerly load the aspect. Different from AJ
118: *
119: * @param cw
120: * @param cv
121: * @param aspectInfo
122: * @param joinPointClassName
123: */
124: public void createAndStoreStaticAspectInstantiation(
125: ClassVisitor cw, MethodVisitor cv, AspectInfo aspectInfo,
126: String joinPointClassName) {
127: String aspectClassSignature = aspectInfo
128: .getAspectClassSignature();
129: String aspectClassName = aspectInfo.getAspectClassName();
130: // retrieve the aspect set it to the field
131: DeploymentModel deploymentModel = aspectInfo
132: .getDeploymentModel();
133: if (CflowCompiler.isCflowClass(aspectClassName)) {
134: cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo
135: .getAspectFieldName(), aspectClassSignature, null,
136: null);
137: // handle Cflow native aspectOf
138: //TODO: would be better done with a custom aspectModel for cflow, or with default factory handling
139: //FIXME AVF what does factory do there ?
140: cv.visitMethodInsn(INVOKESTATIC, aspectClassName,
141: CflowCompiler.CFLOW_ASPECTOF_METHOD_NAME, "()"
142: + aspectClassSignature);
143: cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo
144: .getAspectFieldName(), aspectClassSignature);
145: } else if (deploymentModel.equals(DeploymentModel.PER_JVM)) {
146: cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo
147: .getAspectFieldName(), aspectClassSignature, null,
148: null);
149: cv.visitMethodInsn(INVOKESTATIC, aspectInfo
150: .getAspectFactoryClassName(), "aspectOf", "()"
151: + aspectClassSignature);
152: cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo
153: .getAspectFieldName(), aspectClassSignature);
154: } else if (deploymentModel.equals(DeploymentModel.PER_CLASS)) {
155: cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo
156: .getAspectFieldName(), aspectClassSignature, null,
157: null);
158: cv.visitFieldInsn(GETSTATIC, joinPointClassName,
159: THIS_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
160: cv.visitMethodInsn(INVOKESTATIC, aspectInfo
161: .getAspectFactoryClassName(), "aspectOf",
162: "(Ljava/lang/Class;)" + aspectClassSignature);
163: cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo
164: .getAspectFieldName(), aspectClassSignature);
165: } else if (AbstractJoinPointCompiler
166: .requiresCallerOrCallee(deploymentModel)) {
167: cw.visitField(ACC_PRIVATE, aspectInfo.getAspectFieldName(),
168: aspectClassSignature, null, null);
169: } else {
170: throw new UnsupportedOperationException(
171: "unsupported deployment model - "
172: + aspectInfo.getAspectClassName() + " "
173: + deploymentModel);
174: }
175: }
176:
177: /**
178: * Initializes instance level aspects, retrieves them from the target instance through the
179: * <code>HasInstanceLevelAspect</code> interfaces.
180: * <p/>
181: * Use by 'perInstance', 'perThis' and 'perTarget' deployment models.
182: *
183: * @param cv
184: * @param aspectInfo
185: * @param input
186: */
187: public void createAndStoreRuntimeAspectInstantiation(
188: final MethodVisitor cv, final CompilerInput input,
189: final AspectInfo aspectInfo) {
190: // gen code: if (Aspects.hasAspect(...) { aspectField = (<TYPE>)((HasInstanceLocalAspect)CALLER).aw$getAspect(className, qualifiedName, containerClassName) }
191: if (DeploymentModel.PER_INSTANCE.equals(aspectInfo
192: .getDeploymentModel())) {//TODO && callerIndex >= 0
193: //storeAspectInstance(cv, input, aspectInfo, input.callerIndex);
194: } else if (DeploymentModel.PER_THIS.equals(aspectInfo
195: .getDeploymentModel())
196: && input.callerIndex >= 0) {
197: Label hasAspectCheck = pushPerXCondition(cv,
198: input.callerIndex, aspectInfo);
199: storeAspectInstance(cv, input, aspectInfo,
200: input.callerIndex);
201: cv.visitLabel(hasAspectCheck);
202: } else if (DeploymentModel.PER_TARGET.equals(aspectInfo
203: .getDeploymentModel())
204: && input.calleeIndex >= 0) {
205: Label hasAspectCheck = pushPerXCondition(cv,
206: input.calleeIndex, aspectInfo);
207: storeAspectInstance(cv, input, aspectInfo,
208: input.calleeIndex);
209: cv.visitLabel(hasAspectCheck);
210: }
211:
212: if (aspectInfo.getDeploymentModel() == DeploymentModel.PER_INSTANCE) {//TODO refactor with previous if block
213: // gen code: aspectField = (<TYPE>)((HasInstanceLocalAspect)CALLER).aw$getAspect(className, qualifiedName, containerClassName)
214: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
215: if (input.callerIndex >= 0) {
216: cv.visitVarInsn(ALOAD, input.callerIndex);
217: } else {
218: // caller instance not available - skipping
219: //TODO clean up should not occur
220: }
221: cv.visitMethodInsn(INVOKESTATIC, aspectInfo
222: .getAspectFactoryClassName(), "aspectOf",
223: "(Ljava/lang/Object;)"
224: + aspectInfo.getAspectClassSignature());
225: // cv.visitLdcInsn(aspectInfo.getAspectClassName().replace('/', '.'));
226: // cv.visitLdcInsn(aspectInfo.getAspectQualifiedName());
227: // AsmHelper.loadStringConstant(cv, aspectInfo.getAspectDefinition().getContainerClassName());
228: // cv.visitMethodInsn(
229: // INVOKEINTERFACE,
230: // HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME,
231: // INSTANCE_LEVEL_GETASPECT_METHOD_NAME,
232: // INSTANCE_LEVEL_GETASPECT_METHOD_SIGNATURE
233: // );
234: // cv.visitTypeInsn(CHECKCAST, aspectInfo.getAspectClassName());
235: cv.visitFieldInsn(PUTFIELD, input.joinPointClassName,
236: aspectInfo.getAspectFieldName(), aspectInfo
237: .getAspectClassSignature());
238: }
239: }
240:
241: /**
242: * Load aspect instance on stack
243: *
244: * @param cv
245: * @param input
246: * @param aspectInfo
247: */
248: public void loadAspect(final MethodVisitor cv,
249: final CompilerInput input, final AspectInfo aspectInfo) {
250: DeploymentModel deploymentModel = aspectInfo
251: .getDeploymentModel();
252: if (DeploymentModel.PER_JVM.equals(deploymentModel)
253: || DeploymentModel.PER_CLASS.equals(deploymentModel)) {
254: cv.visitFieldInsn(GETSTATIC, input.joinPointClassName,
255: aspectInfo.getAspectFieldName(), aspectInfo
256: .getAspectClassSignature());
257: } else if (DeploymentModel.PER_INSTANCE.equals(deploymentModel)) {
258: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
259: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
260: aspectInfo.getAspectFieldName(), aspectInfo
261: .getAspectClassSignature());
262: } else if (DeploymentModel.PER_THIS.equals(deploymentModel)) {
263: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
264: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
265: aspectInfo.getAspectFieldName(), aspectInfo
266: .getAspectClassSignature());
267:
268: //FIXME see FIXME on aspect instantion
269: Label nullCheck = new Label();
270: cv.visitJumpInsn(IFNONNULL, nullCheck);
271: storeAspectInstance(cv, input, aspectInfo,
272: input.callerIndex);
273: cv.visitLabel(nullCheck);
274:
275: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
276: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
277: aspectInfo.getAspectFieldName(), aspectInfo
278: .getAspectClassSignature());
279: } else if (DeploymentModel.PER_TARGET.equals(deploymentModel)) {
280: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
281: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
282: aspectInfo.getAspectFieldName(), aspectInfo
283: .getAspectClassSignature());
284: //FIXME see FIXME on aspect instantion
285:
286: Label nullCheck = new Label();
287: cv.visitJumpInsn(IFNONNULL, nullCheck);
288: storeAspectInstance(cv, input, aspectInfo,
289: input.calleeIndex);
290: cv.visitLabel(nullCheck);
291:
292: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
293: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
294: aspectInfo.getAspectFieldName(), aspectInfo
295: .getAspectClassSignature());
296: } else {
297: throw new DefinitionException("deployment model ["
298: + deploymentModel + "] is not supported");
299: }
300: }
301:
302: public void createAroundAdviceArgumentHandling(MethodVisitor cv,
303: CompilerInput input, Type[] joinPointArgumentTypes,
304: AdviceMethodInfo adviceMethodInfo) {
305: defaultCreateAroundAdviceArgumentHandling(cv, input,
306: joinPointArgumentTypes, adviceMethodInfo);
307: }
308:
309: public void createBeforeOrAfterAdviceArgumentHandling(
310: MethodVisitor cv, CompilerInput input,
311: Type[] joinPointArgumentTypes,
312: AdviceMethodInfo adviceMethodInfo, int specialArgIndex) {
313: defaultCreateBeforeOrAfterAdviceArgumentHandling(cv, input,
314: joinPointArgumentTypes, adviceMethodInfo,
315: specialArgIndex);
316: }
317:
318: public boolean requiresReflectiveInfo() {
319: // custom proceed() JoinPoint will not be recognize by the default logic
320: return m_customProceedMethodStructs.size() > 0;
321: }
322:
323: ///////---------- Helpers
324:
325: /**
326: * Generate a "if Aspects.hasAspect(qName, instance)"
327: *
328: * @param cv
329: * @param perInstanceIndex
330: * @param aspectInfo
331: * @return
332: */
333: private Label pushPerXCondition(final MethodVisitor cv,
334: final int perInstanceIndex, final AspectInfo aspectInfo) {
335: Label hasAspectCheck = new Label();
336:
337: cv.visitVarInsn(ALOAD, perInstanceIndex);
338: cv.visitMethodInsn(INVOKESTATIC, aspectInfo
339: .getAspectFactoryClassName(),
340: FACTORY_HASASPECT_METHOD_NAME,
341: FACTORY_HASASPECT_PEROBJECT_METHOD_SIGNATURE);
342: cv.visitJumpInsn(IFEQ, hasAspectCheck);
343:
344: return hasAspectCheck;
345: }
346:
347: /**
348: * Creates the instance of an aspect by invoking
349: * "HasInstanceLevelAspect.aw$getAspect(String, String)" on perInstanceIndex variable
350: * and stores the aspect instance in the joinpoint instance field
351: */
352: private void storeAspectInstance(final MethodVisitor cv,
353: final CompilerInput input, final AspectInfo aspectInfo,
354: final int perInstanceIndex) {
355: AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
356:
357: if (perInstanceIndex >= 0) {
358: cv.visitVarInsn(ALOAD, perInstanceIndex);
359: }
360:
361: cv.visitMethodInsn(INVOKESTATIC, aspectInfo
362: .getAspectFactoryClassName(),
363: FACTORY_ASPECTOF_METHOD_NAME, "(Ljava/lang/Object;)"
364: + aspectInfo.getAspectClassSignature());
365: //
366: // cv.visitLdcInsn(aspectInfo.getAspectClassName().replace('/', '.'));
367: // cv.visitLdcInsn(aspectInfo.getAspectQualifiedName());
368: // AsmHelper.loadStringConstant(cv, aspectInfo.getAspectDefinition().getContainerClassName());
369: // cv.visitMethodInsn(
370: // INVOKEINTERFACE,
371: // HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME,
372: // INSTANCE_LEVEL_GETASPECT_METHOD_NAME,
373: // INSTANCE_LEVEL_GETASPECT_METHOD_SIGNATURE
374: // );
375: //
376: // cv.visitTypeInsn(CHECKCAST, aspectInfo.getAspectClassName());
377:
378: cv.visitFieldInsn(PUTFIELD, input.joinPointClassName,
379: aspectInfo.getAspectFieldName(), aspectInfo
380: .getAspectClassSignature());
381: }
382:
383: /**
384: * Creates the custom proceed methods.
385: */
386: private void createCustomProceedMethods(ClassWriter cw,
387: AbstractJoinPointCompiler compiler) {
388: Set addedMethodSignatures = new HashSet();
389: for (Iterator it = m_customProceedMethodStructs.iterator(); it
390: .hasNext();) {
391: CustomProceedMethodStruct customProceedStruct = (CustomProceedMethodStruct) it
392: .next();
393: MethodInfo methodInfo = customProceedStruct.customProceed;
394: final String desc = methodInfo.getSignature();
395:
396: if (addedMethodSignatures.contains(desc)) {
397: continue;
398: }
399: addedMethodSignatures.add(desc);
400:
401: MethodVisitor cv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL,
402: PROCEED_METHOD_NAME, desc, null,
403: new String[] { THROWABLE_CLASS_NAME });
404:
405: // update the joinpoint instance with the given values
406: // starts at 1 since first arg is the custom join point by convention
407: //TODO see JoinPointManage for this custom jp is first convention
408: int argStackIndex = 1;
409: for (int i = 1; i < customProceedStruct.adviceToTargetArgs.length; i++) {
410: int targetArg = customProceedStruct.adviceToTargetArgs[i];
411: if (targetArg >= 0) {
412: // regular arg
413: String fieldName = compiler.m_fieldNames[targetArg];
414: cv.visitVarInsn(ALOAD, 0);
415: Type type = compiler.m_argumentTypes[targetArg];
416: argStackIndex = AsmHelper.loadType(cv,
417: argStackIndex, type);
418: cv.visitFieldInsn(PUTFIELD,
419: compiler.m_joinPointClassName, fieldName,
420: type.getDescriptor());
421: } else if (targetArg == AdviceInfo.TARGET_ARG) {
422: cv.visitVarInsn(ALOAD, 0);
423: argStackIndex = AsmHelper
424: .loadType(
425: cv,
426: argStackIndex,
427: Type
428: .getType(compiler.m_calleeClassSignature));
429: cv.visitFieldInsn(PUTFIELD,
430: compiler.m_joinPointClassName,
431: CALLEE_INSTANCE_FIELD_NAME,
432: compiler.m_calleeClassSignature);
433: } else if (targetArg == AdviceInfo.THIS_ARG) {
434: cv.visitVarInsn(ALOAD, 0);
435: argStackIndex = AsmHelper
436: .loadType(
437: cv,
438: argStackIndex,
439: Type
440: .getType(compiler.m_callerClassSignature));
441: cv.visitFieldInsn(PUTFIELD,
442: compiler.m_joinPointClassName,
443: CALLER_INSTANCE_FIELD_NAME,
444: compiler.m_callerClassSignature);
445: } else {
446: ;//skip it
447: }
448: }
449:
450: // call proceed()
451: // and handles unwrapping for returning primitive
452: Type returnType = Type
453: .getType(customProceedStruct.customProceed
454: .getReturnType().getSignature());
455: if (AsmHelper.isPrimitive(returnType)) {
456: cv.visitVarInsn(ALOAD, 0);
457: cv.visitMethodInsn(INVOKESPECIAL,
458: compiler.m_joinPointClassName,
459: PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
460: AsmHelper.unwrapType(cv, returnType);
461: } else {
462: cv.visitVarInsn(ALOAD, 0);
463: cv.visitMethodInsn(INVOKESPECIAL,
464: compiler.m_joinPointClassName,
465: PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
466: if (!returnType.getClassName().equals(
467: OBJECT_CLASS_SIGNATURE)) {
468: cv.visitTypeInsn(CHECKCAST, returnType
469: .getInternalName());
470: }
471: }
472: AsmHelper.addReturnStatement(cv, returnType);
473: cv.visitMaxs(0, 0);
474: }
475: }
476:
477: //---------- Model specific methods
478:
479: /**
480: * Collects the custom proceed methods used in the advice specified.
481: *
482: * @param model
483: * @param advices
484: */
485: private void collectCustomProceedMethods(
486: final CompilationInfo.Model model,
487: final AdviceInfoContainer advices) {
488: ClassLoader loader = model.getThisClassInfo().getClassLoader();
489: final AdviceInfo[] beforeAdviceInfos = advices
490: .getBeforeAdviceInfos();
491: for (int i = 0; i < beforeAdviceInfos.length; i++) {
492: collectCustomProceedMethods(beforeAdviceInfos[i], loader);
493: }
494: final AdviceInfo[] aroundAdviceInfos = advices
495: .getAroundAdviceInfos();
496: for (int i = 0; i < aroundAdviceInfos.length; i++) {
497: collectCustomProceedMethods(aroundAdviceInfos[i], loader);
498: }
499: final AdviceInfo[] afterFinallyAdviceInfos = advices
500: .getAfterFinallyAdviceInfos();
501: for (int i = 0; i < afterFinallyAdviceInfos.length; i++) {
502: collectCustomProceedMethods(afterFinallyAdviceInfos[i],
503: loader);
504: }
505: final AdviceInfo[] afterReturningAdviceInfos = advices
506: .getAfterReturningAdviceInfos();
507: for (int i = 0; i < afterReturningAdviceInfos.length; i++) {
508: collectCustomProceedMethods(afterReturningAdviceInfos[i],
509: loader);
510: }
511: final AdviceInfo[] afterThrowingAdviceInfos = advices
512: .getAfterThrowingAdviceInfos();
513: for (int i = 0; i < afterThrowingAdviceInfos.length; i++) {
514: collectCustomProceedMethods(afterThrowingAdviceInfos[i],
515: loader);
516: }
517: }
518:
519: /**
520: * Collects the custom proceed methods used in the advice specified.
521: *
522: * @param adviceInfo
523: * @param loader
524: */
525: private void collectCustomProceedMethods(
526: final AdviceInfo adviceInfo, final ClassLoader loader) {
527: final Type[] paramTypes = adviceInfo.getMethodParameterTypes();
528: if (paramTypes.length != 0) {
529: Type firstParam = paramTypes[0];
530: //TODO should we support JP at other positions or lock the other advice models then so that JP..
531: // ..is not there or first only ?
532: // check if first param is an object but not a JP or SJP
533: if (firstParam.getSort() == Type.OBJECT
534: && !firstParam.getClassName().equals(
535: JOIN_POINT_JAVA_CLASS_NAME)
536: && !firstParam.getClassName().equals(
537: STATIC_JOIN_POINT_JAVA_CLASS_NAME)) {
538: ClassInfo classInfo = AsmClassInfo.getClassInfo(
539: firstParam.getClassName(), loader);
540: if (ClassInfoHelper.implements Interface(classInfo,
541: JOIN_POINT_JAVA_CLASS_NAME)
542: || ClassInfoHelper.implements Interface(
543: classInfo,
544: STATIC_JOIN_POINT_JAVA_CLASS_NAME)) {
545: // we have ourselves a custom joinpoint
546: MethodInfo[] methods = classInfo.getMethods();
547: for (int j = 0; j < methods.length; j++) {
548: MethodInfo method = methods[j];
549: if (method.getName()
550: .equals(PROCEED_METHOD_NAME)) {
551: // we inherit the binding from the advice that actually use us
552: // for now the first advice sets the rule
553: // it is up to the user to ensure consistency if the custom proceed
554: // is used more than once in different advices.
555: m_customProceedMethodStructs
556: .add(new CustomProceedMethodStruct(
557: method,
558: adviceInfo
559: .getMethodToArgIndexes()));
560: }
561: }
562: }
563: }
564: }
565: }
566:
567: private static class CustomProceedMethodStruct {
568: MethodInfo customProceed;
569: int[] adviceToTargetArgs;
570:
571: public CustomProceedMethodStruct(MethodInfo customProceed,
572: int[] adviceToTargetArgs) {
573: this .customProceed = customProceed;
574: this .adviceToTargetArgs = adviceToTargetArgs;
575: }
576: }
577:
578: public static void defaultCreateBeforeOrAfterAdviceArgumentHandling(
579: MethodVisitor cv, CompilerInput input,
580: Type[] joinPointArgumentTypes,
581: AdviceMethodInfo adviceMethodInfo, int specialArgIndex) {
582: int[] argIndexes = adviceMethodInfo.getAdviceMethodArgIndexes();
583: // if empty, we consider for now that we have to push JoinPoint for old advice with JoinPoint as sole arg
584: for (int j = 0; j < argIndexes.length; j++) {
585: int argIndex = argIndexes[j];
586: if (argIndex >= 0) {
587: Type argumentType = joinPointArgumentTypes[argIndex];
588: int argStackIndex = AsmHelper.getRegisterIndexOf(
589: joinPointArgumentTypes, argIndex)
590: + input.argStartIndex;
591: AsmHelper.loadType(cv, argStackIndex, argumentType);
592: } else if (argIndex == AdviceInfo.JOINPOINT_ARG
593: || argIndex == AdviceInfo.STATIC_JOINPOINT_ARG) {
594: AbstractJoinPointCompiler.loadJoinPointInstance(cv,
595: input);
596: } else if (argIndex == AdviceInfo.TARGET_ARG) {
597: AbstractJoinPointCompiler.loadCallee(cv, input);
598: // add a cast if runtime check was used
599: if (adviceMethodInfo.getAdviceInfo()
600: .hasTargetWithRuntimeCheck()) {
601: cv.visitTypeInsn(CHECKCAST,
602: adviceMethodInfo.getAdviceInfo()
603: .getMethodParameterTypes()[j]
604: .getInternalName());
605: }
606: } else if (argIndex == AdviceInfo.THIS_ARG) {
607: AbstractJoinPointCompiler.loadCaller(cv, input);
608: } else if (argIndex == AdviceInfo.SPECIAL_ARGUMENT
609: && specialArgIndex != INDEX_NOTAVAILABLE) {
610: Type argumentType = adviceMethodInfo.getAdviceInfo()
611: .getMethodParameterTypes()[j];
612: AsmHelper.loadType(cv, specialArgIndex, argumentType);
613: if (AdviceType.AFTER_THROWING.equals(adviceMethodInfo
614: .getAdviceInfo().getAdviceDefinition()
615: .getType())
616: || AdviceType.AFTER_RETURNING
617: .equals(adviceMethodInfo
618: .getAdviceInfo()
619: .getAdviceDefinition()
620: .getType())) {
621: cv.visitTypeInsn(CHECKCAST, argumentType
622: .getInternalName());
623: }
624: } else {
625: throw new Error("magic index is not supported: "
626: + argIndex);
627: }
628: }
629: }
630:
631: public static void defaultCreateAroundAdviceArgumentHandling(
632: MethodVisitor cv, CompilerInput input,
633: Type[] joinPointArgumentTypes,
634: AdviceMethodInfo adviceMethodInfo) {
635: int[] argIndexes = adviceMethodInfo.getAdviceMethodArgIndexes();
636: for (int j = 0; j < argIndexes.length; j++) {
637: int argIndex = argIndexes[j];
638: if (argIndex >= 0) {
639: Type argumentType = joinPointArgumentTypes[argIndex];
640: cv.visitVarInsn(ALOAD, 0);
641: cv.visitFieldInsn(GETFIELD, input.joinPointClassName,
642: ARGUMENT_FIELD + argIndex, argumentType
643: .getDescriptor());
644: } else if (argIndex == AdviceInfo.JOINPOINT_ARG
645: || argIndex == AdviceInfo.STATIC_JOINPOINT_ARG
646: || argIndex == AdviceInfo.VALID_NON_AW_AROUND_CLOSURE_TYPE
647: || argIndex == AdviceInfo.CUSTOM_JOIN_POINT_ARG) {
648: cv.visitVarInsn(ALOAD, 0);
649: } else if (argIndex == AdviceInfo.TARGET_ARG) {
650: AbstractJoinPointCompiler.loadCallee(cv, input);
651: // add a cast if runtime check was used
652: if (adviceMethodInfo.getAdviceInfo()
653: .hasTargetWithRuntimeCheck()) {
654: cv.visitTypeInsn(CHECKCAST,
655: adviceMethodInfo.getAdviceInfo()
656: .getMethodParameterTypes()[j]
657: .getInternalName());
658: }
659: } else if (argIndex == AdviceInfo.THIS_ARG) {
660: AbstractJoinPointCompiler.loadCaller(cv, input);
661: } else {
662: throw new Error(
663: "advice method argument index type is not supported: "
664: + argIndex);
665: }
666: }
667: }
668:
669: }
|