KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > transform > inlining > model > AspectWerkzAspectModel


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.transform.inlining.model;
5
6 import com.tc.asm.ClassVisitor;
7 import com.tc.asm.ClassWriter;
8 import com.tc.asm.MethodVisitor;
9 import com.tc.asm.Opcodes;
10 import com.tc.asm.Label;
11 import com.tc.asm.Type;
12
13 import com.tc.aspectwerkz.DeploymentModel;
14 import com.tc.aspectwerkz.aspect.AdviceInfo;
15 import com.tc.aspectwerkz.aspect.AdviceType;
16 import com.tc.aspectwerkz.cflow.CflowCompiler;
17 import com.tc.aspectwerkz.definition.AspectDefinition;
18 import com.tc.aspectwerkz.exception.DefinitionException;
19 import com.tc.aspectwerkz.joinpoint.management.AdviceInfoContainer;
20 import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
21 import com.tc.aspectwerkz.reflect.ClassInfo;
22 import com.tc.aspectwerkz.reflect.MethodInfo;
23 import com.tc.aspectwerkz.reflect.ClassInfoHelper;
24 import com.tc.aspectwerkz.transform.JoinPointCompiler;
25 import com.tc.aspectwerkz.transform.TransformationConstants;
26 import com.tc.aspectwerkz.transform.inlining.AdviceMethodInfo;
27 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
28 import com.tc.aspectwerkz.transform.inlining.AspectInfo;
29 import com.tc.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
30 import com.tc.aspectwerkz.transform.inlining.compiler.CompilationInfo;
31 import com.tc.aspectwerkz.transform.inlining.compiler.CompilerInput;
32 import com.tc.aspectwerkz.transform.inlining.spi.AspectModel;
33
34 import java.util.ArrayList JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Set JavaDoc;
39
40 /**
41  * TODO doc
42  *
43  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
44  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
45  */

46 public class AspectWerkzAspectModel implements AspectModel, Opcodes, TransformationConstants {
47
48   protected final List JavaDoc m_customProceedMethodStructs;
49
50
51   public AspectWerkzAspectModel() {
52     m_customProceedMethodStructs = null;
53     //prototype
54
}
55
56   private AspectWerkzAspectModel(CompilationInfo.Model compilationModel) {
57     m_customProceedMethodStructs = new ArrayList JavaDoc(0);
58     collectCustomProceedMethods(compilationModel, compilationModel.getAdviceInfoContainer());
59   }
60
61   public static final String JavaDoc TYPE = AspectWerkzAspectModel.class.getName();
62
63   public AspectModel getInstance(CompilationInfo.Model compilationModel) {
64     // return a new instance to handle custom proceed
65
return new AspectWerkzAspectModel(compilationModel);
66   }
67
68   public String JavaDoc getAspectModelType() {
69     return TYPE;
70   }
71
72   public void defineAspect(ClassInfo aspectClassInfo, AspectDefinition aspectDef, ClassLoader JavaDoc loader) {
73   }
74
75   public AroundClosureClassInfo getAroundClosureClassInfo() {
76     if (m_customProceedMethodStructs.isEmpty()) {
77       //let the compiler deal with JP / SJP interface
78
return new AroundClosureClassInfo(OBJECT_CLASS_NAME, new String JavaDoc[0]);
79     } else {
80       // getDefault the custom join point interfaces
81
Set JavaDoc interfaces = new HashSet JavaDoc();
82       for (Iterator JavaDoc it = m_customProceedMethodStructs.iterator(); it.hasNext();) {
83         MethodInfo methodInfo = ((CustomProceedMethodStruct) it.next()).customProceed;
84         interfaces.add(methodInfo.getDeclaringType().getName().replace('.', '/'));
85       }
86       return new AroundClosureClassInfo(OBJECT_CLASS_NAME, (String JavaDoc[]) interfaces.toArray(new String JavaDoc[]{}));
87     }
88   }
89
90   public void createMandatoryMethods(ClassWriter cw, JoinPointCompiler compiler) {
91     createCustomProceedMethods(cw, (AbstractJoinPointCompiler) compiler);
92   }
93
94   public void createInvocationOfAroundClosureSuperClass(MethodVisitor cv) {
95     ;// AW model has no super class apart Object, which is handled by the compiler
96
}
97
98   /**
99    * Create and initialize the aspect field for a specific aspect (qualified since it depends
100    * on the param, deployment model, container etc).
101    * And creates instantiation of aspects using the Aspects.aspectOf() methods which uses the AspectContainer impls.
102    * We are using the THIS_CLASS classloader since the aspect can be visible from that one only f.e. for getDefault/set/call
103    * <p/>
104    * TODO for perJVM and perClass aspect this means we eagerly load the aspect. Different from AJ
105    *
106    * @param cw
107    * @param cv
108    * @param aspectInfo
109    * @param joinPointClassName
110    */

111   public void createAndStoreStaticAspectInstantiation(ClassVisitor cw, MethodVisitor cv, AspectInfo aspectInfo, String JavaDoc joinPointClassName) {
112     String JavaDoc aspectClassSignature = aspectInfo.getAspectClassSignature();
113     String JavaDoc aspectClassName = aspectInfo.getAspectClassName();
114     // retrieve the aspect set it to the field
115
DeploymentModel deploymentModel = aspectInfo.getDeploymentModel();
116     if (CflowCompiler.isCflowClass(aspectClassName)) {
117       cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo.getAspectFieldName(), aspectClassSignature, null, null);
118       // handle Cflow native aspectOf
119
//TODO: would be better done with a custom aspectModel for cflow, or with default factory handling
120
//FIXME AVF what does factory do there ?
121
cv.visitMethodInsn(
122               INVOKESTATIC,
123               aspectClassName,
124               CflowCompiler.CFLOW_ASPECTOF_METHOD_NAME,
125               "()" + aspectClassSignature
126       );
127       cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo.getAspectFieldName(), aspectClassSignature);
128     } else if (deploymentModel.equals(DeploymentModel.PER_JVM)) {
129       cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo.getAspectFieldName(), aspectClassSignature, null, null);
130       cv.visitMethodInsn(
131               INVOKESTATIC,
132               aspectInfo.getAspectFactoryClassName(),
133               "aspectOf",
134               "()" + aspectClassSignature
135       );
136       cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo.getAspectFieldName(), aspectClassSignature);
137     } else if (deploymentModel.equals(DeploymentModel.PER_CLASS)) {
138       cw.visitField(ACC_PRIVATE + ACC_STATIC, aspectInfo.getAspectFieldName(), aspectClassSignature, null, null);
139       cv.visitFieldInsn(GETSTATIC, joinPointClassName, THIS_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
140       cv.visitMethodInsn(
141               INVOKESTATIC,
142               aspectInfo.getAspectFactoryClassName(),
143               "aspectOf",
144               "(Ljava/lang/Class;)" + aspectClassSignature
145       );
146       cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo.getAspectFieldName(), aspectClassSignature);
147     } else if (AbstractJoinPointCompiler.requiresCallerOrCallee(deploymentModel)) {
148       cw.visitField(ACC_PRIVATE, aspectInfo.getAspectFieldName(), aspectClassSignature, null, null);
149     } else {
150       throw new UnsupportedOperationException JavaDoc(
151               "unsupported deployment model - " +
152                       aspectInfo.getAspectClassName() + " " +
153                       deploymentModel
154       );
155     }
156   }
157
158   /**
159    * Initializes instance level aspects, retrieves them from the target instance through the
160    * <code>HasInstanceLevelAspect</code> interfaces.
161    * <p/>
162    * Use by 'perInstance', 'perThis' and 'perTarget' deployment models.
163    *
164    * @param cv
165    * @param aspectInfo
166    * @param input
167    */

168   public void createAndStoreRuntimeAspectInstantiation(final MethodVisitor cv,
169                                                        final CompilerInput input,
170                                                        final AspectInfo aspectInfo) {
171     // gen code: if (Aspects.hasAspect(...) { aspectField = (<TYPE>)((HasInstanceLocalAspect)CALLER).aw$getAspect(className, qualifiedName, containerClassName) }
172
if (DeploymentModel.PER_INSTANCE.equals(aspectInfo.getDeploymentModel())) {//TODO && callerIndex >= 0
173
//storeAspectInstance(cv, input, aspectInfo, input.callerIndex);
174
} else if (DeploymentModel.PER_THIS.equals(aspectInfo.getDeploymentModel())
175             && input.callerIndex >= 0) {
176       Label hasAspectCheck = pushPerXCondition(cv, input.callerIndex, aspectInfo);
177       storeAspectInstance(cv, input, aspectInfo, input.callerIndex);
178       cv.visitLabel(hasAspectCheck);
179     } else if (DeploymentModel.PER_TARGET.equals(aspectInfo.getDeploymentModel())
180             && input.calleeIndex >= 0) {
181       Label hasAspectCheck = pushPerXCondition(cv, input.calleeIndex, aspectInfo);
182       storeAspectInstance(cv, input, aspectInfo, input.calleeIndex);
183       cv.visitLabel(hasAspectCheck);
184     }
185
186     if (aspectInfo.getDeploymentModel() == DeploymentModel.PER_INSTANCE) {//TODO refactor with previous if block
187
// gen code: aspectField = (<TYPE>)((HasInstanceLocalAspect)CALLER).aw$getAspect(className, qualifiedName, containerClassName)
188
AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
189       if (input.callerIndex >= 0) {
190         cv.visitVarInsn(ALOAD, input.callerIndex);
191       } else {
192         // caller instance not available - skipping
193
//TODO clean up should not occur
194
}
195       cv.visitMethodInsn(
196               INVOKESTATIC,
197               aspectInfo.getAspectFactoryClassName(),
198               "aspectOf",
199               "(Ljava/lang/Object;)" + aspectInfo.getAspectClassSignature()
200       );
201 // cv.visitLdcInsn(aspectInfo.getAspectClassName().replace('/', '.'));
202
// cv.visitLdcInsn(aspectInfo.getAspectQualifiedName());
203
// AsmHelper.loadStringConstant(cv, aspectInfo.getAspectDefinition().getContainerClassName());
204
// cv.visitMethodInsn(
205
// INVOKEINTERFACE,
206
// HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME,
207
// INSTANCE_LEVEL_GETASPECT_METHOD_NAME,
208
// INSTANCE_LEVEL_GETASPECT_METHOD_SIGNATURE
209
// );
210
// cv.visitTypeInsn(CHECKCAST, aspectInfo.getAspectClassName());
211
cv.visitFieldInsn(
212               PUTFIELD,
213               input.joinPointClassName,
214               aspectInfo.getAspectFieldName(),
215               aspectInfo.getAspectClassSignature()
216       );
217     }
218   }
219
220
221   /**
222    * Load aspect instance on stack
223    *
224    * @param cv
225    * @param input
226    * @param aspectInfo
227    */

228   public void loadAspect(final MethodVisitor cv,
229                          final CompilerInput input,
230                          final AspectInfo aspectInfo) {
231     DeploymentModel deploymentModel = aspectInfo.getDeploymentModel();
232     if (DeploymentModel.PER_JVM.equals(deploymentModel)
233             || DeploymentModel.PER_CLASS.equals(deploymentModel)) {
234       cv.visitFieldInsn(
235               GETSTATIC, input.joinPointClassName, aspectInfo.getAspectFieldName(),
236               aspectInfo.getAspectClassSignature()
237       );
238     } else if (DeploymentModel.PER_INSTANCE.equals(deploymentModel)) {
239       AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
240       cv.visitFieldInsn(
241               GETFIELD, input.joinPointClassName, aspectInfo.getAspectFieldName(),
242               aspectInfo.getAspectClassSignature()
243       );
244     } else if (DeploymentModel.PER_THIS.equals(deploymentModel)) {
245       AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
246       cv.visitFieldInsn(
247               GETFIELD,
248               input.joinPointClassName,
249               aspectInfo.getAspectFieldName(),
250               aspectInfo.getAspectClassSignature()
251       );
252
253       //FIXME see FIXME on aspect instantion
254
Label nullCheck = new Label();
255       cv.visitJumpInsn(IFNONNULL, nullCheck);
256       storeAspectInstance(cv, input, aspectInfo, input.callerIndex);
257       cv.visitLabel(nullCheck);
258
259       AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
260       cv.visitFieldInsn(
261               GETFIELD,
262               input.joinPointClassName,
263               aspectInfo.getAspectFieldName(),
264               aspectInfo.getAspectClassSignature()
265       );
266     } else if (DeploymentModel.PER_TARGET.equals(deploymentModel)) {
267       AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
268       cv.visitFieldInsn(
269               GETFIELD,
270               input.joinPointClassName,
271               aspectInfo.getAspectFieldName(),
272               aspectInfo.getAspectClassSignature()
273       );
274       //FIXME see FIXME on aspect instantion
275

276       Label nullCheck = new Label();
277       cv.visitJumpInsn(IFNONNULL, nullCheck);
278       storeAspectInstance(cv, input, aspectInfo, input.calleeIndex);
279       cv.visitLabel(nullCheck);
280
281       AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
282       cv.visitFieldInsn(
283               GETFIELD,
284               input.joinPointClassName,
285               aspectInfo.getAspectFieldName(),
286               aspectInfo.getAspectClassSignature()
287       );
288     } else {
289       throw new DefinitionException("deployment model [" + deploymentModel + "] is not supported");
290     }
291   }
292
293   public void createAroundAdviceArgumentHandling(MethodVisitor cv,
294                                                  CompilerInput input,
295                                                  Type[] joinPointArgumentTypes,
296                                                  AdviceMethodInfo adviceMethodInfo) {
297     defaultCreateAroundAdviceArgumentHandling(
298             cv,
299             input,
300             joinPointArgumentTypes,
301             adviceMethodInfo
302     );
303   }
304
305   public void createBeforeOrAfterAdviceArgumentHandling(MethodVisitor cv,
306                                                         CompilerInput input,
307                                                         Type[] joinPointArgumentTypes,
308                                                         AdviceMethodInfo adviceMethodInfo,
309                                                         int specialArgIndex) {
310     defaultCreateBeforeOrAfterAdviceArgumentHandling(
311             cv,
312             input,
313             joinPointArgumentTypes,
314             adviceMethodInfo,
315             specialArgIndex
316     );
317   }
318
319   public boolean requiresReflectiveInfo() {
320     // custom proceed() JoinPoint will not be recognize by the default logic
321
return m_customProceedMethodStructs.size() > 0;
322   }
323
324   ///////---------- Helpers
325

326   /**
327    * Generate a "if Aspects.hasAspect(qName, instance)"
328    *
329    * @param cv
330    * @param perInstanceIndex
331    * @param aspectInfo
332    * @return
333    */

334   private Label pushPerXCondition(final MethodVisitor cv,
335                                   final int perInstanceIndex,
336                                   final AspectInfo aspectInfo) {
337     Label hasAspectCheck = new Label();
338
339     cv.visitVarInsn(ALOAD, perInstanceIndex);
340     cv.visitMethodInsn(
341             INVOKESTATIC,
342             aspectInfo.getAspectFactoryClassName(),
343             FACTORY_HASASPECT_METHOD_NAME,
344             FACTORY_HASASPECT_PEROBJECT_METHOD_SIGNATURE
345     );
346     cv.visitJumpInsn(IFEQ, hasAspectCheck);
347
348     return hasAspectCheck;
349   }
350
351   /**
352    * Creates the instance of an aspect by invoking
353    * "HasInstanceLevelAspect.aw$getAspect(String, String)" on perInstanceIndex variable
354    * and stores the aspect instance in the joinpoint instance field
355    */

356   private void storeAspectInstance(final MethodVisitor cv,
357                                    final CompilerInput input,
358                                    final AspectInfo aspectInfo,
359                                    final int perInstanceIndex) {
360     AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
361
362     if (perInstanceIndex >= 0) {
363       cv.visitVarInsn(ALOAD, perInstanceIndex);
364     }
365
366     cv.visitMethodInsn(
367             INVOKESTATIC,
368             aspectInfo.getAspectFactoryClassName(),
369             FACTORY_ASPECTOF_METHOD_NAME,
370             "(Ljava/lang/Object;)" + aspectInfo.getAspectClassSignature()
371     );
372 //
373
// cv.visitLdcInsn(aspectInfo.getAspectClassName().replace('/', '.'));
374
// cv.visitLdcInsn(aspectInfo.getAspectQualifiedName());
375
// AsmHelper.loadStringConstant(cv, aspectInfo.getAspectDefinition().getContainerClassName());
376
// cv.visitMethodInsn(
377
// INVOKEINTERFACE,
378
// HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME,
379
// INSTANCE_LEVEL_GETASPECT_METHOD_NAME,
380
// INSTANCE_LEVEL_GETASPECT_METHOD_SIGNATURE
381
// );
382
//
383
// cv.visitTypeInsn(CHECKCAST, aspectInfo.getAspectClassName());
384

385     cv.visitFieldInsn(
386             PUTFIELD,
387             input.joinPointClassName,
388             aspectInfo.getAspectFieldName(),
389             aspectInfo.getAspectClassSignature()
390     );
391   }
392
393   /**
394    * Creates the custom proceed methods.
395    */

396   private void createCustomProceedMethods(ClassWriter cw, AbstractJoinPointCompiler compiler) {
397     Set JavaDoc addedMethodSignatures = new HashSet JavaDoc();
398     for (Iterator JavaDoc it = m_customProceedMethodStructs.iterator(); it.hasNext();) {
399       CustomProceedMethodStruct customProceedStruct = (CustomProceedMethodStruct) it.next();
400       MethodInfo methodInfo = customProceedStruct.customProceed;
401       final String JavaDoc desc = methodInfo.getSignature();
402
403       if (addedMethodSignatures.contains(desc)) {
404         continue;
405       }
406       addedMethodSignatures.add(desc);
407
408       MethodVisitor cv = cw.visitMethod(
409               ACC_PUBLIC | ACC_FINAL,
410               PROCEED_METHOD_NAME,
411               desc,
412               null,
413               new String JavaDoc[]{
414                       THROWABLE_CLASS_NAME
415               }
416       );
417
418       // update the joinpoint instance with the given values
419
// starts at 1 since first arg is the custom join point by convention
420
//TODO see JoinPointManage for this custom jp is first convention
421
int argStackIndex = 1;
422       for (int i = 1; i < customProceedStruct.adviceToTargetArgs.length; i++) {
423         int targetArg = customProceedStruct.adviceToTargetArgs[i];
424         if (targetArg >= 0) {
425           // regular arg
426
String JavaDoc fieldName = compiler.m_fieldNames[targetArg];
427           cv.visitVarInsn(ALOAD, 0);
428           Type type = compiler.m_argumentTypes[targetArg];
429           argStackIndex = AsmHelper.loadType(cv, argStackIndex, type);
430           cv.visitFieldInsn(PUTFIELD, compiler.m_joinPointClassName, fieldName, type.getDescriptor());
431         } else if (targetArg == AdviceInfo.TARGET_ARG) {
432           cv.visitVarInsn(ALOAD, 0);
433           argStackIndex = AsmHelper.loadType(
434                   cv, argStackIndex, Type.getType(compiler.m_calleeClassSignature)
435           );
436           cv.visitFieldInsn(
437                   PUTFIELD,
438                   compiler.m_joinPointClassName,
439                   CALLEE_INSTANCE_FIELD_NAME,
440                   compiler.m_calleeClassSignature
441           );
442         } else if (targetArg == AdviceInfo.THIS_ARG) {
443           cv.visitVarInsn(ALOAD, 0);
444           argStackIndex = AsmHelper.loadType(
445                   cv, argStackIndex, Type.getType(compiler.m_callerClassSignature)
446           );
447           cv.visitFieldInsn(
448                   PUTFIELD,
449                   compiler.m_joinPointClassName,
450                   CALLER_INSTANCE_FIELD_NAME,
451                   compiler.m_callerClassSignature
452           );
453         } else {
454           ;//skip it
455
}
456       }
457
458       // call proceed()
459
// and handles unwrapping for returning primitive
460
Type returnType = Type.getType(customProceedStruct.customProceed.getReturnType().getSignature());
461       if (AsmHelper.isPrimitive(returnType)) {
462         cv.visitVarInsn(ALOAD, 0);
463         cv.visitMethodInsn(
464                 INVOKESPECIAL,
465                 compiler.m_joinPointClassName,
466                 PROCEED_METHOD_NAME,
467                 PROCEED_METHOD_SIGNATURE
468         );
469         AsmHelper.unwrapType(cv, returnType);
470       } else {
471         cv.visitVarInsn(ALOAD, 0);
472         cv.visitMethodInsn(
473                 INVOKESPECIAL,
474                 compiler.m_joinPointClassName,
475                 PROCEED_METHOD_NAME,
476                 PROCEED_METHOD_SIGNATURE
477         );
478         if (!returnType.getClassName().equals(OBJECT_CLASS_SIGNATURE)) {
479           cv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
480         }
481       }
482       AsmHelper.addReturnStatement(cv, returnType);
483       cv.visitMaxs(0, 0);
484     }
485   }
486
487   //---------- Model specific methods
488

489   /**
490    * Collects the custom proceed methods used in the advice specified.
491    *
492    * @param model
493    * @param advices
494    */

495   private void collectCustomProceedMethods(final CompilationInfo.Model model,
496                                            final AdviceInfoContainer advices) {
497     ClassLoader JavaDoc loader = model.getThisClassInfo().getClassLoader();
498     final AdviceInfo[] beforeAdviceInfos = advices.getBeforeAdviceInfos();
499     for (int i = 0; i < beforeAdviceInfos.length; i++) {
500       collectCustomProceedMethods(beforeAdviceInfos[i], loader);
501     }
502     final AdviceInfo[] aroundAdviceInfos = advices.getAroundAdviceInfos();
503     for (int i = 0; i < aroundAdviceInfos.length; i++) {
504       collectCustomProceedMethods(aroundAdviceInfos[i], loader);
505     }
506     final AdviceInfo[] afterFinallyAdviceInfos = advices.getAfterFinallyAdviceInfos();
507     for (int i = 0; i < afterFinallyAdviceInfos.length; i++) {
508       collectCustomProceedMethods(afterFinallyAdviceInfos[i], loader);
509     }
510     final AdviceInfo[] afterReturningAdviceInfos = advices.getAfterReturningAdviceInfos();
511     for (int i = 0; i < afterReturningAdviceInfos.length; i++) {
512       collectCustomProceedMethods(afterReturningAdviceInfos[i], loader);
513     }
514     final AdviceInfo[] afterThrowingAdviceInfos = advices.getAfterThrowingAdviceInfos();
515     for (int i = 0; i < afterThrowingAdviceInfos.length; i++) {
516       collectCustomProceedMethods(afterThrowingAdviceInfos[i], loader);
517     }
518   }
519
520   /**
521    * Collects the custom proceed methods used in the advice specified.
522    *
523    * @param adviceInfo
524    * @param loader
525    */

526   private void collectCustomProceedMethods(final AdviceInfo adviceInfo, final ClassLoader JavaDoc 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(JOIN_POINT_JAVA_CLASS_NAME) &&
535               !firstParam.getClassName().equals(STATIC_JOIN_POINT_JAVA_CLASS_NAME)) {
536         ClassInfo classInfo = AsmClassInfo.getClassInfo(firstParam.getClassName(), loader);
537         if (ClassInfoHelper.implementsInterface(classInfo, JOIN_POINT_JAVA_CLASS_NAME) ||
538                 ClassInfoHelper.implementsInterface(classInfo, STATIC_JOIN_POINT_JAVA_CLASS_NAME)) {
539           // we have ourselves a custom joinpoint
540
MethodInfo[] methods = classInfo.getMethods();
541           for (int j = 0; j < methods.length; j++) {
542             MethodInfo method = methods[j];
543             if (method.getName().equals(PROCEED_METHOD_NAME)) {
544               // we inherit the binding from the advice that actually use us
545
// for now the first advice sets the rule
546
// it is up to the user to ensure consistency if the custom proceed
547
// is used more than once in different advices.
548
m_customProceedMethodStructs.add(
549                       new CustomProceedMethodStruct(
550                               method,
551                               adviceInfo.getMethodToArgIndexes()
552                       )
553               );
554             }
555           }
556         }
557       }
558     }
559   }
560
561   private static class CustomProceedMethodStruct {
562     MethodInfo customProceed;
563     int[] adviceToTargetArgs;
564
565     public CustomProceedMethodStruct(MethodInfo customProceed, int[] adviceToTargetArgs) {
566       this.customProceed = customProceed;
567       this.adviceToTargetArgs = adviceToTargetArgs;
568     }
569   }
570
571   public static void defaultCreateBeforeOrAfterAdviceArgumentHandling(MethodVisitor cv,
572                                                                       CompilerInput input,
573                                                                       Type[] joinPointArgumentTypes,
574                                                                       AdviceMethodInfo adviceMethodInfo,
575                                                                       int specialArgIndex) {
576     int[] argIndexes = adviceMethodInfo.getAdviceMethodArgIndexes();
577     // if empty, we consider for now that we have to push JoinPoint for old advice with JoinPoint as sole arg
578
for (int j = 0; j < argIndexes.length; j++) {
579       int argIndex = argIndexes[j];
580       if (argIndex >= 0) {
581         Type argumentType = joinPointArgumentTypes[argIndex];
582         int argStackIndex = AsmHelper.getRegisterIndexOf(joinPointArgumentTypes, argIndex) + input.argStartIndex;
583         AsmHelper.loadType(cv, argStackIndex, argumentType);
584       } else if (argIndex == AdviceInfo.JOINPOINT_ARG || argIndex == AdviceInfo.STATIC_JOINPOINT_ARG) {
585         AbstractJoinPointCompiler.loadJoinPointInstance(cv, input);
586       } else if (argIndex == AdviceInfo.TARGET_ARG) {
587         AbstractJoinPointCompiler.loadCallee(cv, input);
588         // add a cast if runtime check was used
589
if (adviceMethodInfo.getAdviceInfo().hasTargetWithRuntimeCheck()) {
590           cv.visitTypeInsn(
591                   CHECKCAST,
592                   adviceMethodInfo.getAdviceInfo().getMethodParameterTypes()[j].getInternalName()
593           );
594         }
595       } else if (argIndex == AdviceInfo.THIS_ARG) {
596         AbstractJoinPointCompiler.loadCaller(cv, input);
597       } else if (argIndex == AdviceInfo.SPECIAL_ARGUMENT && specialArgIndex != INDEX_NOTAVAILABLE) {
598         Type argumentType = adviceMethodInfo.getAdviceInfo().getMethodParameterTypes()[j];
599         AsmHelper.loadType(cv, specialArgIndex, argumentType);
600         if (AdviceType.AFTER_THROWING.equals(adviceMethodInfo.getAdviceInfo().getAdviceDefinition().getType())
601                 || AdviceType.AFTER_RETURNING.equals(adviceMethodInfo.getAdviceInfo().getAdviceDefinition().getType()))
602         {
603           cv.visitTypeInsn(CHECKCAST, argumentType.getInternalName());
604         }
605       } else {
606         throw new Error JavaDoc("magic index is not supported: " + argIndex);
607       }
608     }
609   }
610
611   public static void defaultCreateAroundAdviceArgumentHandling(MethodVisitor cv,
612                                                                CompilerInput input,
613                                                                Type[] joinPointArgumentTypes,
614                                                                AdviceMethodInfo adviceMethodInfo) {
615     int[] argIndexes = adviceMethodInfo.getAdviceMethodArgIndexes();
616     for (int j = 0; j < argIndexes.length; j++) {
617       int argIndex = argIndexes[j];
618       if (argIndex >= 0) {
619         Type argumentType = joinPointArgumentTypes[argIndex];
620         cv.visitVarInsn(ALOAD, 0);
621         cv.visitFieldInsn(
622                 GETFIELD,
623                 input.joinPointClassName,
624                 ARGUMENT_FIELD + argIndex,
625                 argumentType.getDescriptor()
626         );
627       } else if (argIndex == AdviceInfo.JOINPOINT_ARG ||
628               argIndex == AdviceInfo.STATIC_JOINPOINT_ARG ||
629               argIndex == AdviceInfo.VALID_NON_AW_AROUND_CLOSURE_TYPE ||
630               argIndex == AdviceInfo.CUSTOM_JOIN_POINT_ARG) {
631         cv.visitVarInsn(ALOAD, 0);
632       } else if (argIndex == AdviceInfo.TARGET_ARG) {
633         AbstractJoinPointCompiler.loadCallee(cv, input);
634         // add a cast if runtime check was used
635
if (adviceMethodInfo.getAdviceInfo().hasTargetWithRuntimeCheck()) {
636           cv.visitTypeInsn(
637                   CHECKCAST,
638                   adviceMethodInfo.getAdviceInfo().getMethodParameterTypes()[j].getInternalName()
639           );
640         }
641       } else if (argIndex == AdviceInfo.THIS_ARG) {
642         AbstractJoinPointCompiler.loadCaller(cv, input);
643       } else {
644         throw new Error JavaDoc("advice method argument index type is not supported: " + argIndex);
645       }
646     }
647   }
648
649 }
650
Popular Tags