Community
Participate
Working Groups
While following up a mailing list question, I blundered into a bug I don't understand. Same result in 1.5.1 (command-line) and 1.5.1a (via AJDT 1.3.1). ---------------- output Starting CflowOrder.main(..) Exception in thread "main" java.lang.VerifyError: (class: bugs/CflowOrder$A, method: foo signature: ()V) Incompatible object argument for function call at bugs.CflowOrder.main(CflowOrder.java:20) ---------------- bugs/CflowOrder.java package bugs; import java.io.PrintStream; import java.lang.annotation.*; import org.aspectj.lang.JoinPoint; public class CflowOrder { public static void main(String[] args) { Log.print("Starting CflowOrder.main(..)"); A.main(null); Log.print("Ending CflowOrder.main(..)"); } @Retention(value = RetentionPolicy.RUNTIME) @interface Annotation { String value(); } static class A { @Annotation("A.foo") void foo() { new B().foo(); Log.print("A.foo()"); } public static void main(String[] args) { new A().foo(); Log.print("A.main(..)"); } } static class B { @Annotation("B.foo") void foo() { Log.print("B.foo()"); } } static class Log implements IAspect { static final PrintStream out = System.err; static void print(String label) { out.println(label); } static void print(String label, JoinPoint tjp, JoinPoint.StaticPart sp, Object a) { out.println(label); out.println("\tJoin point: " + tjp); out.println("\tEnclosing join point: " + sp); out.println("\tAnnotation: " + a); } } static aspect Logger implements IAspect { //declare error: execution(* *(..)) && !within(Log) : "er"; // before() : cflow(execution(void CflowOrder.main(String[]))) // && !call(* IAspect+.*(..)) && ! within(IAspect+) { // Log.print("cflow(..main(..))", thisJoinPoint, // thisEnclosingJoinPointStaticPart, null); // } } interface IAspect {} static aspect MyAspect implements IAspect { pointcut annotated(Annotation a) : call(@Annotation * *(..)) && @annotation(a); pointcut belowAnnotated() : cflowbelow(annotated(Annotation)); pointcut topAnnotated(Annotation a) : annotated(a) && !belowAnnotated(); pointcut notTopAnnotated(Annotation a, Annotation aTop) : annotated(a) && cflowbelow(annotated(aTop)); // pointcut topAnnotated(Annotation a) : annotated(a) // && !cflowbelow(annotated(Annotation)); // // pointcut notTopAnnotated(Annotation a, Annotation aTop) : annotated(a) // && cflowbelow(topAnnotated(aTop)); // if this first, then no nonTopAnnotated advice before(Annotation a) : topAnnotated(a) { Log.print("topAnnotated", thisJoinPoint, thisEnclosingJoinPointStaticPart, a); } // if topAnnotated is first, this does not run before(Annotation a, Annotation aTop) : notTopAnnotated(a, aTop) { Log.print("nonTopAnnotated", thisJoinPoint, thisEnclosingJoinPointStaticPart, a); } } }
Created attachment 38239 [details] .class files produced by ajc 1.5.1
Yikes, that was hard to diagnose. Offending code looks like: 46: getstatic #36; //Field CflowOrder$MyAspect.ajc$cflowCounter$0:Lorg/aspectj/runtime/internal/CFlowCounter; 49: bipush 0 51: invokevirtual #42; //Method org/aspectj/runtime/internal/CFlowStack.get:(I)Ljava/lang/Object; You can't call CflowStack.get() on a CflowCounter instance! This is occurring because of the logic that shares cflow fields when working with the same pointcut. Unfortunately in the situation in this program the pointcut behaves like a counter in one place and a stack in the other (ie. the consumer of the pointcut is using the context it exposes in one case but not the other). Our cache that is indexed by "pointcutString:declaringAspect" to find a cflow field doesn't take into account the kind of context in which it is being used. if we extend the cache key to include this information (by appending 'stack' or 'counter' to the key) then it works. fix committed - there are possibly other bugzilla cases that are this same problem, but Wes' testcase was the best ;)