Bug 233032 - bridge methods created when not required?
Summary: bridge methods created when not required?
Status: RESOLVED WONTFIX
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.6.0   Edit
Hardware: PC Windows Vista
: P3 normal with 1 vote (vote)
Target Milestone: 1.6.4   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-05-20 14:37 EDT by Andrew Clement CLA
Modified: 2009-02-17 17:12 EST (History)
1 user (show)

See Also:


Attachments
test maven project demonstrating the issue (50.35 KB, application/x-gzip)
2009-02-13 00:28 EST, Jacques CLA
no flags Details
test maven project demonstrating the issue (50.42 KB, application/x-gzip)
2009-02-13 01:55 EST, Jacques CLA
no flags Details
test maven project demonstrating the issue (55.29 KB, application/x-zip)
2009-02-16 14:25 EST, Jacques CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Clement CLA 2008-05-20 14:37:56 EDT
See discussion in bug 232712 about:

1. Annotation style leading us to add bridge methods when code style does not
2. Bridge methods being added when not necessary as the compiler already did it
Comment 1 Andrew Clement CLA 2008-10-29 15:01:19 EDT
no simple testcase available right now - deferring this until it proves to be an issue
Comment 2 Jacques CLA 2009-02-13 00:28:08 EST
Created attachment 125606 [details]
test maven project demonstrating the issue

I believe I have a test case for you :-)
See attached maven project. Run mvn clean test. All 6 tests will fail.
This is the output (target/surefire-reports/TestSuite.txt) of the first test:

testCallToFindIsProtected(com.sabre.util.regex.MatcherContrainingAspectTest)  Time elapsed: 0.013 sec  <<< FAILURE!
java.lang.ClassFormatError: Duplicate method name&signature in class file com/sabre/util/regex/MatcherExecutionConstrainingAspect
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
        at com.sabre.util.regex.Matcher.reset(Matcher.java)
        at com.sabre.util.regex.Matcher.<init>(Matcher.java:212)
        at com.sabre.util.regex.Pattern.matcher(Pattern.java:875)
        at com.sabre.util.regex.MatcherContrainingAspectTest.testCallToFindIsProtected(MatcherContrainingAspectTest.java:50)
Comment 3 Jacques CLA 2009-02-13 01:55:08 EST
Created attachment 125609 [details]
test maven project demonstrating the issue

This is basically the same testcase as before cleaned up and with an identical aj aspect that works to speed up diagnosis.
Comment 4 Andrew Clement CLA 2009-02-16 13:09:48 EST
downloaded that, run 
mvn clean test

got:
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.

Missing:
----------
1) com.sabre.liberty.commons:testng-libs:pom:1.0-SNAPSHOT
  Path to dependency:
        1) com.sabre.liberty.commons:saferegex:jar:1.6.1
        2) com.sabre.liberty.commons:testng-libs:pom:1.0-SNAPSHOT

----------
1 required artifact is missing.

for artifact:
  com.sabre.liberty.commons:saferegex:jar:1.6.1

from the specified remote repositories:
  public-snapshots (http://public-snapshots),
  public (http://public),
  central (http://repo1.maven.org/maven2)
Comment 5 Andrew Clement CLA 2009-02-16 13:28:51 EST
moved it all into an eclipse project, now just complaining about:

        2) com.sabre.liberty.commons:testng-libs:pom:1.0-SNAPSHOT
Comment 6 Jacques CLA 2009-02-16 14:25:40 EST
Created attachment 125809 [details]
 test maven project demonstrating the issue 

Sorry for the pom not cleaned up. I thought help:effective-pom would do that.
I have cleaned it up and tested it can build w/ no other dependencies.
Comment 7 Andrew Clement CLA 2009-02-16 19:43:56 EST
Still not working for me, this time on mvn clean test:

...
[INFO] Using default encoding to copy filtered resources.
Downloading: http://repo1.maven.org/maven2/org/testng/testng/5.8/testng-5.8.jar
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed to resolve artifact.

Missing:
----------
1) org.testng:testng:jar:5.8

I haven't got the first clue about maven so sorry if I'm not trying something obvious.
Comment 8 Andrew Clement CLA 2009-02-16 19:49:18 EST
alright I've manually downloaded it and installed it in my repo to satisfy this pom and have recreated the problem.  Now to untangle it from maven and actually run it normally so i can debug it.
Comment 9 Andrew Clement CLA 2009-02-16 20:34:22 EST
Right, I've unpicked all that, phew.  Here is a failing test program with the same error:

--- A.java ---
import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;

@Aspect("percflow(within(C))")
public class A {

  @Before("execution(* foo(..)) && cflow(execution(* bar(..)) && this(o))")
  public void m(Object o) {}

  public static void main(String[] argv) {
    new C().bar();
  }

}

class C {
  public void bar() {
    foo();
  }
  public void foo() {}
}
--- A.java ---

ajc -1.5 A.java
java A
Exception in thread "main" java.lang.ClassFormatError: Duplicate method name&signature in class file A
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)

Here are the methods in A:

 public A();
 public static A aspectOf();
 public static boolean hasAspect();
 public static final org.aspectj.runtime.internal.CFlowStack ajc$cflowStack$1;
 public static final org.aspectj.runtime.internal.CFlowStack ajc$perCflowStack;
 public static void ajc$perCflowPush();
 public static void main(java.lang.String[]);
 public void m(java.lang.Object);
 static {};
 static void ajc$preClinit();
 private static void ajc$preClinit();

There are two ajc$preClinit methods.  So this bug is not related to bridge method creation unfortunately, but it is still serious.  I believe it is the cflow combinations that cause it.
Comment 10 Andrew Clement CLA 2009-02-16 20:52:03 EST
as the problem we are discovering is not related to bridge methods I have opened bug 265072 to cover the actual problem of double preClinit methods.
Comment 11 Jacques CLA 2009-02-16 21:43:01 EST
(In reply to comment #10)
> as the problem we are discovering is not related to bridge methods I have
> opened bug 265072 to cover the actual problem of double preClinit methods.
> 

(In reply to comment #10)
> as the problem we are discovering is not related to bridge methods I have
> opened bug 265072 to cover the actual problem of double preClinit methods.
> 

Sorry for being such trouble. Thanks for sorting it out.
Comment 12 Andrew Clement CLA 2009-02-17 00:58:33 EST
No problem Jacques - thanks for coming up with the testcase and helping me get it recreated - it was a serious bug !
Comment 13 Andrew Clement CLA 2009-02-17 17:12:29 EST
Here is an example of what the bug is really about:
--A.java--

public class A implements Cloneable {
  public A clone() {
    return new A();
  }
}

 class B extends A {

  public B clone() {
    return new B();
  }
}
--A.java--

javac A.java

javap -private A
public class A extends java.lang.Object implements java.lang.Cloneable{
    public A();
    public A clone();
    public java.lang.Object clone() throws CloneNotSupportedException;
}

javap -private B
class B extends A{
    B();
    public B clone();
    public A clone();
    public java.lang.Object clone() throws CloneNotSupportedException;
}

Notice the bridge from 'Object clone()' in both classes.  Now paste it into an Eclipse project (not an AJ one) and let JDT compile it:

javap -private A
public class A extends java.lang.Object implements java.lang.Cloneable{
    public A();
    public A clone();
    public java.lang.Object clone() throws CloneNotSupportedException;
}

javap -private B
class B extends A{
    B();
    public B clone();
    public A clone();
}

Notice that there is no 'Object clone()' bridge method in B now.

Now the AspectJ bridge building code in the bcel weaver is behaving like javac.  This means when the JDT compiler chooses not to add a bridge method, we will add it during weaving  *if* that type is opened for bridge analysis.  Bridge analysis is triggered by: the weaver being in 1.5 mode, the type is not an interface and the type has intertype declarations upon it.

Due to the differing implementations of annotation and code style, it is occasionally necessary to 'under the covers' implement a language feature via an internal itd.  This means a type may be affected by itds even though there is nothing apparent in the source code.

I don't plan to address this now - I can't immediately see how it will cause any problems.  It is just a possible future optimization - so resolving WONTFIX until someone shows me a failing scenario ;)