Bug 237419 - Generics and @Around aspects corrupt class file format
Summary: Generics and @Around aspects corrupt class file format
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: DEVELOPMENT   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 1.6.1   Edit
Assignee: AJDT-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-06-16 23:58 EDT by Alex CLA
Modified: 2008-06-17 14:14 EDT (History)
1 user (show)

See Also:


Attachments
Project demonstrating the bug (106.13 KB, application/octet-stream)
2008-06-16 23:58 EDT, Alex CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alex CLA 2008-06-16 23:58:13 EDT
Created attachment 105126 [details]
Project demonstrating the bug

Build ID: M20080221-1800

Steps To Reproduce:
Use the attached project for demonstration.
Before running SpecificService you need to clean the project and have the project to be rebuilt.



More information:
The class file seams to be corrupted only when a full build runs. Incremental compilation seems to be fixing the generated class file. So, if you make a change in SpecificService after a full build, then the problem goes away, but it returns if you clean the project again.
Comment 1 Alex CLA 2008-06-16 23:59:45 EDT
The stack trace generated when running SpecificServer as an application is:
java.lang.ClassFormatError: Duplicate method name&signature in class file problem/SpecificService
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
	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:306)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
Exception in thread "main"
Comment 2 Alex CLA 2008-06-17 00:01:00 EDT
I don't know if relevant, but the project is set to "Build Automatically".
Comment 3 Alex CLA 2008-06-17 00:14:52 EDT
Building the project outside eclipse with AspectJ 1.6.0 and JDK 1.6.0_02 don't cause the problem. Following are the different generated bytecodes:

In eclipse:

// Compiled from SpecificService.java (version 1.6 : 50.0, super bit)
// Signature: Lproblem/GenericService<Lproblem/Specific;>;
public class problem.SpecificService extends problem.GenericService {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public SpecificService();
    0  aload_0 [this]
    1  invokespecial problem.GenericService() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: problem.SpecificService
  
  // Method descriptor #15 (Lproblem/Specific;)Lproblem/Specific;
  // Stack: 1, Locals: 2
  protected problem.Specific update(problem.Specific current);
    0  aconst_null
    1  areturn
      Line numbers:
        [pc: 0, line: 6]
      Local variable table:
        [pc: 0, pc: 2] local: this index: 0 type: problem.SpecificService
        [pc: 0, pc: 2] local: current index: 1 type: problem.Specific
  
  // Method descriptor #20 ([Ljava/lang/String;)V
  // Stack: 1, Locals: 1
  public static void main(java.lang.String[] args);
    0  new problem.SpecificService [1]
    3  invokespecial problem.SpecificService() [21]
    6  return
      Line numbers:
        [pc: 0, line: 10]
        [pc: 6, line: 11]
      Local variable table:
        [pc: 0, pc: 7] local: args index: 0 type: java.lang.String[]
  
  // Method descriptor #24 (Lproblem/Generic;)Lproblem/Generic;
  // Stack: 2, Locals: 2
  protected bridge synthetic problem.Generic update(problem.Generic arg0);
     0  aload_0
     1  aload_1
     2  checkcast problem.Specific [25]
     5  invokevirtual problem.SpecificService.update(problem.Specific) : problem.Specific [27]
     8  checkcast problem.Generic [29]
    11  areturn
      Line numbers:
        [pc: 0, line: 1]
  
  // Method descriptor #24 (Lproblem/Generic;)Lproblem/Generic;
  // Stack: 2, Locals: 2
  protected bridge problem.Generic update(problem.Generic arg0);
    0  aload_0
    1  aload_1
    2  checkcast problem.Specific [25]
    5  invokevirtual problem.SpecificService.update(problem.Specific) : problem.Specific [27]
    8  areturn
      Line numbers:
        [pc: 0, line: 1]

}


Outside:

// Compiled from SpecificService.java (version 1.6 : 50.0, super bit)
// Signature: Lproblem/GenericService<Lproblem/Specific;>;
public class problem.SpecificService extends problem.GenericService {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public SpecificService();
    0  aload_0 [this]
    1  invokespecial problem.GenericService() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: problem.SpecificService
  
  // Method descriptor #15 (Lproblem/Specific;)Lproblem/Specific;
  // Stack: 1, Locals: 2
  protected problem.Specific update(problem.Specific current);
    0  aconst_null
    1  areturn
      Line numbers:
        [pc: 0, line: 6]
      Local variable table:
        [pc: 0, pc: 2] local: this index: 0 type: problem.SpecificService
        [pc: 0, pc: 2] local: current index: 1 type: problem.Specific
  
  // Method descriptor #20 ([Ljava/lang/String;)V
  // Stack: 1, Locals: 1
  public static void main(java.lang.String[] args);
    0  new problem.SpecificService [1]
    3  invokespecial problem.SpecificService() [21]
    6  return
      Line numbers:
        [pc: 0, line: 10]
        [pc: 6, line: 11]
      Local variable table:
        [pc: 0, pc: 7] local: args index: 0 type: java.lang.String[]
  
  // Method descriptor #24 (Lproblem/Generic;)Lproblem/Generic;
  // Stack: 2, Locals: 2
  protected bridge synthetic problem.Generic update(problem.Generic arg0);
     0  aload_0
     1  aload_1
     2  checkcast problem.Specific [25]
     5  invokevirtual problem.SpecificService.update(problem.Specific) : problem.Specific [27]
     8  checkcast problem.Generic [29]
    11  areturn
      Line numbers:
        [pc: 0, line: 1]
}
Comment 4 Andrew Clement CLA 2008-06-17 00:34:43 EDT
I fixed two aspectj bugs last week relating to this problem of duplicate name and signature.  Please can you update to a dev build of AJDT 1.5.3 and retry.  The latest dev build was today, the update site is:

http://download.eclipse.org/tools/ajdt/33/dev/update

AJDT 1.5.3 includes AspectJ1.6.1 dev builds.
Comment 5 Alex CLA 2008-06-17 01:19:20 EDT
(In reply to comment #4)
> I fixed two aspectj bugs last week relating to this problem of duplicate name
> and signature.  Please can you update to a dev build of AJDT 1.5.3 and retry. 
> The latest dev build was today, the update site is:
> 
> http://download.eclipse.org/tools/ajdt/33/dev/update
> 
> AJDT 1.5.3 includes AspectJ1.6.1 dev builds.
> 

I did installed the latest from the update site, but my project is still failing in the same way.
Comment 6 Andrew Clement CLA 2008-06-17 14:13:39 EDT
I was confused that I couldn't recreate this on the command line since it is the same compiler as in AJDT.  Then I figured out it was an ordering problem and related to pipeline compilation.  This produces the broken .class on the command line:

ajc -1.5 problem\aspect\AnyAspect.java problem\SpecificService.java problem\Specific.java problem\GenericService.java problem\Generic.java 

Two bugs here though:
1 why does the signature generator code in BcelWeaver created the duplicate
2 why does the signature generator code get called when the aspect doesn't do anything!

Problem (1) is due to the pipeline and that we are dealing with an EclipseResolvedMember in the signature generator code.  It is not returning an erased form of the signature on getSignature() like the equivalent Bcel variants.  I've added a new 'getSignatureErased()' method to the member hierarchy that now always returns the right thing.  The code now compiles and runs OK.

Problem (2) is due to it being an annotation style aspect, it doesn't happen for code style.  The BcelTypeMunger created for the PerClause is added to the SpecificService type.

This is because of this code in BcelPerClauseAspectAdder

    public boolean matches(ResolvedType onType) {
        //we cannot return onType.equals(aspectType)
        //since we need to eagerly create the nested ajcMighHaveAspect interface on LTW
        //return aspectType.equals(onType);
        return true;
    }

so all types get it attached.  But only certain perclauses can lead to us needing to generate ajcMightHaveAspect marker interfaces, so a huge optimization here for annotation style is to check the pertype and do an optimal check if we can (aspectType.equals(onType)).  This works ;)

So both bugs addressed, fixes committed.  thanks for the test program.
Comment 7 Andrew Clement CLA 2008-06-17 14:14:21 EDT
i'll put it into AJDT later today.