Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
research:mao:invariant-pcd [2011/12/19 16:34] – minostro | research:mao:invariant-pcd [2012/01/21 15:27] (current) – minostro | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | Join point interfaces (JPIs) are contracts between aspects and advised code. Pieces of advice do not refer explicitly to the advised code anymore because of they are pointcut free. From now on, a piece of advice contains a bound JPI instead of a pointcut expression. | ||
+ | Due to our semantics a pointcut expression, defined as part of an exhibits clause, must select join points in a invariant way considering the bound JPI signature. | ||
+ | |||
+ | ====== Motivation ====== | ||
+ | |||
+ | We devise JPIs as a compiler extension of AspectBench compiler for AspectJ. | ||
+ | |||
+ | The pointcut matcher elements which in certain situations select join points in a covariant way are //args//, //this// and //target//. //Args//, //this// and // | ||
+ | |||
+ | <code java> | ||
+ | jpi void Call(Number n); | ||
+ | |||
+ | class C{ | ||
+ | |||
+ | exhibits void Call(Number l) : //(1) | ||
+ | call(void *(..)) && args(l); | ||
+ | |||
+ | public static void doSomething(Integer x){...} | ||
+ | |||
+ | public static void doSomethingElse(Float x){...} | ||
+ | | ||
+ | public static void main(string[] args){ | ||
+ | doSomething(2); | ||
+ | doSomethingElse(2.3); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The pointcut expression defines as part of the exhibits clause (1) will capture the join points (*) in a covariant way. That means a) join points(*) will be captured by the pointcut expression, and b) the following advice will be able to manipulate the arguments of those join points as if they were Number. | ||
+ | |||
+ | <code java> | ||
+ | aspect A{ | ||
+ | |||
+ | void around Call(Number z){ | ||
+ | proceed(new Integer(4)); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | You might see that this program will raise a ClassCastException when the second selected join point is executed. | ||
+ | |||
+ | ====== Solution ====== | ||
+ | |||
+ | In order to have a pointcut matcher that knows our semantics, we need to define three new PCDs: // | ||
+ | |||
+ | |||
+ | ====== Implementation ====== | ||
+ | The implementation of invariant versions of //arg//, //this// and //target// PCDs needs to modify our compiler extension in the following parts: //parser//, //AST//, // | ||
+ | |||
+ | First, // | ||
+ | |||
+ | Finally, we will create // | ||
+ | |||
+ | <code java> | ||
+ | CheckType.construct(cv, | ||
+ | </ | ||
+ | |||
+ | |||
+ | ====== Appendix ====== | ||
+ | In this section we show some examples which defeat the JPI's type system (also AspectJ) by using PCDs that use variant semantics in types (args, this, target). | ||
+ | |||
+ | |||
+ | <code java> | ||
+ | jpi void MethodCall(AbstractCommand ac); | ||
+ | |||
+ | abstract class AbstractCommand{ | ||
+ | public void exec(){} | ||
+ | } | ||
+ | |||
+ | class UndoableCommand extends AbstractCommand{} | ||
+ | |||
+ | class UndoCommand extends AbstractCommand{ | ||
+ | |||
+ | exhibits void MethodCall(AbstractCommand ac) : | ||
+ | execution(void exec()) && this(ac); //variant PCD definition | ||
+ | |||
+ | @Override | ||
+ | public void exec(){} | ||
+ | } | ||
+ | |||
+ | public aspect TypeVariance{ | ||
+ | |||
+ | void around MethodCall(AbstractCommand ac){ | ||
+ | proceed(new UndoableCommand()); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args){ | ||
+ | UndoCommand uc = new UndoCommand(); | ||
+ | uc.exec(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | The output is: | ||
+ | |||
+ | < | ||
+ | Running test 1655: abctests/ | ||
+ | Commandline: | ||
+ | ac | ||
+ | InvocationTargetException while trying to run compiled class: java.lang.ClassCastException: | ||
+ | java.lang.reflect.InvocationTargetException | ||
+ | at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) | ||
+ | at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: | ||
+ | at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: | ||
+ | at java.lang.reflect.Method.invoke(Method.java: | ||
+ | at abc.testing.TestCase.runTest(TestCase.java: | ||
+ | at abc.testing.Main.doCase(Main.java: | ||
+ | at abc.testing.Main.main(Main.java: | ||
+ | Caused by: java.lang.ClassCastException: | ||
+ | at TypeVariance.inline$0$around$0(TypeVariance.java: | ||
+ | at UndoCommand.exec(TypeVariance.java) | ||
+ | at TypeVariance.main(TypeVariance.java: | ||
+ | ... 7 more | ||
+ | FAIL: Test 1655: " | ||
+ | </ | ||
+ | |||
+ | |||
+ | Interestingly, | ||
+ | |||
+ | <code java> | ||
+ | public aspect Interfaces { | ||
+ | |||
+ | public static void main(String[] args){ | ||
+ | BasicThread bt = new BasicThread(); | ||
+ | ComplexThread ct = new ComplexThread(); | ||
+ | bt.run(); | ||
+ | ct.run(); | ||
+ | } | ||
+ | |||
+ | void around(Runnable r) : call(void run()) && target(r){ | ||
+ | proceed(new DummyThread()); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | class BasicThread implements Runnable{ | ||
+ | public void run() {} | ||
+ | } | ||
+ | |||
+ | class ComplexThread implements Runnable{ | ||
+ | public void run() {} | ||
+ | } | ||
+ | |||
+ | class DummyThread implements Runnable{ | ||
+ | public void run() {} | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The execution output of this program is the following: | ||
+ | |||
+ | < | ||
+ | aspects.BasicThread | ||
+ | at aspects.Interfaces$AjcClosure1.run(Interfaces.aj: | ||
+ | at aspects.Interfaces.ajc$around$aspects_Interfaces$1$3b1f0542proceed(Interfaces.aj: | ||
+ | at aspects.Interfaces.ajc$around$aspects_Interfaces$1$3b1f0542(Interfaces.aj: | ||
+ | at aspects.Interfaces.main(Interfaces.aj: | ||
+ | </ |