Download - ABC: an implementation of AspectJ
ABC: an implementation of AspectJ
Oege de MoorProgramming Tools Group
University of Oxford
joint work with Ganesh Sittampalam, Sascha Kuzins, Chris Allan,
Pavel Avgustinov, Julian Tibble, Damien Sereni (Oxford)Laurie Hendren, Jennifer Lhoták, Ondřej Lhoták, Bruno Dufour,
Christopher Goard, Clark Verbrugge (McGill)Aske Simon Christensen (Århus)
What is AspectJ?
disciplined metaprogramming
The bluffer's guide to aspect-lingo
Intertype declarations:inject new members intoexisting classes at compile-time
aspect observes base programwhen certain patterns of events happen,run some extra code
Static:
Dynamic:
“join point” = event = node in (dynamic) call graph
“pointcut” = pattern of events = set of nodes in call graph
“shadow” = program point that corresponds to join point
“advice” = extra code
EJB policy enforcementpublic aspect DetectEJBViolations {
pointcut uiCalls() : call(* java.awt.*+.*(..));
before() : uiCalls() && cflow(call(* EnterpriseBean+.*(..))) {System.err.println("UI call from EJB");
}
declare error : uiCalls() && within(EnterpriseBean+) : "UI call from EJB";
pointcut staticMemberAccess() : set(static * EnterpriseBean+.*);
declare error : staticMemberAccess() : "EJBs are not allowed to have non-final static vars";
}
Counting live objects per classpublic aspect AllocFree {
public interface Finalize {}
declare parents: mypackage..* implements Finalize;
public void Finalize.finalize() throws Throwable { LiveData.decr(this.getClass());
}
before(Object tgt): initialization(mypackage..*.new(..)) && this(tgt) { LiveData.incr(tgt.getClass());
} }
Authorisationpublic abstract aspect AbstractAuthAspect { private Subject _authenticatedSubject; public abstract pointcut authOperations(); ... Object around()
: authOperations() && !cflowbelow(authOperations()) {try { return Subject.doAsPrivileged(_authenticatedSubject,
new PrivilegedExceptionAction() {public Object run() throws Exception { return proceed();}}, null);
} catch (PrivilegedActionException ex) { throw new AuthorizationException(ex.getException());}
}}
New compiler passpublic aspect AspectTransformPass {
AspectTransformer Assign.aspectTransformEnter(AspectTransformer at) { ....}
Node Assign.aspectTransformLeave(AspectTransformer at) { ...
} }
AST node Assign has subclasses LocalAssign, FieldAssign, ...
ajc: “standard” AspectJ compiler
aspects
java source
jars
ajc class files
● builds on Eclipse compiler● weaving with BCEL● incremental● about 45KLOC, excluding IDE support
“weaving”
● started out as source-to-source● java parts may be aspect-aware
Daniel Sabbah (VP of development@ IBM): “critical to our survival”
Problems with jars vs sourcepublic class MethodMatch { public static void main(String[] args) { foo((Object)"Object"); foo("String"); } public static void foo(Object o) { System.out.println("An object: " + o); } }
public aspect NewFoo { public static void MethodMatch.foo(String s) { System.out.println("A string: " + s); } }
compile together from source:
An object: ObjectA string: String
weave aspect into MethodMatch.class:
An object: ObjectAn object: String
What do you pay at runtime?
From the FAQ on aspectj.org:
We aim for the performance of our implementation of AspectJ to be on par with the same functionality hand-coded in Java. Anything significantly less should be considered a bug.
...we believe that code generated by AspectJ has negligible performance overhead.
Measuring the cost with *J
frontend
tagging bytecodeweaver
modified ajc
JVMPI interface
standard JVM
*J dynamic metric tool
JVMPI agent
metric analyser with
tag propagator
standard metrics
AspectJ-specific metrics
Dufour, Goard et al,OOPSLA 2004
ajc performance
DCM ProdLin Bean NllChk Figure LoD0
20
40
60
80
100
120
Overheads(%)Slowdown(*)
The need for a second compiler
● language definition other than test suite
● explore AOP language design space
● experiment with better code generation
● experiment with static analyses
for safety checks and optimisations
The AspectBench Compiler: ABC
AspectJextension
AspectJsource,and jars
Polyglot Javacompiler
aspectInfo
Java extracts of source
Jimple
intertypeadjuster
advice weaver
Sootanalysis and
transformationframework
class files
Polyglot: scope for intertype decls
public class A {
int x;
class B {
int x;
}
}
aspect Aspect {
static int x;
static int y;
int A.B.foo() {
class C {
int x = 3;
int bar() {return x + A.this.x;}
}
return (new C()).bar() + x + y;
}
}
when does field or call refer to host class A.B?● no explicit receiver? if it was introduced
into environment via the ITD, give it “this” from host.● explicit “this” or “super”? if there is no
qualifier and we're not inside a local class,
it refers to the host. If there is a qualifier Q,
it refers to the host if the host has an enclosing
instance of type Q.
implementation:● extend environment type● new AST nodes “hostSpecial” (this/super)● ITDs add accessible members from host● rewrite rules to disambiguate this/super to “Special” or “hostSpecial”
host class
Soot: Jimple int foo(int x, int y) {
if (x<y) return (y-x);else return (x-y);
}
int foo(int, int) {
Example this; int x, y, $i0, $i1;
this := @this:Example; x := @parameter0: int; y := @parameter1: int; if x >= y goto label0;
$i0 = y - x; return $i0;
label0: $i1 = x - y; return $i1; }
want to weave:aspect Aspect { after() returning : execution(* foo(..)) {
System.out.println("woven"); } after() returning(int x) : execution(int foo(..)) {
System.out.println("result="+x); } }
normal compilation
Weaving at shadows this := @this:Example; x := @parameter0: int; y := @parameter1: int; nop; if x >= y goto label0;
$i0 = y - x; $i1 = $i0; goto label1;
label0: $i1 = x - y;
label1: nop; return $i1; }
nop;
theAspect = staticinvoke <Aspect: Aspect
aspectOf()>();
virtualinvoke theAspect.<Aspect: void
afterReturning$0()>();
nop;
theAspect1 = staticinvoke <Aspect: Aspect
aspectOf()>();
adviceformal = $i1;
virtualinvoke theAspect1.<Aspect: void
afterReturning$1(int)>
(adviceformal);
nop;
ABC performance
dcm prdlin bean nllchk figure LoD0
2
4
6
8
10
12
14
16
ajc/abc
JIT interpreter
Win (1) : no closures for aroundpublic class ShadowClass implements AroundClosure$1 {
public [ret-type] proceed(int shadowID, [arg-type] arg1, ...) {switch(shadowID) {
case 0:... do what first shadow did ...
case 1:... do what second shadow did ...
}}
public void shadowMethod() {... Aspect.aspectOf().adviceMethod$1(this,0,arg1,...); ...
}
public void anotherShadowMethod() {... Aspect.aspectOf().adviceMethod$1(this,1,arg1,...); ...
}}
calls thisparam.proceed(0,...)
calls thisparam.proceed(1,...)
Win (2) : no stacks for cflow
cflow(call(* foo(..))) && call (* bar(..))
matches call stack:
bar
foo
...
...
ajc:● simulates call stack by pushing and
popping around foo calls ● one stack per thread
abc:● use counter in lieu of stack when possible● CSE on cflow expressions● look up thread-local stack/counter only once per body ● static estimate of possible call stacks can
eliminate runtime cost completelyallow cflow in declare warning/error
Sereni et al, AOSD 2003.
Extensibility of abc
three extensions:● local variables in pointcuts● cast pointcut● global pointcuts
● 3 new ast classes● 3 new weaver classes● override 1 ast class● 1 new node factory● 1 new visitor pass● total 946 lines● enable with compiler flags
in the works:pointcuts that query program trace“pure” modifier on aspects
size of abc: 40KLOCpolyglot: 60KLOCSoot: 180KLOC
ABC Summary● Implements the same language as ajc● Whole-program, aimed at
– extensibility
– static analysis
– performance of compiled code
● Suite of associated tools: decompiler, performance measurement, visualisation in Eclipse
● Current status:– pass majority of ajc test suite
– likely release mid-October:complete development in 9 months