Bug 115251 - BCException when compiling incrementally on constructor-call shadow
Summary: BCException when compiling incrementally on constructor-call shadow
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.0M4   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 1.5.0RC1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-06 21:36 EST by Wes Isberg CLA
Modified: 2012-04-03 16:08 EDT (History)
0 users

See Also:


Attachments
testcase patch (2.62 KB, patch)
2005-11-22 08:21 EST, Helen Beeken CLA
aclement: iplog+
Details | Diff
NPE fix patch (1.06 KB, patch)
2005-11-22 08:23 EST, Helen Beeken CLA
aclement: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Wes Isberg CLA 2005-11-06 21:36:24 EST
I get the same BCException when I build incrementally but not after cleaning the
project.  The code is correct (I think) and runs fine after clean-and-build.

AJDT Build id: 20051104134042
AspectJ version: 1.5.0.200510241400

(Sorry if this is another manifestation of a different bug or an AJDT bug.)

---------------------------------------------------------------
----------------- Singleton.java
package com.isberg.articles.aop7.patterns;

/**
 * CODE article singleton variant without eager/lazy
 */
public abstract aspect Singleton<Target> pertypewithin(Target) {
	private final Object lock = new Object();
	private Target singleton;

	/**
	 * Subaspects define this.  All join points must return type Target.
	 */
	abstract protected pointcut creation();

	pointcut creating() : cflow(within(Singleton+) && adviceexecution());
	
    Target around() : creation() && !creating(){
    	synchronized(lock) {
            if (singleton == null) {
                singleton = proceed();
            }
            return singleton;
    	}
    }
}

----------------- SingletonTest.java
package com.isberg.articles.aop7.patterns;

import junit.framework.TestCase;

public class SingletonTest extends TestCase {
	public void testSingleton() throws Exception {
		C[] cs = {C.create(), new C(), C.create()};
		for (int i = 1; i < cs.length; i++) {
			assertEquals(cs[0], cs[i]);
		}
	}
	static class C {
		static C create() {return new C();}
		C() {}		
	}
	static aspect A extends Singleton<C> {
		protected pointcut creation() : execution(static C C.create())
			|| call(C.new());
	}
}
---------------------------------------------------------------

trouble in:public class com.isberg.articles.aop7.patterns.SingletonTest extends
junit.framework.TestCase:
public void <init>():
ALOAD_0     // com.isberg.articles.aop7.patterns.SingletonTest this   (line 5)
INVOKESPECIAL junit.framework.TestCase.<init> ()V
constructor-execution(void com.isberg.articles.aop7.patterns.SingletonTest.<init>())
|               RETURN
constructor-execution(void com.isberg.articles.aop7.patterns.SingletonTest.<init>())
end public void <init>()
public void testSingleton() throws java.lang.Exception   
org.aspectj.weaver.MethodDeclarationLineNumber: 6:142
:
method-execution(void
com.isberg.articles.aop7.patterns.SingletonTest.testSingleton())
|               ICONST_3   (line 7)
|               ANEWARRAY com.isberg.articles.aop7.patterns.SingletonTest$C
|               DUP
|               ICONST_0
| method-call(com.isberg.articles.aop7.patterns.SingletonTest$C
com.isberg.articles.aop7.patterns.SingletonTest$C.create())
| |             INVOKESTATIC
com.isberg.articles.aop7.patterns.SingletonTest$C.create
()Lcom/isberg/articles/aop7/patterns/SingletonTest$C;
| method-call(com.isberg.articles.aop7.patterns.SingletonTest$C
com.isberg.articles.aop7.patterns.SingletonTest$C.create())
|               AASTORE
|               DUP
|               ICONST_1
| constructor-call(void com.isberg.articles.aop7.patterns.SingletonTest$C.<init>())
| |             NEW com.isberg.articles.aop7.patterns.SingletonTest$C
| |             DUP
| |             INVOKESPECIAL
com.isberg.articles.aop7.patterns.SingletonTest$C.<init> ()V
| constructor-call(void com.isberg.articles.aop7.patterns.SingletonTest$C.<init>())
|               AASTORE
|               DUP
|               ICONST_2
| method-call(com.isberg.articles.aop7.patterns.SingletonTest$C
com.isberg.articles.aop7.patterns.SingletonTest$C.create())
| |             INVOKESTATIC
com.isberg.articles.aop7.patterns.SingletonTest$C.create
()Lcom/isberg/articles/aop7/patterns/SingletonTest$C;
| method-call(com.isberg.articles.aop7.patterns.SingletonTest$C
com.isberg.articles.aop7.patterns.SingletonTest$C.create())
|               AASTORE
|               ASTORE_1
|               ICONST_1   (line 8)
|               ISTORE_2
|               GOTO L1
|           L0: ALOAD_1     //
com.isberg.articles.aop7.patterns.SingletonTest$C[] cs   (line 9)
|               ICONST_0
|               AALOAD
|               ALOAD_1     //
com.isberg.articles.aop7.patterns.SingletonTest$C[] cs
|               ILOAD_2     // int i
|               AALOAD
| method-call(void junit.framework.Assert.assertEquals(java.lang.Object,
java.lang.Object))
| |             INVOKESTATIC
com.isberg.articles.aop7.patterns.SingletonTest.assertEquals
(Ljava/lang/Object;Ljava/lang/Object;)V
| method-call(void junit.framework.Assert.assertEquals(java.lang.Object,
java.lang.Object))
|               IINC 2 1     // int i   (line 8)
|           L1: ILOAD_2     // int i
|               ALOAD_1     //
com.isberg.articles.aop7.patterns.SingletonTest$C[] cs
|               ARRAYLENGTH
|               IF_ICMPLT L0
|               RETURN   (line 11)
method-execution(void
com.isberg.articles.aop7.patterns.SingletonTest.testSingleton())
end public void testSingleton() throws java.lang.Exception
end public class com.isberg.articles.aop7.patterns.SingletonTest
when implementing on shadow constructor-call(void
com.isberg.articles.aop7.patterns.SingletonTest$C.<init>())
when weaving type com.isberg.articles.aop7.patterns.SingletonTest
when weaving classes
when weaving
when incrementally building
BuildConfig[c:\home\ws\main-31\.metadata\.plugins\org.eclipse.ajdt.core\devworks-fall.generated.lst]
#Files=90


org.aspectj.weaver.BCException: Class
com.isberg.articles.aop7.patterns.Singleton does not have a method
ajc$around$com_isberg_articles_aop7_patterns_Singleton$1$51e13820 with signature
(Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object;
when implementing on shadow constructor-call(void
com.isberg.articles.aop7.patterns.SingletonTest$C.<init>())
when weaving type com.isberg.articles.aop7.patterns.SingletonTest
when weaving classes
when weaving
when incrementally building
BuildConfig[c:\home\ws\main-31\.metadata\.plugins\org.eclipse.ajdt.core\devworks-fall.generated.lst]
#Files=90
at org.aspectj.weaver.bcel.LazyClassGen.getLazyMethodGen(LazyClassGen.java:1161)
at org.aspectj.weaver.bcel.LazyClassGen.getLazyMethodGen(LazyClassGen.java:1146)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundInline(BcelShadow.java:1973)
at org.aspectj.weaver.bcel.BcelAdvice.implementOn(BcelAdvice.java:211)
at org.aspectj.weaver.Shadow.implementMungers(Shadow.java:514)
at org.aspectj.weaver.Shadow.implement(Shadow.java:391)
at org.aspectj.weaver.bcel.BcelClassWeaver.implement(BcelClassWeaver.java:1782)
at org.aspectj.weaver.bcel.BcelClassWeaver.weave(BcelClassWeaver.java:394)
at org.aspectj.weaver.bcel.BcelClassWeaver.weave(BcelClassWeaver.java:98)
at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1478)
at org.aspectj.weaver.bcel.BcelWeaver.weaveWithoutDump(BcelWeaver.java:1443)
at org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify(BcelWeaver.java:1217)
at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1039)
at
org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.weave(AjCompilerAdapter.java:300)
at
org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.afterCompiling(AjCompilerAdapter.java:178)
at
org.aspectj.ajdt.internal.compiler.CompilerAdapter.ajc$afterReturning$org_aspectj_ajdt_internal_compiler_CompilerAdapter$2$f9cc9ca0(CompilerAdapter.aj:70)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:367)
at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.performCompilation(AjBuildManager.java:759)
at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.doBuild(AjBuildManager.java:249)
at
org.aspectj.ajdt.internal.core.builder.AjBuildManager.incrementalBuild(AjBuildManager.java:158)
at org.aspectj.ajde.internal.CompilerAdapter.compile(CompilerAdapter.java:117)
at
org.aspectj.ajde.internal.AspectJBuildManager$CompilerThread.run(AspectJBuildManager.java:191)
Comment 1 Andrew Clement CLA 2005-11-07 03:05:27 EST
I better take a look.
Comment 2 Helen Beeken CLA 2005-11-22 08:21:13 EST
Created attachment 30372 [details]
testcase patch

Patch containing failing testcase - apply to the tests project.

The testcase contains the line:

	AjdeInteractionTestbed.VERBOSE=true;

to be used for debugging, but should probably be removed when integrated.

The key things to recreating this bug seemed to be the around advice returning a 'Target' which is the same as used within the aspect declaration.
Comment 3 Helen Beeken CLA 2005-11-22 08:23:51 EST
Created attachment 30373 [details]
NPE fix patch

Apply to the org.aspectj.ajdt.core project.

When you run the test program attached above an NPE occurs before the reported BCException (this has been introduced since the bug was raised since I've run the test program within a workspace containing an old version of aspectj and no NPE was seen). This patch contains a fix for that NPE. With this fix, the previously attached testcase produces the reported BCException.
Comment 4 Adrian Colyer CLA 2005-11-25 04:55:56 EST
This bug is proving to be really hard to track down - here's what I've learnt so far:

"The case of the zombie shadow munger"
==========================

We start off with a full build, and aspect A1 has around advice in it. This cause an around advice shadow munger to be created in the crosscutting member set. 

We change A1 (to delete the around advice) and do an incremental build. This causes us to source compile only A1.java, but to weave everything. The first bug lurking here is that A1 is an abstract aspect extended by A. When we addOrReplaceAspect in the CrosscuttingMembersSet, if the aspect is abstract we also need to refresh the crosscutting members of any subaspects of it we have defined - because crosscutting members are aggregated in concrete subaspects from abstract super aspects. This part of the fix is in and working. When we do this, the around advice shadow munger is no longer present (correct).

We come back to the incremental compilation loop, and the references tell us that we need to recompile C1.java too (because in that file is a subtype of A1 that we just rebuilt). So we do an incremental compile of C1.java, which triggers a full weave again (C1.java contains the definition of concrete aspect A). But this time, when we get all of the shadow mungers for the crosscutting members set, the around advice shadow munger has come back from the dead! In particular, when we ask the reference type for A1 for it shadowMungers, it returns the around advice munger.

Well, it's all downhill from here. We do matching, see that the around advice munger matches, and try to inline a call to the advice method that the munger specifies - but that method doesn't exist anymore, and bang!. 

So the question is.... why does the around shadowMunger come back from the dead, having correctly disappeared in the first incremental compilation round? ??
Comment 5 Adrian Colyer CLA 2005-11-25 06:46:58 EST
"The case of the zombie shadow munger, part 2"

OK, there were two more layered problems here. Firstly, generic reference types need to remember all of their derivative types, so that if the delegate of the generic type is updated, the delegates of the derivative (raw and parameterized) types get updated too. This is mostly an issue during incremental compilation when delegates get updated after an increment.

Second issue was that EclipseFactory was sometimes creating new Reference types for generic types when the world already had one. This leads to multiple versions kicking around and trouble later on.

Both of these are now fixed, and this test case passes, but several other tests in the suite are broken so we're not out of the woods yet...

Comment 6 Adrian Colyer CLA 2005-11-25 11:20:24 EST
The final hurdle.

It turns out that cflow is a bit of a mess. The change to add-or-replace sub-aspects when adding-or-replacing an abstract super aspect breaks an assumption in CflowPointcut.concretize1 that adds special shadow and type mungers to the crosscutting member set of a concrete aspect. If you ask for the crosscutting member set more than once, you don't get the members second time round. After several more hours looking at the options, I backed out this part of the change. It should probably be re-enabled post 1.5.0 when we can reconsider the cflow design at our leisure. Breaking backwards compatibility with 1.2.1 is one of the issues I ran into. The part of the change that is backed out is actually not necessary to make this case pass :- the order of adding aspects to the member set seems to nearly always work out so that my safeguard was just that. I'd just like to be 100% certain about it rather than saying "it seems to (nearly?) always work out". ...!
Comment 7 Adrian Colyer CLA 2005-11-25 12:40:42 EST
fixes checked into cvs - first green bar in a long time it feels like! waiting on build.....
Comment 8 Adrian Colyer CLA 2005-11-25 14:19:53 EST
fix available