From cdddd38d261f0ae75bf95f0859e7a440be1bb3d5 Mon Sep 17 00:00:00 2001 From: avasseur Date: Mon, 2 May 2005 08:17:36 +0000 Subject: [PATCH] PTW perClause for @AJ + perClause test --- runtime/src/org/aspectj/lang/Aspects.java | 112 +++++++- .../ataspectj/ataspectj/BindingTest.java | 14 +- .../ataspectj/ataspectj/PerClauseTest.java | 162 +++++++++++- .../ajc150/ataspectj/atajc150-tests.xml | 208 --------------- .../systemtest/ajc150/ataspectj/atajc150.xml | 12 - .../systemtest/ajc150/ataspectj/syntax.xml | 8 + .../tools/AjdeInteractionTestbed.java | 10 +- .../org/aspectj/weaver/AjcMemberMaker.java | 27 +- .../weaver/bcel/BcelPerClauseAspectAdder.java | 249 +++++++++++++++--- .../weaver/patterns/PerTypeWithin.java | 8 + 10 files changed, 531 insertions(+), 279 deletions(-) delete mode 100644 tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150-tests.xml delete mode 100644 tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150.xml diff --git a/runtime/src/org/aspectj/lang/Aspects.java b/runtime/src/org/aspectj/lang/Aspects.java index 0d8cb5ccb..dd1286365 100644 --- a/runtime/src/org/aspectj/lang/Aspects.java +++ b/runtime/src/org/aspectj/lang/Aspects.java @@ -13,13 +13,14 @@ package org.aspectj.lang; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationTargetException; /** * Handles generic aspectOf method when those are not available in the aspects but added later on * thru load time weaving. *

* Aspects.aspectOf(..) is doing reflective calls to the aspect aspectOf, so for better performance - * consider using preparation of the aspects. + * consider using ajc compilation of the aspects and using them as a binary dependancies in your project. * * @author Alexandre Vasseur */ @@ -27,11 +28,13 @@ public class Aspects { private final static Class[] EMPTY_CLASS_ARRAY = new Class[0]; private final static Class[] PEROBJECT_CLASS_ARRAY = new Class[]{Object.class}; + private final static Class[] PERTYPEWITHIN_CLASS_ARRAY = new Class[]{Class.class}; private final static Object[] EMPTY_OBJECT_ARRAY = new Object[0]; private final static String ASPECTOF = "aspectOf"; + private final static String HASASPECT = "hasAspect"; /** - * Returns the singleton aspect + * Returns the singleton aspect or the percflow / percflowbelow associated with the current thread * * @param aspectClass * @return @@ -39,7 +42,9 @@ public class Aspects { */ public static Object aspectOf(Class aspectClass) throws NoAspectBoundException { try { - return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); + return getSingletonOrThreadAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); + } catch (InvocationTargetException e) { + throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); } catch (Exception e) { throw new NoAspectBoundException(aspectClass.getName(), e); } @@ -55,22 +60,78 @@ public class Aspects { public static Object aspectOf(Class aspectClass, Object perObject) throws NoAspectBoundException { try { return getPerObjectAspectOf(aspectClass).invoke(null, new Object[]{perObject}); + } catch (InvocationTargetException e) { + throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); } catch (Exception e) { throw new NoAspectBoundException(aspectClass.getName(), e); } } - public static Object aspectOf(Class aspectClass, Thread perThread) throws NoAspectBoundException { - //TODO - how to know it s a real per Thread ? - // if it is actually a singleton one, we will have it as well... + /** + * Returns the pertypewithin aspect + * @param aspectClass + * @param perTypeWithin class + * @return + * @throws NoAspectBoundException if no such aspect, or no aspect bound + */ + public static Object aspectOf(Class aspectClass, Class perTypeWithin) throws NoAspectBoundException { try { - return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); + return getPerTypeWithinAspectOf(aspectClass).invoke(null, new Object[]{perTypeWithin}); + } catch (InvocationTargetException e) { + throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); } catch (Exception e) { throw new NoAspectBoundException(aspectClass.getName(), e); } } - private static Method getSingletonAspectOf(Class aspectClass) throws NoSuchMethodException { + /** + * Returns true if singleton aspect or percflow / percflowbelow aspect is bound + * + * @param aspectClass + * @return + * @throws NoAspectBoundException if not bound + */ + public static boolean hasAspect(Class aspectClass) throws NoAspectBoundException { + try { + return ((Boolean)getSingletonOrThreadHasAspect(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY)).booleanValue(); + } catch (Exception e) { + return false; + } + } + + /** + * Returns true if the perthis / pertarget aspect is bound + * @param aspectClass + * @param perObject + * @return + * @throws NoAspectBoundException if not bound + */ + public static boolean hasAspect(Class aspectClass, Object perObject) throws NoAspectBoundException { + try { + return ((Boolean)getPerObjectHasAspect(aspectClass).invoke(null, new Object[]{perObject})).booleanValue(); + } catch (Exception e) { + return false; + } + } + + /** + * Returns true if the pertypewithin aspect is bound + * @param aspectClass + * @param perTypeWithin class + * @return + * @throws NoAspectBoundException if not bound + */ + public static boolean hasAspect(Class aspectClass, Class perTypeWithin) throws NoAspectBoundException { + try { + return ((Boolean)getPerTypeWithinHasAspect(aspectClass).invoke(null, new Object[]{perTypeWithin})).booleanValue(); + } catch (Exception e) { + return false; + } + } + + // -- aspectOf + + private static Method getSingletonOrThreadAspectOf(Class aspectClass) throws NoSuchMethodException { Method method = aspectClass.getDeclaredMethod(ASPECTOF, EMPTY_CLASS_ARRAY); return checkAspectOf(method, aspectClass); } @@ -80,8 +141,12 @@ public class Aspects { return checkAspectOf(method, aspectClass); } - private static Method checkAspectOf(Method method, Class aspectClass) - throws NoSuchMethodException { + private static Method getPerTypeWithinAspectOf(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(ASPECTOF, PERTYPEWITHIN_CLASS_ARRAY); + return checkAspectOf(method, aspectClass); + } + + private static Method checkAspectOf(Method method, Class aspectClass) throws NoSuchMethodException { method.setAccessible(true); if (!method.isAccessible() || !Modifier.isPublic(method.getModifiers()) @@ -90,4 +155,31 @@ public class Aspects { } return method; } + + // -- hasAspect + + private static Method getSingletonOrThreadHasAspect(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(HASASPECT, EMPTY_CLASS_ARRAY); + return checkHasAspect(method, aspectClass); + } + + private static Method getPerObjectHasAspect(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(HASASPECT, PEROBJECT_CLASS_ARRAY); + return checkHasAspect(method, aspectClass); + } + + private static Method getPerTypeWithinHasAspect(Class aspectClass) throws NoSuchMethodException { + Method method = aspectClass.getDeclaredMethod(HASASPECT, PERTYPEWITHIN_CLASS_ARRAY); + return checkHasAspect(method, aspectClass); + } + + private static Method checkHasAspect(Method method, Class aspectClass) throws NoSuchMethodException { + method.setAccessible(true); + if (!method.isAccessible() + || !Modifier.isPublic(method.getModifiers()) + || !Modifier.isStatic(method.getModifiers())) { + throw new NoSuchMethodException(aspectClass.getName() + ".hasAspect(..) is not accessible public static"); + } + return method; + } } diff --git a/tests/java5/ataspectj/ataspectj/BindingTest.java b/tests/java5/ataspectj/ataspectj/BindingTest.java index c4114f020..342b8ebf0 100644 --- a/tests/java5/ataspectj/ataspectj/BindingTest.java +++ b/tests/java5/ataspectj/ataspectj/BindingTest.java @@ -90,6 +90,10 @@ public class BindingTest extends TestCase { //assertEquals(2, aspect.m_count); } + public void testTryCatch() { + assertEquals(6, echo(3)); + } + private static void callWithinStatic() { int res = dup((3+1)); assertEquals(6, res); @@ -177,10 +181,18 @@ public class BindingTest extends TestCase { @Around("call(int echo(int)) && withincode(void ataspectj.BindingTest.testAccessAspectState()) && args(i)") public Object aaround7(int i, final ProceedingJoinPoint jp) throws Throwable { - //m_count++;// what if inlined ? + //m_count++;// what if inlined ?//FIXME return jp.proceed(); } + @Around("call(int echo(int)) && withincode(void ataspectj.BindingTest.testTryCatch()) && args(i)") + public Object aaround8(int i, final ProceedingJoinPoint jp) throws Throwable { + try { + return 2*((Integer)jp.proceed()).intValue(); + } catch (Throwable t) { + throw t; + } + } } } diff --git a/tests/java5/ataspectj/ataspectj/PerClauseTest.java b/tests/java5/ataspectj/ataspectj/PerClauseTest.java index 0773f627f..ff8a354d2 100644 --- a/tests/java5/ataspectj/ataspectj/PerClauseTest.java +++ b/tests/java5/ataspectj/ataspectj/PerClauseTest.java @@ -33,9 +33,46 @@ public class PerClauseTest extends TestCase { } public static junit.framework.Test suite() { - return new junit.framework.TestSuite(AfterXTest.class); + return new junit.framework.TestSuite(PerClauseTest.class); } + public void perSingleton() { + log("perSingleton"); + } + + public void testPerSingleton() { + s_log = new StringBuffer(); + + // singleton is bound as soon as clinit + try { + assertTrue(Aspects.hasAspect(TestAspectPerSingleton.class)); + Aspects.aspectOf(TestAspectPerSingleton.class); + } catch (NoAspectBoundException e) { + fail(e.toString()); + } + + perSingleton(); + assertEquals("AOP.perSingleton perSingleton ", s_log.toString()); + + perSingleton(); + assertEquals(1, TestAspectPerSingleton.s_count); + } + + @Aspect() + public static class TestAspectPerSingleton { + static int s_count = 0; + public TestAspectPerSingleton() { + s_count++; + } + + @Before("execution(* ataspectj.PerClauseTest.perSingleton()) && target(t)") + public void before(JoinPoint jp, Object t) { + log("AOP."+jp.getSignature().getName()); + assertTrue("perX match", this.equals(Aspects.aspectOf(getClass()))); + } + } + + public void perTarget() { log("perTarget"); } @@ -45,8 +82,9 @@ public class PerClauseTest extends TestCase { perTarget(); assertEquals("AOP.perTarget perTarget ", s_log.toString()); - // singleton + // calling singleton API will fail try { + assertFalse(Aspects.hasAspect(TestAspectPerTarget.class)); Aspects.aspectOf(TestAspectPerTarget.class); fail("should fail with NOABE"); } catch (NoAspectBoundException e) { @@ -55,6 +93,7 @@ public class PerClauseTest extends TestCase { // this per try { + assertTrue(Aspects.hasAspect(TestAspectPerTarget.class, this)); TestAspectPerTarget aspect = (TestAspectPerTarget) Aspects.aspectOf(TestAspectPerTarget.class, this); assertNotNull(aspect); } catch (NoAspectBoundException e) { @@ -64,6 +103,7 @@ public class PerClauseTest extends TestCase { // another per PerClauseTest me = new PerClauseTest(); try { + assertFalse(Aspects.hasAspect(TestAspectPerTarget.class, me)); Aspects.aspectOf(TestAspectPerTarget.class, me); fail("should fail"); } catch (NoAspectBoundException e) { @@ -71,18 +111,22 @@ public class PerClauseTest extends TestCase { } me.perTarget(); try { + assertTrue(Aspects.hasAspect(TestAspectPerTarget.class, me)); TestAspectPerTarget aspect = (TestAspectPerTarget) Aspects.aspectOf(TestAspectPerTarget.class, me); assertNotNull(aspect); } catch (NoAspectBoundException e) { fail(e.toString()); } + + assertEquals(2, TestAspectPerTarget.s_count); } @Aspect("pertarget(execution(* ataspectj.PerClauseTest.perTarget()))") public static class TestAspectPerTarget { + static int s_count; public TestAspectPerTarget() { - ; + s_count++; } @Before("execution(* ataspectj.PerClauseTest.perTarget()) && target(t)") @@ -93,6 +137,13 @@ public class PerClauseTest extends TestCase { } public void perCflowEntry() { + // the aspect is bound to the executing thread + try { + assertTrue(Aspects.hasAspect(TestAspectPerCflow.class)); + Aspects.aspectOf(TestAspectPerCflow.class); + } catch (NoAspectBoundException e) { + fail(e.toString()); + } perCflow(); } @@ -100,27 +151,126 @@ public class PerClauseTest extends TestCase { log("perCflow"); } - public void testPerCflow() { + public void testPerCflow() throws Throwable { s_log = new StringBuffer(); + + // no aspect bound yet + try { + assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); + Aspects.aspectOf(TestAspectPerCflow.class); + fail("No perCflow should be bound yet"); + } catch (NoAspectBoundException e) { + ;//ok + } + perCflow(); assertEquals("perCflow ", s_log.toString()); + // still no aspect bound yet + try { + assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); + Aspects.aspectOf(TestAspectPerCflow.class); + fail("No perCflow should be bound yet"); + } catch (NoAspectBoundException e) { + ;//ok + } s_log = new StringBuffer(); perCflowEntry(); assertEquals("AOP.perCflow perCflow ", s_log.toString()); + // no aspect bound anymore since went OUT of the per clause + try { + assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); + Aspects.aspectOf(TestAspectPerCflow.class); + fail("No perCflow should be bound anymore"); + } catch (NoAspectBoundException e) { + ;//ok + } + + Runnable rok = new Runnable() { + public void run() { + perCflowEntry(); + } + }; + Thread trok = new Thread(rok); + trok.start(); + trok.join(); + + Runnable rko = new Runnable() { + public void run() { + perCflow(); + } + }; + Thread trko = new Thread(rko); + trko.start(); + trko.join(); + + assertEquals(2, TestAspectPerCflow.s_count); } @Aspect("percflow(execution(* ataspectj.PerClauseTest.perCflowEntry()))") public static class TestAspectPerCflow { + static int s_count; public TestAspectPerCflow() { - ; + s_count++; } @Before("execution(* ataspectj.PerClauseTest.perCflow())") public void before(JoinPoint jp) { log("AOP."+jp.getSignature().getName()); - assertTrue("perX match", this.equals(Aspects.aspectOf(getClass(), Thread.currentThread()))); + assertTrue("perX match", this.equals(Aspects.aspectOf(getClass()))); + } + } + + public void testPerTypeWithin() { + assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW1.class)); + assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW2.class)); + assertFalse(Aspects.hasAspect(TestAspectPTW.class, PTWNoMatch.class)); + + PTW1.foo(); + PTW2.foo(); + PTWNoMatch.foo(); + + assertEquals(2, TestAspectPTW.s_count); + try { + assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW1.class)); + assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW2.class)); + Aspects.aspectOf(TestAspectPTW.class, PTW1.class); + Aspects.aspectOf(TestAspectPTW.class, PTW2.class); + } catch (NoAspectBoundException e) { + fail(e.toString()); + } + try { + assertFalse(Aspects.hasAspect(TestAspectPTW.class, PTWNoMatch.class)); + Aspects.aspectOf(TestAspectPTW.class, PTWNoMatch.class); + fail("should not have PTW aspect"); + } catch (NoAspectBoundException e) { + ;//ok } } + + static class PTW1 { + static void foo() {}; + } + static class PTW2 { + static void foo() {}; + } + static class PTWNoMatch { + static void foo() {}; + } + + @Aspect("pertypewithin(ataspectj.PerClauseTest.PTW* && !ataspectj.PerClauseTest.PTWNoMatch)") + public static class TestAspectPTW { + static int s_count; + + public TestAspectPTW() { + s_count++; + } + + @Before("execution(* ataspectj.PerClauseTest.PTW*.foo())") + public void before(JoinPoint jp) { + ; + } + + } } diff --git a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150-tests.xml b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150-tests.xml deleted file mode 100644 index c426dbaa6..000000000 --- a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150-tests.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150.xml b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150.xml deleted file mode 100644 index fb3611111..000000000 --- a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150.xml +++ /dev/null @@ -1,12 +0,0 @@ - -]> - - - - - -&tests; - - - diff --git a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml index 417d0be48..daeb4da84 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml +++ b/tests/src/org/aspectj/systemtest/ajc150/ataspectj/syntax.xml @@ -79,4 +79,12 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/src/org/aspectj/systemtest/incremental/tools/AjdeInteractionTestbed.java b/tests/src/org/aspectj/systemtest/incremental/tools/AjdeInteractionTestbed.java index a7005d6b4..f90ed90b3 100644 --- a/tests/src/org/aspectj/systemtest/incremental/tools/AjdeInteractionTestbed.java +++ b/tests/src/org/aspectj/systemtest/incremental/tools/AjdeInteractionTestbed.java @@ -223,8 +223,14 @@ public class AjdeInteractionTestbed extends TestCase { // AMC - I did this rather than use the JDK default as I hate having to go look // in c:\documents and settings\......... for the results of a failed test. if (os.startsWith("Windows")) { - tempDir = new File("C:\\temp"); - if (!tempDir.exists()) {tempDir.mkdir();} + //Alex: try D first since NTFS on mine while FAT leads to failure.. + tempDir = new File("D:\\temp"); + if (!tempDir.exists()) { + tempDir = new File("C:\\temp"); + if (!tempDir.exists()) { + tempDir.mkdir(); + } + } } else { tempDir = new File("/tmp"); } diff --git a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java index d285a1574..428c0b4b8 100644 --- a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java +++ b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java @@ -160,7 +160,15 @@ public class AjcMemberMaker { TypeX.forSignature("Ljava/lang/String;"), NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, TypeX.NONE); } - + public static ResolvedMember perTypeWithinPerClassMapField(ResolvedTypeX aspectType) { + int modifiers = Modifier.PRIVATE; + if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) { + modifiers |= Modifier.TRANSIENT; + } + return new ResolvedMember(Member.FIELD, aspectType, modifiers, + TypeX.forSignature("Ljava/util/Map;"), "instances", TypeX.NONE); + } + public static ResolvedMember perObjectBind(TypeX declaringType) { return new ResolvedMember( Member.METHOD, @@ -184,7 +192,22 @@ public class AjcMemberMaker { ); return rm; } - + + // PTWIMPL ResolvedMember for "Set getInstances()" method, declared in aspect + public static ResolvedMember perTypeWithinGetInstancesSet(TypeX declaringType) { +// public Set getInstances() + ResolvedMember rm = new ResolvedMember( + Member.METHOD, + declaringType, + Modifier.PUBLIC, + TypeX.forSignature("Ljava/util/Set;"), + "getInstances", + TypeX.NONE, + TypeX.NONE + ); + return rm; + } + public static ResolvedMember perTypeWithinCreateAspectInstance(TypeX declaringType) { // public static a.X ajc$createAspectInstance(java.lang.String) ResolvedMember rm = new ResolvedMember( diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java index 7f759c721..254f429fe 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java @@ -27,6 +27,13 @@ import org.aspectj.apache.bcel.generic.POP; import org.aspectj.apache.bcel.generic.PUSH; import org.aspectj.apache.bcel.generic.ReferenceType; import org.aspectj.apache.bcel.generic.Type; +import org.aspectj.apache.bcel.generic.MethodGen; +import org.aspectj.apache.bcel.generic.RETURN; +import org.aspectj.apache.bcel.generic.NEW; +import org.aspectj.apache.bcel.generic.INVOKESPECIAL; +import org.aspectj.apache.bcel.generic.ASTORE; +import org.aspectj.apache.bcel.generic.ACONST_NULL; +import org.aspectj.apache.bcel.generic.IRETURN; import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; @@ -35,6 +42,8 @@ import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.TypeX; import org.aspectj.weaver.patterns.PerClause; +import java.util.Iterator; + /** * Adds aspectOf, hasAspect etc to the annotation defined aspects * @@ -58,8 +67,12 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { public boolean munge(BcelClassWeaver weaver) { LazyClassGen gen = weaver.getLazyClassGen(); - // agressively generate the inner interface + // agressively generate the inner interface if any + // Note: we do so because of the bug that leads to have this interface implemented by all classes and not + // only those matched by the per clause, which fails under LTW since the very first class + // gets weaved and impl this interface that is still not defined. if (!hasGeneratedInner) { + //FIXME AV - restore test below or ?? + add test to detect such side effect //if (kind == PerClause.PEROBJECT || kind == PerClause.PERCFLOW) { //inner class TypeX interfaceTypeX = AjcMemberMaker.perObjectInterfaceType(aspectType); @@ -99,6 +112,12 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { generatePerCflowHasAspectMethod(gen); generatePerCflowPushMethod(gen); generatePerCflowAjcClinitMethod(gen); + } else if (kind == PerClause.PERTYPEWITHIN) { + generatePerTWGetInstancesMethod(gen); + generatePerTWAspectOfMethod(gen); + generatePerTWHasAspectMethod(gen); + generatePerTWGetInstanceMethod(gen); + generatePerTWCreateAspectInstanceMethod(gen); } else { throw new RuntimeException("TODO not yet implemented perClause " + kind.getName()); } @@ -135,31 +154,45 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { } else if (kind == PerClause.PEROBJECT) { ResolvedMember perObjectFieldInfo = AjcMemberMaker.perObjectField(aspectType, aspectType); classGen.addField(makeFieldGen(classGen, perObjectFieldInfo).getField(), null); - -// //inner class -// TypeX interfaceTypeX = AjcMemberMaker.perObjectInterfaceType(aspectType); -// LazyClassGen interfaceGen = new LazyClassGen( -// interfaceTypeX.getName(), -// "java.lang.Object", -// null, -// Constants.ACC_PRIVATE + Constants.ACC_ABSTRACT, -// new String[0] -// ); -// interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceGet(aspectType))); -// interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceSet(aspectType))); -// classGen.addGeneratedInner(interfaceGen); + // if lazy generation of the inner interface MayHaveAspect works on LTW (see previous note) + // it should be done here. } else if (kind == PerClause.PERCFLOW) { ResolvedMember perCflowFieldInfo = AjcMemberMaker.perCflowField(aspectType); classGen.addField(makeFieldGen(classGen, perCflowFieldInfo).getField(), null); + } else if (kind == PerClause.PERTYPEWITHIN) { + ResolvedMember perTypeWithinForField = AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType); + classGen.addField(makeFieldGen(classGen, perTypeWithinForField).getField(), null); + ResolvedMember perTypeWithinPerClassMapField = AjcMemberMaker.perTypeWithinPerClassMapField(aspectType); + classGen.addField(makeFieldGen(classGen, perTypeWithinPerClassMapField).getField(), null); + // we need to initialize this map as a WeakHashMap in the aspect constructor(s) + InstructionFactory factory = classGen.getFactory(); + for (Iterator iterator = classGen.getMethodGens().iterator(); iterator.hasNext();) { + LazyMethodGen methodGen = (LazyMethodGen) iterator.next(); + if ("".equals(methodGen.getName())) { + InstructionList il = new InstructionList(); + il.append(InstructionConstants.ALOAD_0); + il.append(Utility.createGet(factory, perTypeWithinPerClassMapField)); + BranchInstruction ifNotNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); + il.append(ifNotNull); + il.append(InstructionConstants.ALOAD_0); + il.append(factory.createNew("java/util/WeakHashMap")); + il.append(new DUP()); + il.append(factory.createInvoke( + "java/util/WeakHashMap", + "", + Type.VOID, + Type.NO_ARGS, + Constants.INVOKESPECIAL + )); + il.append(Utility.createSet(factory, perTypeWithinPerClassMapField)); + InstructionHandle currentEnd = methodGen.getBody().getEnd(); + ifNotNull.setTarget(currentEnd); + methodGen.getBody().insert(currentEnd, il); + } + } } else { - throw new RuntimeException("TODO not implemented yet"); + throw new Error("Should not happen - no such kind " + kind.toString()); } -// } else if (kind == PerClause.PERTYPEWITHIN) { -// //PTWIMPL Add field for storing typename in aspect for which the aspect instance exists -// binding.addField(factory.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX))); -// } else { -// throw new RuntimeException("unimplemented"); -// } } private void generatePerSingletonAspectOfMethod(LazyClassGen classGen) { @@ -217,8 +250,8 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { InstructionHandle tryStart = il.append(factory.createInvoke(aspectType.getName(), NameMangler.AJC_POST_CLINIT_NAME, Type.VOID, Type.NO_ARGS, Constants.INVOKESTATIC)); BranchInstruction tryEnd = InstructionFactory.createBranchInstruction(Constants.GOTO, null); il.append(tryEnd); - InstructionHandle handler = il.append(InstructionFactory.createStore(Type.OBJECT, 0)); - il.append(InstructionFactory.createLoad(Type.OBJECT, 0)); + InstructionHandle handler = il.append(InstructionConstants.ASTORE_0); + il.append(InstructionConstants.ALOAD_0); il.append(Utility.createSet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); il.append(InstructionFactory.createReturn(Type.VOID)); tryEnd.setTarget(il.getEnd()); @@ -239,14 +272,14 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { classGen.addMethodGen(method); InstructionList il = method.getBody(); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createInstanceOf(interfaceType)); BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); il.append(ifEq); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createCheckCast(interfaceType)); il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); - il.append(new DUP()); + il.append(InstructionConstants.DUP); BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); il.append(ifNull); il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(aspectType))); @@ -254,7 +287,7 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { ifNull.setTarget(ifNullElse); InstructionHandle ifEqElse = il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); ifEq.setTarget(ifEqElse); - il.append(new DUP()); + il.append(InstructionConstants.DUP); il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); il.append(new ATHROW()); } @@ -266,20 +299,20 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { classGen.addMethodGen(method); InstructionList il = method.getBody(); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createInstanceOf(interfaceType)); BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); il.append(ifEq); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createCheckCast(interfaceType)); il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); il.append(ifNull); - il.append(new ICONST(1));//TODO is ok ? else Push boolean + il.append(InstructionConstants.ICONST_1); il.append(InstructionFactory.createReturn(Type.INT)); - InstructionHandle ifEqElse = il.append(new ICONST(0)); + InstructionHandle ifEqElse = il.append(InstructionConstants.ICONST_0); ifEq.setTarget(ifEqElse); - ifNull.setTarget(ifEqElse);//?? + ifNull.setTarget(ifEqElse);//??//FIXME AV - ok or what ? il.append(InstructionFactory.createReturn(Type.INT)); } @@ -290,16 +323,16 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { classGen.addMethodGen(method); InstructionList il = method.getBody(); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createInstanceOf(interfaceType)); BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); il.append(ifEq); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createCheckCast(interfaceType)); il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); il.append(ifNonNull); - il.append(new ALOAD(0)); + il.append(InstructionConstants.ALOAD_0); il.append(factory.createCheckCast(interfaceType)); il.append(factory.createNew(aspectType.getName())); il.append(InstructionConstants.DUP); @@ -317,7 +350,7 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { classGen.addMethodGen(methodGet); InstructionList ilGet = methodGet.getBody(); ilGet = new InstructionList(); - ilGet.append(new ALOAD(0)); + ilGet.append(InstructionConstants.ALOAD_0); ilGet.append(Utility.createGet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); ilGet.append(InstructionFactory.createReturn(Type.OBJECT)); @@ -325,8 +358,8 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { classGen.addMethodGen(methodSet); InstructionList ilSet = methodSet.getBody(); ilSet = new InstructionList(); - ilSet.append(new ALOAD(0)); - ilSet.append(new ALOAD(1)); + ilSet.append(InstructionConstants.ALOAD_0); + ilSet.append(InstructionConstants.ALOAD_1); ilSet.append(Utility.createSet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); ilSet.append(InstructionFactory.createReturn(Type.VOID)); } @@ -387,4 +420,144 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { clinit.getBody().insert(il); } + private void generatePerTWGetInstancesMethod(LazyClassGen classGen) { + InstructionFactory factory = classGen.getFactory(); + LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetInstancesSet(aspectType)); + classGen.addMethodGen(method); + + InstructionList il = method.getBody(); + il.append(InstructionConstants.ALOAD_0); + il.append(Utility.createGet(factory, AjcMemberMaker.perTypeWithinPerClassMapField(aspectType))); + il.append(factory.createInvoke( + "java/util/Map", "keySet", Type.getType("Ljava/util/Set;"), Type.NO_ARGS, Constants.INVOKEINTERFACE + )); + il.append(InstructionFactory.createReturn(Type.OBJECT)); + } + + private void generatePerTWAspectOfMethod(LazyClassGen classGen) { + InstructionFactory factory = classGen.getFactory(); + LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinAspectOfMethod(aspectType)); + classGen.addMethodGen(method); + + InstructionList il = method.getBody(); + InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); + + il.append(Utility.createInvoke( + factory, + Constants.INVOKESTATIC, + AjcMemberMaker.perTypeWithinGetInstance(aspectType) + )); + il.append(InstructionConstants.ASTORE_1); + il.append(InstructionConstants.ALOAD_1); + BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); + il.append(ifNonNull); + il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); + il.append(InstructionConstants.DUP); + il.append(new PUSH(classGen.getConstantPoolGen(), aspectType.getName())); + il.append(InstructionConstants.ACONST_NULL); + il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "", Type.VOID, new Type[] { Type.STRING, new ObjectType("java.lang.Throwable") }, Constants.INVOKESPECIAL)); + il.append(InstructionConstants.ATHROW); + InstructionHandle ifElse = il.append(InstructionConstants.ALOAD_1); + ifNonNull.setTarget(ifElse); + il.append(InstructionFactory.createReturn(Type.OBJECT)); + + InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); + il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); + il.append(InstructionConstants.DUP); + il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + il.append(InstructionConstants.ATHROW); + + method.addExceptionHandler( + tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false + ); + } + + private void generatePerTWHasAspectMethod(LazyClassGen classGen) { + InstructionFactory factory = classGen.getFactory(); + LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinHasAspectMethod(aspectType)); + classGen.addMethodGen(method); + + InstructionList il = method.getBody(); + InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); + il.append(Utility.createInvoke( + factory, + Constants.INVOKESTATIC, + AjcMemberMaker.perTypeWithinGetInstance(aspectType) + )); + BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); + il.append(ifNull); + il.append(InstructionConstants.ICONST_1); + il.append(InstructionConstants.IRETURN); + InstructionHandle ifElse = il.append(InstructionConstants.ICONST_0); + ifNull.setTarget(ifElse); + il.append(InstructionConstants.IRETURN); + + InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); + il.append(InstructionConstants.ICONST_0); + il.append(InstructionConstants.IRETURN); + + method.addExceptionHandler( + tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false + ); + } + + private void generatePerTWGetInstanceMethod(LazyClassGen classGen) { + InstructionFactory factory = classGen.getFactory(); + LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetInstance(aspectType)); + classGen.addMethodGen(method); + + InstructionList il = method.getBody(); + InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); + il.append(new PUSH(factory.getConstantPool(), NameMangler.perTypeWithinLocalAspectOf(aspectType))); + il.append(InstructionConstants.ACONST_NULL);//Class[] for "getDeclaredMethod" + il.append(factory.createInvoke( + "java/lang/Class", + "getDeclaredMethod", + Type.getType("Ljava/lang/reflect/Method;"), + new Type[]{Type.getType("Ljava/lang/String;"), Type.getType("[Ljava/lang/Class;")}, + Constants.INVOKEVIRTUAL + )); + il.append(InstructionConstants.ACONST_NULL);//Object for "invoke", static method + il.append(InstructionConstants.ACONST_NULL);//Object[] for "invoke", no arg + il.append(factory.createInvoke( + "java/lang/reflect/Method", + "invoke", + Type.OBJECT, + new Type[]{Type.getType("Ljava/lang/Object;"), Type.getType("[Ljava/lang/Object;")}, + Constants.INVOKEVIRTUAL + )); + il.append(factory.createCheckCast((ReferenceType) BcelWorld.makeBcelType(aspectType))); + il.append(InstructionConstants.ARETURN); + + InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); + il.append(InstructionConstants.ALOAD_1); + il.append(InstructionConstants.ATHROW); + + method.addExceptionHandler( + tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false + ); + } + + private void generatePerTWCreateAspectInstanceMethod(LazyClassGen classGen) { + InstructionFactory factory = classGen.getFactory(); + LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinCreateAspectInstance(aspectType)); + classGen.addMethodGen(method); + + InstructionList il = method.getBody(); + il.append(factory.createNew(aspectType.getName())); + il.append(InstructionConstants.DUP); + il.append(factory.createInvoke( + aspectType.getName(), "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL + )); + il.append(InstructionConstants.ASTORE_1); + il.append(InstructionConstants.ALOAD_1); + il.append(InstructionConstants.ALOAD_0); + il.append(Utility.createSet( + factory, + AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType) + )); + il.append(InstructionConstants.ALOAD_1); + il.append(InstructionConstants.ARETURN); + } + } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java index 151e3f2d7..df2db0cbb 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java @@ -145,6 +145,14 @@ public class PerTypeWithin extends PerClause { ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret); inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect)); + + //ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects + if (inAspect.isAnnotationStyleAspect()) { + inAspect.crosscuttingMembers.addTypeMunger( + inAspect.getWorld().makePerClauseAspect(inAspect, getKind()) + ); + } + return ret; } -- 2.39.5