Bug 273628 - java.lang.VerifyError: Incompatible argument to function when using an annotation value binding in a pointcut
Summary: java.lang.VerifyError: Incompatible argument to function when using an annota...
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.6.3   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.6.5   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-04-24 14:40 EDT by Jonathan Brown CLA
Modified: 2009-04-24 17:28 EDT (History)
1 user (show)

See Also:


Attachments
Eclipse java project demonstrating bug (4.10 KB, application/x-zip-compressed)
2009-04-24 14:40 EDT, Jonathan Brown CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Brown CLA 2009-04-24 14:40:21 EDT
Created attachment 133162 [details]
Eclipse java project demonstrating bug

I am trying to extract a value from an annotation and pass it into my advice but I am not having much luck.

Here is the exception generated by my test project:
Exception in thread "main" java.lang.VerifyError: (class: aspectj/pointcut/annotation/bug/AspectTargetClass, method: aspectTargetMethod signature: ()V) Incompatible argument to function
	at aspectj.pointcut.annotation.bug.TestPointcutAnnotationAspect.main(TestPointcutAnnotationAspect.java:7)


This simple example works if I run with the jvm -noverify flag, however my real-world case fails with a different error when I try to do that (the ApiDescriptor argument value passed into AnnotationAspect.monitorMethodPerformancePartialAnnotation is the wrong type -- it's the object that the pointcut matched).  I can investigate that more should the resolution of the VerifyError bug not completely take care of the problem.

I am using version 1.6.3.20090122141228 of the AspectJ Development Tools plug-in and I have tried JDK 1.5.0_16 and JDK 1.6.0_07.  My eclipse version is 3.4.0.


Here is the article I used as a reference:
http://andrewclement.blogspot.com/2009/02/aspectj-optimized-annotation-value.html
Comment 1 Andrew Clement CLA 2009-04-24 15:14:09 EDT
Few things uncovered here...

I can make it work in code style (I shortened the package to p for readability):

  pointcut p(ApiDescriptor api): if(true) && 
    execution(@MonitorableMethod public * p..*(..)) && 
    @annotation(MonitorableMethod(api));

  Object around(ApiDescriptor api): p(api) {
    System.out.println("Descriptor value: " + api.number);
    return proceed(api);
  }

however, that proceed(api) isn't right - there shouldn't be a need to pass api.  Not passing it causes this error:

"too few arguments to proceed, expected 1"

Going back to annotation style and trying the same solution (passing api):

return pjp.proceed(new Object[]{api});

gives this nasty problem:

C:\temp\ajcSandbox\aspectj16_2\ajcTest30146.tmp\AnnotationAspect.java:0::0 Internal compiler error
java.lang.ArrayIndexOutOfBoundsException: 1
	at org.aspectj.weaver.bcel.BcelWeaver.validateSingleBranchRecursion(BcelWeaver.java:808)
	at org.aspectj.weaver.bcel.BcelWeaver.validateSingleBranchRecursion(BcelWeaver.java:791)


And as Jonathan says, not passing anything on proceed in a pure annotation style aspect gives:

junit.framework.AssertionFailedError: Exception thrown by p.TestPointcutAnnotationAspect.main(String[]) :java.lang.VerifyError: (class: p/AspectTargetClass, method: aspectTargetMethod signature: ()V) Incompatible argument to function
	at junit.framework.Assert.fail(Assert.java:47)
	at org.aspectj.tools.ajc.AjcTestCase.run(AjcTestCase.java:655)
	at org.aspectj.testing.RunSpec.execute(RunSpec.java:62)
	at org.aspectj.testing.AjcTest.runTest(AjcTest.java:72)


a few things to sort out...

Comment 2 Andrew Clement CLA 2009-04-24 16:25:57 EDT
ok - let's ignore for now that it wants the annotation value passing in again and look at the verifyerror.  Here is the problem code:

public void aspectTargetMethod();
  org.aspectj.weaver.MethodDeclarationLineNumber: length = 0x8
   00 00 00 07 00 00 00 FFFFFF85 
  Code:
   Stack=5, Locals=2, Args_size=1
   0:	getstatic	#41; //Field ajc$tjp_0:Lorg/aspectj/lang/JoinPoint$StaticPart;
   3:	aload_0
   4:	aload_0
   5:	invokestatic	#47; //Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
   8:	astore_1
   9:	aload_0
   10:	invokestatic	#93; //Method p/AnnotationAspect.adviseIfMonitoringPartialAnnotation:(Lp/ApiDescriptor;)Z
   13:	ifeq	30
   16:	aload_0
   17:	aload_1
   18:	invokestatic	#81; //Method p/AnnotationAspect.aspectOf:()Lp/AnnotationAspect;
   21:	aload_1
   22:	getstatic	#83; //Field p/ApiDescriptor.TARGET_CLASS_TARGET_METHOD:Lp/ApiDescriptor;
   25:	invokestatic	#87; //Method aspectTargetMethod_aroundBody1$advice:(Lp/AspectTargetClass;Lorg/aspectj/lang/JoinPoint;Lp/AnnotationAspect;Lorg/aspectj/lang/ProceedingJoinPoint;Lp/ApiDescriptor;)Ljava/lang/Object;
   28:	pop
   29:	return
   30:	aload_0
   31:	aload_1
   32:	invokestatic	#89; //Method aspectTargetMethod_aroundBody0:(Lp/AspectTargetClass;Lorg/aspectj/lang/JoinPoint;)V
   35:	return
   36:	nop

this bit looks to blame:
  9:	aload_0
   10:	invokestatic	#93; //Method p/AnnotationAspect.adviseIfMonitoringPartialAnnotation:(Lp/ApiDescriptor;)Z

as it tries to call adviseIfMonitoringPartialAnnotation(ApiDescriptor), passing an AspectTargetClass instance.

That represents invocation of the if() pointcut code "return true".  And indeed if we remove if the 'if() &&' from the annotation style pointcut (and change the pointcut to return void) then the aspect works.
Comment 3 Jonathan Brown CLA 2009-04-24 16:53:56 EDT
My real use case also succeeds following removal of the if() clause in the pointcut.  I can move the logic from my adviseIfMonitoring method into the advice itself as a temporary workaround.


Comment 4 Andrew Clement CLA 2009-04-24 17:28:39 EDT
Verify Error is now fixed.  New generated code accesses the field of the annotation before calling the if()

 8:	astore_1
   9:	getstatic	#83; //Field p/ApiDescriptor.TARGET_CLASS_TARGET_METHOD:Lp/ApiDescriptor;
   12:	invokestatic	#93; //Method p/AnnotationAspect.adviseIfMonitoringPartialAnnotation:(Lp/ApiDescriptor;)Z

test and fix committed.

I have raised bug 273655 to cover the other wierdness discovered during investigating this bug.