Bug 92837 - [inc-compilation] Incremental Compilation Fails for ITD's on Aspects
Summary: [inc-compilation] Incremental Compilation Fails for ITD's on Aspects
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.0M3   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.5.0 M4   Edit
Assignee: Andrew Clement CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-04-26 17:48 EDT by Ron Bodkin CLA
Modified: 2005-10-28 08:03 EDT (History)
2 users (show)

See Also:


Attachments
Ajc compiled output that chokes the weaver... (16.16 KB, application/java)
2005-04-27 15:01 EDT, Ron Bodkin CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ron Bodkin CLA 2005-04-26 17:48:55 EDT
On my project, when I save an aspect that calls an inter-type declaration 
defined on itself, the incremental compiler gives a message like this:
The method logError(String, Exception) is undefined for the type Foo Foo.java

Running a full build clears the error.

This might be a compiler bug, or it might be AJDT (I never run command-line 
incremental compilation, so I don't know :-)).

Unfortunately, simple test cases or extracts of just the 2 aspects aren't 
reproducing the issue, so let me know if you need me to spend some time trying 
to create a small isolated version of the issue.
Comment 1 Andrew Clement CLA 2005-04-27 11:43:33 EDT
Hi Ron - it is an AspectJ bug and I'm really keen to resolve errors in this
space - based on your description I tried to recreate the problem but I can't
seem to get it to fail.  If you have time to look into it, I will fix it...

In my attempt, I created two aspects:
X.aj
----
public aspect X {
  before(): call(* *(..)) && !within(X) {
    Y.log();
  }
}

Y.aj
----
public aspect Y {
  public void X.log() {}
}

---------
initially that advice doesn't exist in X and I build the system, then I change X
to include it and do an incremental build - it doesn't fail :(  But it's
something very similar to that scenario that does fail.

I think it only happens if you perform a sequence of saves and I believe ITDs
have to be in the mix - but that's all I've managed to work out so far :(
 Any other constructs in your aspects?  inlinable around advice? declares?
Comment 2 Ron Bodkin CLA 2005-04-27 13:49:54 EDT
Andy, I was able to create the following small test case. Each of these types 
lives in its own source file. If you incrementally compile AbstractDerived, it 
fails. If you do a full rebuild it works...

package sample;

public abstract aspect AbstractBase {
	protected Holder member;
}

package sample;

public abstract aspect AbstractDerived extends AbstractBase {
    Object x = getLogger();
}

package sample;

public interface Holder {

}

package sample;

public aspect Logging {
	declare parents: sample.* && !Logging implements Loggable;
	public interface Loggable {}
	public Object Loggable.getLogger() { return null; }
}

Another interesting problem I ran into while weaving the same logging aspect 
using the AJ5 load-time weaving support was:

java.lang.NegativeArraySizeException
	at org.aspectj.weaver.patterns.TypePatternList.read
(TypePatternList.java:476)
	at org.aspectj.weaver.patterns.DeclareParents.read
(DeclareParents.java:90)
	at org.aspectj.weaver.patterns.Declare.read(Declare.java:35)
	at org.aspectj.weaver.AjAttribute.read(AjAttribute.java:107)
	at org.aspectj.weaver.bcel.BcelAttributes.readAjAttributes
(BcelAttributes.java:42)
	at org.aspectj.weaver.bcel.BcelObjectType.unpackAspectAttributes
(BcelObjectType.java:191)
	at org.aspectj.weaver.bcel.BcelObjectType.<init>
(BcelObjectType.java:98)
	at org.aspectj.weaver.bcel.BcelWorld.makeBcelObjectType
(BcelWorld.java:239)
	at org.aspectj.weaver.bcel.BcelWorld.resolveObjectType
(BcelWorld.java:234)
	at org.aspectj.weaver.World.resolveObjectType(World.java:151)
	at org.aspectj.weaver.World.resolve(World.java:130)
	at org.aspectj.weaver.World.resolve(World.java:109)
	at org.aspectj.weaver.World.resolve(World.java:147)
	at org.aspectj.weaver.tools.WeavingAdaptor.shouldWeaveAspect
(WeavingAdaptor.java:206)
	at org.aspectj.weaver.tools.WeavingAdaptor.shouldWeave
(WeavingAdaptor.java:185)
	at org.aspectj.weaver.tools.WeavingAdaptor.weaveClass
(WeavingAdaptor.java:176)
	at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:74)
	at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform
(ClassPreProcessorAgentAdapter.java:54)
	at sun.instrument.TransformerManager.transform
(TransformerManager.java:122)
...

This might have something to do with incompatibility between the loadtime5 
branch and the AJDT milestone build that I'm using, but they are from the same 
epoch and generally work together, so it might not. Any idea why in the 
debugger it shows a length of -768?
Comment 3 Ron Bodkin CLA 2005-04-27 15:01:33 EDT
Created attachment 20417 [details]
Ajc compiled output that chokes the weaver...

Here is the class file that is causing the weaver to choke. This may or may not
be related to the original bug, but it's also an issue that we need to fix...

I stepped through the weaving in the debugger and it is able to parse the type
pattern but then chokes immediately when parsing the type pattern list.

javap -v gives the following output, which shows the negative numbers:
Compiled from "Logging.java"
public class com.crankj.util.logging.Logging extends java.lang.Object
implements
 com.crankj.util.logging.Logging$Loggable
  SourceFile: "Logging.java"
  InnerClass:
   public abstract #140= #64 of #2; //Loggable=class
com/crankj/util/logging/Log
ging$Loggable of class com/crankj/util/logging/Logging
  org.aspectj.weaver.Declare: length = 0x19C
   02 08 01 01 00 04 00 03 63 6F 6D 00 06 63 72 61
   6E 6B 6A 00 00 00 01 2A 00 00 00 00 00 00 00 00
   00 00 00 00 00 05 00 20 63 6F 6D 2E 63 72 61 6E
   6B 6A 2E 75 74 69 6C 2E 6C 6F 67 67 69 6E 67 2E
   4C 6F 67 67 69 6E 67 24 00 11 6A 61 76 61 2E 6C
   61 6E 67 2E 4F 62 6A 65 63 74 24 00 18 63 6F 6D
   2E 63 72 61 6E 6B 6A 2E 75 74 69 6C 2E 6C 6F 67
   67 69 6E 67 2E 00 0A 6A 61 76 61 2E 6C 61 6E 67
   2E 00 11 6F 72 67 2E 61 70 61 63 68 65 2E 6C 6F
   67 34 6A 2E 00 00 00 FFFFFFDB 00 00 00 FFFFFFE7 07 06 01 01
   00 06 00 03 63 6F 6D 00 06 63 72 61 6E 6B 6A 00
   00 00 03 61 70 69 00 00 00 01 2A 00 00 00 00 00
   00 00 00 00 00 00 00 00 05 00 20 63 6F 6D 2E 63
   72 61 6E 6B 6A 2E 75 74 69 6C 2E 6C 6F 67 67 69
   6E 67 2E 4C 6F 67 67 69 6E 67 24 00 11 6A 61 76
   61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 24 00 18
   63 6F 6D 2E 63 72 61 6E 6B 6A 2E 75 74 69 6C 2E
   6C 6F 67 67 69 6E 67 2E 00 0A 6A 61 76 61 2E 6C
   61 6E 67 2E 00 11 6F 72 67 2E 61 70 61 63 68 65
   2E 6C 6F 67 34 6A 2E 00 00 00 FFFFFFEC 00 00 00 FFFFFFFD 07
   07 00 00 00 FFFFFFEC 00 00 00 FFFFFFFD 00 00 00 FFFFFFDB 00 00 00
   FFFFFFFD 00 01 02 01 00 2A 4C 63 6F 6D 2F 63 72 61 6E
   6B 6A 2F 75 74 69 6C 2F 6C 6F 67 67 69 6E 67 2F
   4C 6F 67 67 69 6E 67 24 4C 6F 67 67 61 62 6C 65
   3B 00 00 07 00 00 01 0A 00 00 01 11 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
   FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00 00 00 FFFFFFCA 00 00 01 11

When I try to recompile the file using -inpath I get:
illegal change to pointcut declaration:
topLevelRequest(BindingTypePattern(javax
.servlet.http.HttpServlet, 0))
illegal change to pointcut declaration:
topLevelRequest(BindingTypePattern(javax
.servlet.http.HttpServlet, 0))
org.aspectj.weaver.BCException: illegal change to pointcut declaration:
topLevel
Request(BindingTypePattern(javax.servlet.http.HttpServlet, 0))
	at
org.aspectj.weaver.patterns.ReferencePointcut.concretize1(ReferencePo
intcut.java:275)
	at org.aspectj.weaver.patterns.Pointcut.concretize(Pointcut.java:255)
	at org.aspectj.weaver.patterns.Pointcut.concretize(Pointcut.java:242)
	at org.aspectj.weaver.Advice.concretize(Advice.java:233)
	at
org.aspectj.weaver.CrosscuttingMembers.addShadowMunger(CrosscuttingMe
mbers.java:83)
	at
org.aspectj.weaver.CrosscuttingMembers.addShadowMungers(CrosscuttingM
embers.java:77)
	at
org.aspectj.weaver.ResolvedTypeX.collectCrosscuttingMembers(ResolvedT
ypeX.java:415)
	at
org.aspectj.weaver.CrosscuttingMembersSet.addOrReplaceAspect(Crosscut
tingMembersSet.java:56)
	at
org.aspectj.weaver.bcel.BcelWeaver.prepareForWeave(BcelWeaver.java:37
9)
	at
org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.weave(AjCompiler
Adapter.java:227)
	at
org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.afterCompiling(A
jCompilerAdapter.java:119)
	at
org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compil
er.java:385)
	at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.performCompilat
ion(AjBuildManager.java:683)
	at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.doBuild(AjBuild
Manager.java:168)
	at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBu
ildManager.java:102)
	at org.aspectj.ajdt.ajc.AjdtCommand.doCommand(AjdtCommand.java:109)
	at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:60)
	at org.aspectj.tools.ajc.Main.run(Main.java:291)
	at org.aspectj.tools.ajc.Main.runMain(Main.java:227)
	at org.aspectj.tools.ajc.Main.main(Main.java:80)


1 fail|abort, 2 errors

The source file that generates this looks like this:
package com.crankj.util.logging;

import org.apache.log4j.*;

public aspect Logging pertypewithin(Loggable) {
	private Logger logger;
	// don't put logging into the public API...
	declare parents: com.crankj..* &&!com.crankj..api..* implements
Loggable;

	before() : staticinitialization(*) {
		 logger =
Logger.getLogger(thisJoinPointStaticPart.getSignature().getDeclaringType());
	}
	public interface Loggable {}
	
	public void Loggable.logError(String message) {
		getLogger().error(message);
	}
	public void Loggable.logError(String message, Throwable throwable) {
		getLogger().error(message, throwable);
	}
	public Logger Loggable.getLogger() {
		return null;
	}
	
	// bizarre: need to advise yourself to get access to the instance
associated with the ITD
	Logger around() : call(* Logging.getLogger()) {
		return logger;
	}
}
Comment 4 Andrew Clement CLA 2005-04-28 03:12:58 EDT
Thanks for the example program Ron, I'll try that.  I'm a little nervous about
you working off the branch as that is very old now - as you are so keen on the
LTW changes in it, we could think about moving them down into the base sooner
rather than later.  hmmm.  Some of your problems really could be related to
using a new AJDT and the branch for LTWing.  
Comment 5 Andrew Clement CLA 2005-05-03 05:41:33 EDT
investigate for M3
Comment 6 Andrew Clement CLA 2005-06-13 08:52:17 EDT
Reached crunch time, now concentrating on just getting generics going for M3.
Incremental problems are moving post M3
Comment 7 Vincent Jorrand CLA 2005-08-29 10:06:36 EDT
I have also encountered this problem (the incremental compilation part).
Here is a minimal case to reproduce it. The interface and aspect each live in
their own file. Each time I save the aspect file, the error appears and a clean
is required to get rid of it.

public interface Foo {
}

import java.util.ArrayList;
import java.util.List;
public aspect Bar {
    private List<String> Foo.l;

    private void Foo.foo() {
        l = new ArrayList<String>();
    }
}
Comment 8 Matt Chapman CLA 2005-09-09 11:26:06 EDT
From Ron DiFrango on the mailing list, here is another case of the same
incremental bug, or a related one:

Matt,

As you point out, these are hard to re-produce.  Maybe the steps [which is a
combination of my previous two posts] that I used is as follows:

Created the following aspect:

package com.tascon.tim.sofia.aop;

import com.salmonllc.jsp.JspTableRow;

public aspect SofiaJspTableRow {
   pointcut generateHtml(JspTableRow row) :
       execution(public void JspTableRow.generateHTML(..))
       && target(row);

   void around(JspTableRow row) throws java.io.IOException :
generateHtml(row)
   {
       System.out.println("Executing my aspect now.");
       proceed(row);
   }
}

Performed an incremental compile [and deploy it to my App Server], then I
modified that same aspect so that it resulted in the following;

package com.tascon.tim.sofia.aop;

public aspect SofiaJspTableRow {
private DataStoreEvaluator JspTableRow._dsEval = null;

/**
* Use this method to bind this component to an expression in a
DataStore
* @param ds The DataStore to bind to.
* @param expression The expression to bind to.
* @see DataStoreEvaluator
*/
public void JspTableRow.setExpression(DataStoreBuffer ds,
DataStoreExpression expression) throws Exception {
// RRD: Error on this line because it can not see _dsEval
this._dsEval = new DataStoreEvaluator(ds, expression);
// RRD: Error on this line because it can not see _dsEval
}

pointcut generateHtml(JspTableRow row) :
execution(public void JspTableRow.generateHTML(..))
&& target(row);

void around(JspTableRow row) throws java.io.IOException :
generateHtml(row)
{

// RRD: Error on this line because it can not see _dsEval

if (row._dsEval != null)
{
System.out.println("row._dsEval is NOT NULL.");
}
else
{
System.out.println("row._dsEval is null.");
}
proceed(row);
}
}

Then, I attempted to perform another incremental compile with a call to this new
method from another class and I got an error and could not compile until I did
the full re-build.

Also, this maybe of important note, these aspects affect only classes in a
binary jar that I am weaving into.

Ron
Comment 9 Andrew Clement CLA 2005-09-13 15:43:46 EDT
I think this is related to a bug I raised of my own, bug 108099.  I plan to
start work on it tomorrow... using all the nice examples in here as testcases :)
Comment 10 Andrew Clement CLA 2005-10-05 10:15:17 EDT
I hate incremental bugs.

I managed to get Ron Bodkins scenario from comment #2 failing reliably in the AJ
test harness.  After some effort debugging it turns out to be exactly the same
problem as I covered in bug 85132.  The problem is that when AbstractDerived is
saved for the second time, we have lost the declare parents information that
AbstractBase implements Loggable - so we never discover the ITD on Loggable -
and compilation fails.

I'm trying to decide how much of a leap it is to conclude that incremental
compilation of ITDs only goes wrong when used with declare parents...  does
everyone use declare parents with ITDs?  This might certainly explain why I've
had so much trouble recreating the problem.  Ron DiFrangos program below doesn't
appear to include any declare parents - but he is binary weaving ITDs into a jar
which I think could be something else.

Considering that we didn't have a problem for a while and that it suddenly got
worse, I wonder if that coincided with the binary weaving declare parents work I
did.  Until I'd implemented binary decp we always modified the parents
permanently - so in the example above, AbstractBase will always implement
Loggable, even on the 2nd compile.  I've been talking about the fix for this
problem under bug 85132.

Comment 11 Andrew Clement CLA 2005-10-06 10:28:04 EDT
Fixed!  See bug 85132.  I'm raising comment #7 as a new bug since its generics
related (bug 111779). waiting on build before closing.  Ron (Bodkin), thanks so
much for your test program!
Comment 12 Adrian Colyer CLA 2005-10-28 08:03:10 EDT
fixed as per andy's last comment