ABC: an implementation of AspectJ

Download Report

Transcript ABC: an implementation of AspectJ

ABC: an implementation of AspectJ

Oege de Moor Programming 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

Static:

Intertype declarations:

inject new members into existing classes at compile-time Dynamic : aspect observes base program when certain patterns of events happen, run some extra code “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 enforcement

}

public 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 class

public 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());

Authorisation

public 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 pass

public 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 “weaving” ajc class files ● builds on Eclipse compiler ● weaving with BCEL ● incremental ● about 45KLOC, excluding IDE support ● 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

source

public class

MethodMatch {

public static

void main(String[] args) { foo((Object)"Object"); foo("String"); }

public aspect

NewFoo {

public static

void MethodMatch.foo(String s) { System.out.println("A string: " + s); } } }

public static

void foo(Object o) { System.out.println("An object: " + o); }

compile together from source:

An object: Object A string: String

weave aspect into MethodMatch.class:

An object: Object An 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

modified ajc frontend tagging bytecode weaver standard JVM Dufour, Goard

et al

, OOPSLA 2004 JVMPI interface *J dynamic metric tool JVMPI agent metric analyser with tag propagator standard metrics

AspectJ-specific metrics

ajc performance

100 90 80 70 60 50 40 30 20 10 0 DCM ProdLin Bean NllChk Figure LoD 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

AspectJ source, and jars Polyglot Java compiler AspectJ extension Java extracts of source aspectInfo intertype adjuster advice weaver class files Jimple Soot analysis and transformation framework

Polyglot: scope for intertype decls

} }

public class

A { int x;

class

B { int x; host class

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.

} }

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; 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

if

int foo(int x, int y) { (x

return

(y-x);

else return

} (x-y);

Soot: Jimple

int foo(int, int) { Example this; int x, y, $i0, $i1; normal compilation this := @this:Example; x := @parameter0: int; y := @parameter1: int;

if

x >= y

goto

label0; }

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); } $i0 = y - x;

return

$i0; } label0: $i1 = x - y;

return

$i1;

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 (); virtualinvoke theAspect.(); nop; theAspect1 = staticinvoke (); adviceformal = $i1; virtualinvoke theAspect1. (adviceformal); nop;

ABC performance

ajc/abc 3 2 1 0 8 7 6 5 4 14 13 12 11 10 9 dcm pr dlin bean nllchk f igur e LoD JIT inter pr eter

Win (1) : no closures for around

public 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,...); ...

} }

calls

thisparam.proceed(0,...)

public

void anotherShadowMethod() { ... Aspect.aspectOf().adviceMethod$1(this,1,arg1,...); ...

calls

thisparam.proceed(1,...)

Win (2) : no stacks for cflow

cflow

(

call

(* foo(..))) &&

call

(* bar(..))

matches call stack:

bar ● ajc: simulates call stack by pushing and popping around

foo

calls ● one stack per thread ...

foo ...

● 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 completely allow cflow in declare warning/error Sereni

et al

, AOSD 2003.

Extensibility of abc

size of abc: 40KLOC polyglot: 60KLOC Soot: 180KLOC ● ● ● three extensions: local variables in pointcuts cast pointcut global pointcuts in the works: pointcuts that query program trace “pure” modifier on aspects ● ● ● ● ● ● ● 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

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