Bug 154253 - Around advice weaving generates repeated methods
Summary: Around advice weaving generates repeated methods
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.2   Edit
Hardware: PC All
: P5 enhancement (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-08-17 12:27 EDT by Eduardo Cordeiro CLA
Modified: 2013-06-24 11:04 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eduardo Cordeiro CLA 2006-08-17 12:27:19 EDT
Shadow extraction and advice inlining in around advice weaver generate repeated methods for occurrences of an identical shadow on a same class. This is an example:

public class BugExample {
	public static void main(String[] args) {
		new BugExample().run();
	}
	private void run() {
		int x = foo(-5);
		int y = foo(1);
		int z = foo(2);
		int w = foo(0);
		System.out.println("x=" + x + " y=" + y + " z=" + z + " w=" + w);
	}
	private int foo(int v) {
		return v;
	}
	public static aspect BugAspect {
		pointcut fooCalls(int v): call(* BugExample.foo(int)) && args(v);
		int around(int v): fooCalls(v) {
			if (v > 0)
				return proceed(v);
			else
				return 0;
		}
	}
}

The result of "javap -c -private BugExample" is at the end of this report (it's rather big). In it you may realize that there is no difference between the several proceed methods, and the only difference between the several advice inline methods is which proceed method invoked (and since those are equivalent, there is no semantic difference between the advice methods either).

I have fixed this problem by applying an aspect to the AspectJ weaver, which caches shadow and advice methods and reuses them as possible. This is done by capturing calls to BcelShadow.extractShadow and avoiding such calls if a method with the same signature has already been created. The same is done for the creation of local advice methods. Of course, this only indicates a path to a (pure Java) final solution.

D:\trabalho\mestrado\pesquisa\ajc-bugreport\bin>javap -c -private BugExample
Compiled from "BugExample.java"
public class BugExample extends java.lang.Object{
public BugExample();
  Code:
   0:   aload_0
   1:   invokespecial   #9; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class BugExample
   3:   dup
   4:   invokespecial   #17; //Method "<init>":()V
   7:   invokespecial   #20; //Method run:()V
   10:  return

private void run();
  Code:
   0:   aload_0
   1:   bipush  -5
   3:   istore  5
   5:   astore  6
   7:   aload_0
   8:   aload   6
   10:  iload   5
   12:  invokestatic    #84; //Method BugExample$BugAspect.aspectOf:()LBugExample$BugAspect;
   15:  iload   5
   17:  aconst_null
   18:  invokestatic    #88; //Method foo_aroundBody1$advice:(LBugExample;LBugExample;ILBugExample$BugAspect;ILorg/aspectj/runtime/internal/AroundClosure;)I
   21:  istore_1
   22:  aload_0
   23:  iconst_1
   24:  istore  7
   26:  astore  8
   28:  aload_0
   29:  aload   8
   31:  iload   7
   33:  invokestatic    #84; //Method BugExample$BugAspect.aspectOf:()LBugExample$BugAspect;
   36:  iload   7
   38:  aconst_null
   39:  invokestatic    #94; //Method foo_aroundBody3$advice:(LBugExample;LBugExample;ILBugExample$BugAspect;ILorg/aspectj/runtime/internal/AroundClosure;)I
   42:  istore_2
   43:  aload_0
   44:  iconst_2
   45:  istore  9
   47:  astore  10
   49:  aload_0
   50:  aload   10
   52:  iload   9
   54:  invokestatic    #84; //Method BugExample$BugAspect.aspectOf:()LBugExample$BugAspect;
   57:  iload   9
   59:  aconst_null
   60:  invokestatic    #100; //Method foo_aroundBody5$advice:(LBugExample;LBugExample;ILBugExample$BugAspect;ILorg/aspectj/runtime/internal/AroundClosure;)I
   63:  istore_3
   64:  aload_0
   65:  iconst_0
   66:  istore  11
   68:  astore  12
   70:  aload_0
   71:  aload   12
   73:  iload   11
   75:  invokestatic    #84; //Method BugExample$BugAspect.aspectOf:()LBugExample$BugAspect;
   78:  iload   11
   80:  aconst_null
   81:  invokestatic    #106; //Method foo_aroundBody7$advice:(LBugExample;LBugExample;ILBugExample$BugAspect;ILorg/aspectj/runtime/internal/AroundClosure;)I
   84:  istore  4
   86:  getstatic       #32; //Field java/lang/System.out:Ljava/io/PrintStream;
   89:  new     #34; //class java/lang/StringBuilder
   92:  dup
   93:  ldc     #36; //String x=
   95:  invokespecial   #39; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   98:  iload_1
   99:  invokevirtual   #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   102: ldc     #45; //String  y=
   104: invokevirtual   #48; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   107: iload_2
   108: invokevirtual   #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   111: ldc     #50; //String  z=
   113: invokevirtual   #48; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   116: iload_3
   117: invokevirtual   #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   120: ldc     #52; //String  w=
   122: invokevirtual   #48; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   125: iload   4
   127: invokevirtual   #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   130: invokevirtual   #56; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   133: invokevirtual   #61; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   136: return

private int foo(int);
  Code:
   0:   iload_1
   1:   ireturn

private static final int foo_aroundBody0(BugExample, BugExample, int);
  Code:
   0:   aload_1
   1:   iload_2
   2:   invokespecial   #26; //Method foo:(I)I
   5:   ireturn

private static final int foo_aroundBody1$advice(BugExample, BugExample, int, BugExample$BugAspect, int, org.aspectj.runtime.internal.AroundClosure);
  Code:
   0:   iload   4
   2:   ifle    21
   5:   iload   4
   7:   aload   5
   9:   astore  6
   11:  istore  7
   13:  aload_0
   14:  aload_1
   15:  iload   7
   17:  invokestatic    #90; //Method foo_aroundBody0:(LBugExample;LBugExample;I)I
   20:  ireturn
   21:  iconst_0
   22:  ireturn

private static final int foo_aroundBody2(BugExample, BugExample, int);
  Code:
   0:   aload_1
   1:   iload_2
   2:   invokespecial   #26; //Method foo:(I)I
   5:   ireturn

private static final int foo_aroundBody3$advice(BugExample, BugExample, int, BugExample$BugAspect, int, org.aspectj.runtime.internal.AroundClosure);
  Code:
   0:   iload   4
   2:   ifle    21
   5:   iload   4
   7:   aload   5
   9:   astore  6
   11:  istore  7
   13:  aload_0
   14:  aload_1
   15:  iload   7
   17:  invokestatic    #96; //Method foo_aroundBody2:(LBugExample;LBugExample;I)I
   20:  ireturn
   21:  iconst_0
   22:  ireturn

private static final int foo_aroundBody4(BugExample, BugExample, int);
  Code:
   0:   aload_1
   1:   iload_2
   2:   invokespecial   #26; //Method foo:(I)I
   5:   ireturn

private static final int foo_aroundBody5$advice(BugExample, BugExample, int, BugExample$BugAspect, int, org.aspectj.runtime.internal.AroundClosure);
  Code:
   0:   iload   4
   2:   ifle    21
   5:   iload   4
   7:   aload   5
   9:   astore  6
   11:  istore  7
   13:  aload_0
   14:  aload_1
   15:  iload   7
   17:  invokestatic    #102; //Method foo_aroundBody4:(LBugExample;LBugExample;I)I
   20:  ireturn
   21:  iconst_0
   22:  ireturn

private static final int foo_aroundBody6(BugExample, BugExample, int);
  Code:
   0:   aload_1
   1:   iload_2
   2:   invokespecial   #26; //Method foo:(I)I
   5:   ireturn

private static final int foo_aroundBody7$advice(BugExample, BugExample, int, BugExample$BugAspect, int, org.aspectj.runtime.internal.AroundClosure);
  Code:
   0:   iload   4
   2:   ifle    21
   5:   iload   4
   7:   aload   5
   9:   astore  6
   11:  istore  7
   13:  aload_0
   14:  aload_1
   15:  iload   7
   17:  invokestatic    #108; //Method foo_aroundBody6:(LBugExample;LBugExample;I)I
   20:  ireturn
   21:  iconst_0
   22:  ireturn

}
Comment 1 Eduardo Cordeiro CLA 2006-08-17 12:28:50 EDT
I forgot to mention that the javap command was run after compiling the code with ajc1.5.2, provided with AJDT 1.4 for Eclipse 3.2.
Comment 2 Andrew Clement CLA 2006-08-23 10:54:23 EDT
worth a try getting this into 1.5.3
Comment 3 Helen Beeken CLA 2006-11-02 04:34:06 EST
Decompiling the provided testcase with "javap -private -verbose BugExample" shows that the LineNumberTables are different.
Comment 4 Eduardo Cordeiro CLA 2006-11-06 10:57:18 EST
(In reply to comment #3)

Indeed, the LineNumberTables for shadow methods are different, since they refer to  different shadows. So this affects debugging, since the same instruction can't refer to several source-code lines.

Can the repeated methods still be applied if line number information is not generated? (or more specifically, if debug is disabled?)
Comment 5 Andrew Clement CLA 2013-06-24 11:04:22 EDT
unsetting the target field which is currently set for something already released