Bug 100195 - Missing LocalVariableTable debug info for around advice
Summary: Missing LocalVariableTable debug info for around advice
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 1.5.0 M4   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 101047
Blocks:
  Show dependency tree
 
Reported: 2005-06-15 10:40 EDT by Per S Hustad CLA
Modified: 2005-10-05 05:40 EDT (History)
0 users

See Also:


Attachments
screenshot of debugging inlined around advice w. local vars (42.50 KB, image/jpeg)
2005-10-05 05:40 EDT, Adrian Colyer CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Per S Hustad CLA 2005-06-15 10:40:29 EDT
AspectJ version: 1.2.1  (also observed in aspectj-DEVELOPMENT)
java version "1.4.2_07"

When debugging java code woven with an "around" advice with proceed, it looks 
like the LocalVariableTable information gets lost during the weaving. Example 
code:

// Foo.java
public class Foo {
    private String myString = "A String";
    public static void main(String[] args) {
        new Foo().foo();
    }
    private void foo() {
      String myLocal = myString;
      System.out.println(myLocal);   // breakpoint here
    }
}
// Test.aj
aspect Test {
  void around() : ( execution(* Foo.foo(..) ) ) {
      System.out.println("before");
      proceed();
      System.out.println("after");
  }
}

We compiled with ajc 1.2.1:
  ajc -g -preserveAllLocals -sourceroots .

When running Foo in the Eclipse 3.1.0 debugger and setting a breakpoint at
the "System.out.println(myLocal);" line, the debugger "Variables" window is
empty. Also, disassembling with javap shows that the LocalVariableTable is
empty in the generated foo_aroundBody0 method :

> javap -c -l -s -private Foo

 private static final void foo_aroundBody0(Foo);
  Signature: (LFoo;)V
  Code:
   0:   aload_0
   1:   getfield        #15; //Field myString:Ljava/lang/String;
   4:   astore_1
   5:   aload_1
   6:   ldc     #30; //String X
   8:   invokevirtual   #36; //Method java/lang/String.endsWith:
(Ljava/lang/String;)Z
   11:  ifeq    27
   14:  ldc     #38; //String local1
   16:  astore_3
   17:  getstatic       #44; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload_3
   21:  invokevirtual   #50; //Method java/io/PrintStream.println:
(Ljava/lang/String;)V
   24:  goto    37
   27:  ldc     #52; //String local2
   29:  astore_3
   30:  getstatic       #44; //Field java/lang/System.out:Ljava/io/PrintStream;
   33:  aload_3
   34:  invokevirtual   #50; //Method java/io/PrintStream.println:
(Ljava/lang/String;)V
   37:  return

  LineNumberTable: 
   line 7: 0
   line 8: 5
   line 9: 14
   line 10: 17
   line 12: 27
   line 13: 30
   line 15: 37
Comment 1 Per S Hustad CLA 2005-06-15 10:55:08 EDT
I have started looking into this. Obviously, the 
org.aspectj.weaver.bcel.ShadowRange does not copy the LocalVariableTags, see 
the comment
// XXX destroying local variable info
Copying the old instruction handle to the new instruction handle actually 
generates a LocalVariableTable for the woven class, but there is another 
problem:
  When the woven code contains branches, the LazyMethodGen.packBody() method 
seem to generate wrong start_pc and length indexes. I'll look further into this 
Comment 2 Adrian Colyer CLA 2005-09-24 07:37:03 EDT
Adding M4 target milestone as per discussion in Oslo...
Comment 3 Adrian Colyer CLA 2005-09-29 07:22:11 EDT
After a few investigations, it turns out that it is safe to retarget local
variable tags when extracting a whole block (method execution, cons execution
etc..), but not when weaving around advice at the statement level inside a block
(eg. get/set/call). I've updated ShadowRange to reflect this. If the new logic
fails, the symptom you well see is a VerifyError with "invalid local variable
index: <some number>".

When I compile:

class Foo {
	
    static int x;
	
    private String myString = "A String";
 
    public static void main(String[] args) {
        new Foo().foo();
        AroundCasting.main(new String[0]);
    }
 
    public void foo() {
      String myLocal = myString;
      x = 5;
      System.out.println(myLocal);   // breakpoint here
      bar(x);
    }
    
    public void bar(int y) {}
}
// Test.aj
aspect Test {
  void around() : ( execution(* Foo.foo(..) ) ) {
	  int y = 4;
      System.out.println("before");
      proceed();
      System.out.println("after");
  }
}

I now get the output:

private static final void foo_aroundBody0(Foo);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:	aload_0
   1:	getfield	#17; //Field myString:Ljava/lang/String;
   4:	astore_1
   5:	iconst_5
   6:	putstatic	#38; //Field x:I
   9:	getstatic	#44; //Field java/lang/System.out:Ljava/io/PrintStream;
   12:	aload_1
   13:	invokevirtual	#50; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:	aload_0
   17:	getstatic	#38; //Field x:I
   20:	invokevirtual	#54; //Method bar:(I)V
   23:	return
  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      24      0    this       LFoo;
   5      19      1    myLocal       Ljava/lang/String;
  LineNumberTable: 
   line 22: 0
   line 23: 5
   line 24: 9
   line 25: 16
   line 26: 23

(note the correctly preserved locals and line numbers).

I'm committing this change, but want to wait and see this do the right thing in
the AJDT debugger before closing out the bug.
Comment 4 Adrian Colyer CLA 2005-10-05 05:39:12 EDT
Required one final change in the weaver to cope with our remapping of locals to
wide slots. Finally you can debug inlined around advice methods and see all
locals in the debugger (see screenshot in the attachment).

Fix will be available in next published AspectJ build, and incorporated into
AJDT next Monday.
Comment 5 Adrian Colyer CLA 2005-10-05 05:40:05 EDT
Created attachment 27852 [details]
screenshot of debugging inlined around advice w. local vars