Bug 194314 - [plan] [weaving] LocalVariableTable not updated for statically woven around advice
Summary: [plan] [weaving] LocalVariableTable not updated for statically woven around a...
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.3   Edit
Hardware: PC Windows XP
: P3 normal with 1 vote (vote)
Target Milestone: 1.6.4   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 122725
  Show dependency tree
 
Reported: 2007-06-25 17:04 EDT by Tim Eck CLA
Modified: 2009-01-29 16:38 EST (History)
3 users (show)

See Also:


Attachments
A small test case demostrating the problem (6.66 KB, application/zip)
2007-06-25 17:05 EDT, Tim Eck CLA
no flags Details
patch to fix this (28.30 KB, patch)
2008-12-09 15:19 EST, Andrew Clement CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tim Eck CLA 2007-06-25 17:04:27 EDT
Build ID: M20070212-1330

Steps To Reproduce:
I'll attach the complete test program once I enter the bug report here. 

In a nutshell, the static method "method_aroundBody1$advice" is introduced in my class where the aspect should be applied. Problem is that the LocalVariableTable code attributes are wrong for this method. It looks like they have been copied from the aspect class and have not been updated for the new method paramters and the changes in the slots where the original locals are stored. 

The woven aspect method has this as it's LocalVaraibleTable:
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      87      0    this       Ltest/ServiceInterceptor;
   0      87      1    pjp       Lorg/aspectj/lang/ProceedingJoinPoint;
   9      78      2    args       [Ljava/lang/Object;
   21      66      3    id       J

Problem is that the method has a bunch of new paramters to it, it no longer an instance method, and the locals "args" and "id" are not stored in the slots indicated. 


More information:
AJDT Version: 1.4.1.200611230655
AspectJ version: 1.5.3.200611221118
Comment 1 Tim Eck CLA 2007-06-25 17:05:50 EDT
Created attachment 72409 [details]
A small test case demostrating the problem

In the attached file, look at the test.Service class after the aspects are woven into it. The LocalVariableTable for the method "method_aroundBody1$advice" is not correct (it has not been adjusted by the ajc)
Comment 2 Eugene Kuleshov CLA 2007-06-26 02:37:17 EDT
This glitch makes it difficult to match method parameter names on those methods using debug info about param names. I think Spring framework is using such strategy in some cases.
Comment 3 Andrew Clement CLA 2008-10-31 15:29:15 EDT
A number of cases to look at here:

- more than the aroundBody1 method is incorrect, the aroundBody0 method is also incorrect
- whether the advice uses: this, target, this & target, args binding, thisJoinPoint, thisEnclosingJoinPoint or ProceedingJoinPoint all affect the ordering
- annotation and code style aspects exercise different code paths

== a few testcases.

Comment 4 Andrew Clement CLA 2008-12-09 15:19:50 EST
Created attachment 119960 [details]
patch to fix this

The attached patch modifies the weaver to create beautiful local variable tables.  But currently it is not 'free' - needs a bit of work to reduce the cost of getting the tables right.
Comment 5 Andrew Eisenberg CLA 2008-12-12 14:07:58 EST
Would it be possible to provide this as an option that can be switched on and off?

Also, are you talking about compile time cost or runtime cost?
Comment 6 Andrew Clement CLA 2008-12-12 14:10:01 EST
i considered it, but really it should be done properly and thats that.  No point in creating wrong local variable tables so work would even be involved in the OFF case to delete the (wrong) tables that are there.
Comment 7 Andrew Clement CLA 2008-12-12 14:46:57 EST
do let me know if this is breaking the eclipse debugger due to the incorrect entries, that makes it more critical.
Comment 8 Andrew Clement CLA 2009-01-27 20:01:20 EST
gradually integrating this - but complex series of changes in that patch (and fool that I am, I didn't make sure all the tests passed before I put the patch here, DOH).
Comment 9 Andrew Clement CLA 2009-01-27 22:25:43 EST
Ok - it seems mostly working apart from two situations:

The newarray joinpoint (only accessible if using a -X switch) has a parameter that is the dimensions for the array.  We don't assign a name to this parameter right now (we would do that in ResolvedType.lookupsyntheticmember() where it deals with ArrayConstructionJoinpoints).  

around advice applying to ITDs.  A mangled member that exists due to an ITD has an effective signature attribute that describes the actual signature of the join point that the ITD would represent.  This effective signature knows nothing about parameter names.  That information could be copied across from the member when the effective one is created, but a better solution would be for an effective signature object to go and fetch the names from the real one if it is ever asked. 

However, I might commit what is working so far as it will cover many cases.
Comment 10 Andrew Clement CLA 2009-01-28 14:34:23 EST
Decided to try and address it for ITDs.  The problem is definetly all the infrastructure methods created to manage a single ITD.

By changing BcelClassWeaver.matchInvokeInstruction() we can ensure that the effective signature member used to create a method gets some parameter names.  Unfortunately it is getting them from the interMethodDispatcher - and that never got them set correctly when constructed.

The interMethodDispatcher for the itd 'public I.foo(String s,int i,String[] ss)'
is called: 'ajc$interMethodDispatch1$X$I$foo' and is created in the aspect.  The local variables for this can be setup during compilation in the InterTypeMethodDeclaration.generateDispatchMethod() code.  It is quite straightforward because they should match those declared on the ITD (itself represented as the member 'ajc$interMethod$X$I$foo' in the aspect.  There is a bit of trickery to ensure the JDT compiler does not throw out these seemingly unused locals, but once that is done we can see them clearly in the classfile.

Here is the declaration:

aspect X {
  public void I.foo(String s,int i,String[] ss) {}
}

and here are the two generated support methods in the aspect:

public static void ajc$interMethod$X$I$foo(I, java.lang.String, int, java.lang.String[]);
  Code:
   Stack=0, Locals=4, Args_size=4
   0:   return
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      0      0    ajc$this_       LI;
   0      0      1    s       Ljava/lang/String;
   0      0      2    i       I
   0      0      3    ss       [Ljava/lang/String;

public static void ajc$interMethodDispatch1$X$I$foo(I, java.lang.String, int, java.lang.String[]);
  Code:
   Stack=4, Locals=4, Args_size=4
   0:   aload_0
   1:   aload_1
   2:   iload_2
   3:   aload_3
   4:   invokeinterface #69,  4; //InterfaceMethod I.foo:(Ljava/lang/String;I[Ljava/lang/String;)V
   9:   return
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      10      0    ajc$this_       LI;
   0      10      1    s       Ljava/lang/String;
   0      10      2    i       I
   0      10      3    ss       [Ljava/lang/String;

Once the dispatch method has the right local variables, they can be copied to the effective signature member created for matching purposes.  Once they are correctly recorded there, the around advice against the ITD will get them.

void around(): call(* foo(..)) {}

producing:
private static final void foo_aroundBody1$advice(C, I, java.lang.String, int, java.lang.String[], X, org.aspectj.runtime.internal.AroundClosure);
  Synthetic: true
  Code:
   Stack=0, Locals=7, Args_size=7
   0:   return
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      0      0    this       LC;
   0      0      1    target       LI;
   0      0      2    s       Ljava/lang/String;
   0      0      3    i       I
   0      0      4    ss       [Ljava/lang/String;
   0      0      5    otherThis       LX;
   0      0      6    ajc_aroundClosure       Lorg/aspectj/runtime/internal/AroundClosure;

running tests now...
Comment 11 Andrew Clement CLA 2009-01-29 16:38:41 EST
Ok.  Resolved.

here is the local variable table for the method_aroundBody1$advice created based on the code initially attached to the bug report:

 LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      86      0    this       Ltest/Service;
  0      86      1    l       J
  0      86      3    thisJoinPoint       Lorg/aspectj/lang/JoinPoint;
  0      86      4    ajc$aspectInstance       Ltest/ServiceInterceptor;
  0      86      5    pjp       Lorg/aspectj/lang/ProceedingJoinPoint;
  9      77      6    args       [Ljava/lang/Object;
  21      65      7    id       J

It is also fixed for around advice on ITDs and newarray joinpoints.