Erroneous exception conversion and Bugzilla Bug 34206 before():execution(new(..)) does not throw NoAspectBoundException All exceptions that occur during the static intialization of a persingleton aspect will be swallowed. When using that aspect (via aspectOf()) a NoAspectBoundException will be thrown with the original exception from the staitc initializer as the cause.tags/v_preCompileLoopAlteration
@@ -18,12 +18,16 @@ import org.aspectj.weaver.AjcMemberMaker; | |||
import org.eclipse.jdt.internal.compiler.CompilationResult; | |||
import org.eclipse.jdt.internal.compiler.ast.Clinit; | |||
import org.eclipse.jdt.internal.compiler.codegen.CodeStream; | |||
import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; | |||
import org.eclipse.jdt.internal.compiler.codegen.Label; | |||
import org.eclipse.jdt.internal.compiler.lookup.ClassScope; | |||
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; | |||
public class AspectClinit extends Clinit { | |||
private boolean hasPre, hasPost; | |||
private FieldBinding initFailureField; | |||
public AspectClinit(Clinit old, CompilationResult compilationResult, boolean hasPre, boolean hasPost) { | |||
public AspectClinit(Clinit old, CompilationResult compilationResult, boolean hasPre, boolean hasPost, FieldBinding initFailureField) { | |||
super(compilationResult); | |||
this.needFreeReturn = old.needFreeReturn; | |||
this.sourceEnd = old.sourceEnd; | |||
@@ -33,12 +37,19 @@ public class AspectClinit extends Clinit { | |||
this.hasPre = hasPre; | |||
this.hasPost = hasPost; | |||
this.initFailureField = initFailureField; | |||
} | |||
private ExceptionLabel handlerLabel; | |||
protected void generateSyntheticCode( | |||
ClassScope classScope, | |||
CodeStream codeStream) | |||
{ | |||
if (initFailureField != null) { | |||
handlerLabel = new ExceptionLabel(codeStream, classScope.getJavaLangThrowable()); | |||
} | |||
if (hasPre) { | |||
final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope); | |||
@@ -64,6 +75,16 @@ public class AspectClinit extends Clinit { | |||
))); | |||
} | |||
if (initFailureField != null) { | |||
handlerLabel.placeEnd(); | |||
Label endLabel = new Label(codeStream); | |||
codeStream.goto_(endLabel); | |||
handlerLabel.place(); | |||
codeStream.putstatic(initFailureField); | |||
endLabel.place(); | |||
} | |||
} | |||
} |
@@ -151,7 +151,7 @@ public class AspectDeclaration extends TypeDeclaration { | |||
} | |||
} | |||
private FieldBinding initFailureField= null; | |||
public void generateCode(ClassFile enclosingClassFile) { | |||
if (ignoreFurtherInvestigation) { | |||
@@ -170,18 +170,22 @@ public class AspectDeclaration extends TypeDeclaration { | |||
if (!isAbstract()) { | |||
initFailureField = factory.makeFieldBinding(AjcMemberMaker.initFailureCauseField(typeX)); | |||
binding.addField(initFailureField); | |||
if (perClause == null) { | |||
// we've already produced an error for this | |||
} else if (perClause.getKind() == PerClause.SINGLETON) { | |||
binding.addField(factory.makeFieldBinding(AjcMemberMaker.perSingletonField( | |||
typeX))); | |||
methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, false, true); | |||
methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, false, true, initFailureField); | |||
} else if (perClause.getKind() == PerClause.PERCFLOW) { | |||
binding.addField( | |||
factory.makeFieldBinding( | |||
AjcMemberMaker.perCflowField( | |||
typeX))); | |||
methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, true, false); | |||
methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, true, false, null); | |||
} else if (perClause.getKind() == PerClause.PEROBJECT) { | |||
// binding.addField( | |||
// world.makeFieldBinding( | |||
@@ -522,10 +526,13 @@ public class AspectDeclaration extends TypeDeclaration { | |||
codeStream.ifnull(isNull); | |||
codeStream.areturn(); | |||
isNull.place(); | |||
codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION)); | |||
codeStream.dup(); | |||
codeStream.ldc(typeX.getNameAsIdentifier()); | |||
codeStream.getstatic(initFailureField); | |||
codeStream.invokespecial(world.makeMethodBindingForCall( | |||
AjcMemberMaker.noAspectBoundExceptionInit() | |||
AjcMemberMaker.noAspectBoundExceptionInitWithCause() | |||
)); | |||
codeStream.athrow(); | |||
// body ends here |
@@ -18,4 +18,16 @@ package org.aspectj.lang; | |||
* when there is no aspect of that type currently bound. | |||
*/ | |||
public class NoAspectBoundException extends RuntimeException { | |||
Throwable cause; | |||
public NoAspectBoundException(String aspectName, Throwable inner) { | |||
super(inner == null ? aspectName : | |||
"Exception while initializing " +aspectName + ": " +inner); | |||
this.cause = inner; | |||
} | |||
public NoAspectBoundException() { | |||
} | |||
public Throwable getCause() { return cause; } | |||
} |
@@ -14,6 +14,8 @@ | |||
// default package | |||
import org.aspectj.lang.NoAspectBoundException; | |||
import junit.framework.*; | |||
public class RuntimeModuleTests extends TestCase { | |||
@@ -27,4 +29,10 @@ public class RuntimeModuleTests extends TestCase { | |||
public RuntimeModuleTests(String name) { super(name); } | |||
public void testNothing() {} | |||
public void testNoAspectBoundException() { | |||
RuntimeException fun = new RuntimeException("fun"); | |||
NoAspectBoundException nab = new NoAspectBoundException("Foo", fun); | |||
assertEquals(fun,nab.getCause()); | |||
} | |||
} |
@@ -7092,4 +7092,18 @@ | |||
<run class="Main1"/> | |||
</ajc-test> | |||
<ajc-test dir="bugs" pr="44587" | |||
title="Erroneous exception conversion"> | |||
<compile files="ErroneousExceptionConversion.java"> | |||
</compile> | |||
<run class="ErroneousExceptionConversion"/> | |||
</ajc-test> | |||
<ajc-test dir="bugs" pr="34206" | |||
title="before():execution(new(..)) does not throw NoAspectBoundException"> | |||
<compile files="ErroneousExceptionConversion1.java"> | |||
</compile> | |||
<run class="ErroneousExceptionConversion1"/> | |||
</ajc-test> | |||
</suite> |
@@ -0,0 +1,44 @@ | |||
// pr 44587 | |||
import org.aspectj.testing.Tester; | |||
import org.aspectj.lang.NoAspectBoundException; | |||
public class ErroneousExceptionConversion { | |||
public static void main(String[] args) { | |||
try { | |||
new ErroneousExceptionConversion(); | |||
Tester.checkFailed("Wanted an exception in initializer error"); | |||
} catch (NoAspectBoundException nabEx) { | |||
// good | |||
// check nabEx.getCause instanceof RuntimeException and has explanation "boom..." | |||
Throwable cause = nabEx.getCause(); | |||
if (!(cause instanceof RuntimeException)) { | |||
Tester.checkFailed("Should have a RuntimeException as cause"); | |||
} | |||
} catch(Throwable t) { | |||
Tester.checkFailed("Wanted an ExceptionInInitializerError but got " + t); | |||
} | |||
} | |||
} | |||
aspect A { | |||
int ErroneousExceptionConversion.someField = throwIt(); | |||
public static int throwIt() { | |||
throw new RuntimeException("Exception during aspect initialization"); | |||
} | |||
public A() { | |||
System.err.println("boom in 5..."); | |||
throw new RuntimeException("boom"); | |||
} | |||
// if I change this to execution the test passes... | |||
after() throwing : initialization(ErroneousExceptionConversion.new(..)) { | |||
System.out.println("After throwing"); | |||
} | |||
} | |||
@@ -0,0 +1,26 @@ | |||
import org.aspectj.lang.*; | |||
import org.aspectj.testing.Tester; | |||
aspect Watchcall { | |||
pointcut myConstructor(): execution(new(..)); | |||
before(): myConstructor() { | |||
System.err.println("Entering Constructor"); | |||
} | |||
after(): myConstructor() { | |||
System.err.println("Leaving Constructor"); | |||
} | |||
} | |||
public class ErroneousExceptionConversion1 { | |||
public static void main(String[] args) { | |||
try { | |||
ErroneousExceptionConversion1 c = new ErroneousExceptionConversion1(); | |||
Tester.checkFailed("shouldn't get here"); | |||
} catch (NoAspectBoundException nab) { | |||
// expected | |||
} | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
import org.aspectj.testing.*; | |||
import org.aspectj.lang.*; | |||
/** | |||
* -usejavac mode: no error | |||
@@ -8,7 +9,10 @@ public class ConstructorExecInitFails { | |||
public static void main(String[] args) { | |||
try { | |||
new ConstructorExecInitFails(); | |||
} catch (ExceptionInInitializerError e) { | |||
} catch (NoAspectBoundException e) { | |||
Tester.check(e.getCause() instanceof NoAspectBoundException, | |||
"Expected NoAspectBoundException, found " + e.getCause()); | |||
return; | |||
} | |||
Tester.checkFailed("shouldn't be able to run"); |
@@ -15,6 +15,8 @@ package org.aspectj.weaver; | |||
import java.lang.reflect.Modifier; | |||
import org.aspectj.weaver.ResolvedTypeX.Name; | |||
public class AjcMemberMaker { | |||
private static final int PUBLIC_STATIC_FINAL = | |||
@@ -60,14 +62,23 @@ public class AjcMemberMaker { | |||
public static Member noAspectBoundExceptionInit() { | |||
return new ResolvedMember( | |||
Member.METHOD, | |||
NO_ASPECT_BOUND_EXCEPTION, | |||
Modifier.PUBLIC, | |||
"<init>", | |||
"()V"); | |||
Member.METHOD, | |||
NO_ASPECT_BOUND_EXCEPTION, | |||
Modifier.PUBLIC, | |||
"<init>", | |||
"()V"); | |||
} | |||
public static Member noAspectBoundExceptionInitWithCause() { | |||
return new ResolvedMember( | |||
Member.METHOD, | |||
NO_ASPECT_BOUND_EXCEPTION, | |||
Modifier.PUBLIC, | |||
"<init>", | |||
"(Ljava/lang/String;Ljava/lang/Throwable;)V"); | |||
} | |||
public static ResolvedMember perCflowPush(TypeX declaringType) { | |||
return new ResolvedMember( | |||
Member.METHOD, | |||
@@ -95,6 +106,15 @@ public class AjcMemberMaker { | |||
declaringType.getSignature()); | |||
} | |||
public static ResolvedMember initFailureCauseField(TypeX declaringType) { | |||
return new ResolvedMember( | |||
Member.FIELD, | |||
declaringType, | |||
PRIVATE_STATIC, | |||
NameMangler.INITFAILURECAUSE_FIELD_NAME, | |||
TypeX.THROWABLE.getSignature()); | |||
} | |||
public static ResolvedMember perObjectField(TypeX declaringType, ResolvedTypeX aspectType) { | |||
int modifiers = Modifier.PRIVATE; |
@@ -40,8 +40,8 @@ public class NameMangler { | |||
public static final String AJC_POST_CLINIT_NAME = PREFIX + "postClinit"; | |||
public static final String INITFAILURECAUSE_FIELD_NAME = PREFIX + "initFailureCause"; | |||
public static String perObjectInterfaceGet(TypeX aspectType) { | |||
return makeName(aspectType.getNameAsIdentifier(), "perObjectGet"); | |||
} |
@@ -904,6 +904,8 @@ class BcelClassWeaver implements IClassWeaver { | |||
// assert t.getHandler() == ih | |||
ExceptionRange er = (ExceptionRange) t; | |||
if (er.getCatchType() == null) continue; | |||
if (isInitFailureHandler(ih)) return; | |||
match( | |||
BcelShadow.makeExceptionHandler( | |||
world, | |||
@@ -915,6 +917,14 @@ class BcelClassWeaver implements IClassWeaver { | |||
} | |||
} | |||
private boolean isInitFailureHandler(InstructionHandle ih) { | |||
if (ih.getInstruction() instanceof PUTSTATIC) { | |||
String name = ((PUTSTATIC)ih.getInstruction()).getFieldName(cpg); | |||
if (name.equals(NameMangler.INITFAILURECAUSE_FIELD_NAME)) return true; | |||
} | |||
return false; | |||
} | |||
private void matchSetInstruction( | |||
LazyMethodGen mg, | |||
@@ -923,6 +933,10 @@ class BcelClassWeaver implements IClassWeaver { | |||
List shadowAccumulator) { | |||
FieldInstruction fi = (FieldInstruction) ih.getInstruction(); | |||
Member field = BcelWorld.makeFieldSignature(clazz, fi); | |||
// synthetic fields are never join points | |||
if (field.getName().startsWith(NameMangler.PREFIX)) return; | |||
ResolvedMember resolvedField = field.resolve(world); | |||
if (resolvedField == null) { | |||
// we can't find the field, so it's not a join point. | |||
@@ -946,6 +960,10 @@ class BcelClassWeaver implements IClassWeaver { | |||
private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List shadowAccumulator) { | |||
FieldInstruction fi = (FieldInstruction) ih.getInstruction(); | |||
Member field = BcelWorld.makeFieldSignature(clazz, fi); | |||
// synthetic fields are never join points | |||
if (field.getName().startsWith(NameMangler.PREFIX)) return; | |||
ResolvedMember resolvedField = field.resolve(world); | |||
if (resolvedField == null) { | |||
// we can't find the field, so it's not a join point. |