Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Static Analysis of Aspects
Evgeniy Gabrilovich
http://www.cs.technion.ac.il/~gabr
CS Department, Technion
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Problems with AOP
1. Aspect applicability is usually decided dynamically
– Matching join points with pointcut designators incurs significant run-time overhead
2. Multiple pieces of advice may apply at the same program point Programs are difficult to maintain and debug
ComposeJ, JasCo/JAC
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
60 seconds about Dynamic Matching
• Aspect code monitors the execution of the base program
• Certain (sequences of) events trigger the aspect code (aka advice)– Monitored events are defined as patterns in
the call stack– An aspect can be applied recursively,
monitoring its own execution
• Dynamic matching is expensive !
Observer Pattern
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Outline
• New syntax for pointcut designators
• Running example
• Compiling aspects in AspectJ
• Static analysis
• Running example revisited
• Limitations of the approach
• Conclusions
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Reminder: Join points and pointcuts in AspectJ• Join point – a machine configuration
where advice might intervene
• Pointcut – a set of join points where a given advice should be executed– Examples: call(…), execution(…),
cflow(…), cflowbelow(…)– Complex pointcuts use boolean operators:
•!p, p1 || p2, p1 && p2
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
New syntax – regular expressions over control stack
• Intuition: join points as abstractions over control stack– modeling the sequence of procedure calls as
a graph
• A join point is a sequence of– Procedure calls (call)– Procedure executions (exec)– Advice executions (aexec)
Invocation of a procedure at the call site
Entry into the procedure’s body
Demeter used object
graphs
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Grammar for the language of possible join points
jp ::= jp_element*
jp_element ::= call(name, name,
actual_param*)
| exec name
| aexec name
Called procedure
Calling context
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Pointcut designators (PCDs)
• Regular expressions over an alphabet of element designators:ed ::= pcall pname
| pwithin name
| args var*
| ed or ed
| ed and ed
| not ed
| true
Matches join point elements of the form call(n,_,_)
Matches calls made from the context n: call(_,n,_)
args(x1,…,xn) matches call(_,_,[a1,…,an]), binding xi to ai
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Profiling Quicksort
• linesbuf is a global variable holding an array of strings
compare(i,j) returns true if linesbuf[i] < linesbuf[j]
swap(i,j) swaps lines i and j
readln(i) reads a line into linesbuf[i]
writeln(i) prints linesbuf[i]
partition(a,b) partitions linesbuf[a..b) with pivot linesbuf[a]
quicksort(a,b) sorts linesbuf[a..b)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Gathering Quicksort statistics
1. Count the number of calls to partition2. Count the number of swap operations
• Note that– there may be other uses of swap apart from
the obvious ones within the partition routine– both swap and partition may also be used
outside quicksort
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Profiling aspect for Quicksort (1/4)
aspect Counts
var swaps, partitions: int;
advice PCount
before: {pcall(partition) /\ pwithin(quicksort)}; {true}*
begin
partitions := partitions + 1
end
Top of the call stack
A call to partition from the body of
quicksort
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Profiling aspect for Quicksort (2/4)
advice SCount
before: {pcall(swap);{true}*;{pcall(quicksort)};{true}*
begin
swaps := swaps + 1
endA call to swap within the context of a call
to quicksort
pcall(swap) /\ cflow(quicksort)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Profiling aspect for Quicksort (3/4)
advice Init
before: {pcall(quicksort)}; {not pcall(quicksort)}*
begin
partitions := 0;
swaps := 0
end
Only matches non-recursive calls to
quicksort
pcall(quicksort) /\ not cflowbelow(quicksort)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Profiling aspect for Quicksort (4/4)
advice Print
after: {pcall(quicksort)}; {not pcall(quicksort)}*
begin
println “Partitions: “ ++ partitions;
println “Swaps: “ ++ swaps;
end
end Counts
Only matches non-recursive calls to
quicksort
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Example
main()
quicksort()
f()
{pcall(quicksort)}; {not pcall(quicksort)}*
quicksort()
X
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
More examples
main()
quicksort()
f()
{pcall(swap);{true}*;{pcall(quicksort)};{true}*
partition()
swap()
main()readln()swap()X
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Interpreting aspects• Localizing the code that gathers quicksort
statistics is nice … provided the run-time cost is negligible
• Dynamic matching– Whenever a new join point is created,
it’s matched against all PCDs– If a match is found, the corresponding advice
is executed, with PCD variables bound in matching
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Interpreting aspects: example• Initialization trigger:
{pcall(quicksort)}; {not pcall(quicksort)}*• To check that a join point satisfies this
PCD, we must traverse the whole join point (= call stack)
• Upon each creation of a new join point, the interpreter may have to traverse the whole join point for each PCD
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
The AspectJ approach
• Each PCD corresponds to a DFA• The compiled program maintains a set of
such automata• Inspecting the automaton state determines
in O(1) whether the corresponding aspect code should be executed
Maintaining these automata is still a significant overhead, proportional to the number of PCDs (= pieces of advice)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Static analysis of aspects• Our goal:
– Completely eliminate the matching process– Determine for each point in the program
exactly what PCDs will apply at run-time
• Then, a compiler can generate a tangled program that the programmer might have written before aspects were invented
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
The approach• Given the program call graph
– determine for each procedure call the set of all join points possible at that call
– statically determine all matching PCDs
• Perform source-to-source transformation by weaving all applicable advice at compile-time– No PCD matching is needed at run-time! – This is not always possible
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Analysis overview
• Each piece of advice (a) is associated with a PCD (pcd), which denotes a (usually infinite) set of join points: join_points(pcd)
• Advice a is executed if the current join point (= sequence of procedure calls in the call stack) belongs to join_points(pcd)
• For each procedure call p in the program, compute a set L(p) of all possible join points at evaluation of the call p.
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Static analysis by computing language containment
• L(p) is defined as a regular language over the call graph of the program
• join_points(pcd) is a regular language defined by the regular expression of pcd
Then:
• a always applies at p
• a never applies at p
• Otherwise, the analysis is inconclusive
s(pcd)join_point)( pL
s(pcd)join_point)( pL
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Examples {pcall(quicksort)}; {not pcall(quicksort)}*
main()quicksort()
Init
{pcall(swap);{true}*;{pcall(quicksort)};{true}*
main()swap()
quicksort()
partition()
SCount
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Constructing the call graph
• Nodes – procedure calls + aspects
• Edges – join point elements– elementary operations affecting the control
stack
• Join points – sequences of join point elements = paths in the call graph
• L(p) = a set of paths from the source
vertex v (main) to the vertex representing p
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Constructing the call graph (2)• Every path from v to p is a valid join point
at p – although it doesn’t have to occur in actual
program runs – overestimation !
• Every valid join point is represented by a path
• 3 kinds of edges (= join point elements):– procedure calls– procedure executions– advice executions
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Direct (unadvised)
path
Advised paths (possibly chaining multiple aspects)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Pruning the call graph
• The construction yields a huge call graph with many infeasible edges
• Reducing the graph size by considering the topmost element of the call stack:– PCDs of the form {pcall(f) /\ …}; … can never
apply to a call to procedure g ≠ f
nodes for corresponding advice need not be included for such calls, and may be pruned
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Meet-over-all-paths analysis• Given the source program, construct its
call graph– The set of paths from v to p is a superset of
the set of possible call stacks at point p during program execution
• For each procedure call p– obtain a regular expression L(p)
• Tarjan’s algorithm – O(|E| · log (|V|)
– Test it for inclusion w.r.t. each PCD• O(|E| + |V|)
The set of join points at p
s(pcd)join_point)( pLs(pcd)join_point)( pL
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Analyzing the Quicksort example
• Legend (for a procedure call p and an advice a):– √ - a always applies at p– x – a can never apply at p– (blank) – the analysis is inconclusive
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Examples {pcall(quicksort)}; {not pcall(quicksort)}*
main()quicksort()
Init
{pcall(swap);{true}*;{pcall(quicksort)};{true}*
main()swap()
quicksort()
partition()
SCount
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Quicksort example (cont’d)
• PCount advice is in a sense static – it only depends on the textual location of the call– Only the topmost item of the stack is matched:
{pcall(partition) /\ pwithin(quicksort)}; {true}*
quicksort() {
…
partition();
…
}
partition() {
…
}
jp_element = call(partition,quicksort,_)
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Quicksort example (cont’d)
• The other two PCDs are truly dynamic and depend on the call stack:– {pcall(swap);{true}*;{pcall(quicksort)};{true}* - a call to
swap is within dynamic scope of quicksort– {pcall(quicksort)}; {not pcall(quicksort)}* - a call to
quicksort is not recursive
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Quicksort example (cont’d)
• The analysis was successful for each advice and each procedure call
Dynamic PCDs are in fact static in the context of the base program
Static matching is possible!
• Separation of concerns (sorting per se and profiling) does not sacrifice run-time efficiency
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Limitations of the approach• Static analysis is not always possible for
arbitrary PCDs– Consider a simple procedure f with a single
recursive call to itself– {pcall(f)}; {true}*; {pcall(f)}; {true}*; {pcall(f)}; {true}*;
• recursion depth ≥ 3
– This PCD applies to some – but not all – recursive calls from f to itself
• For example, it does not apply to the first such call
pcall(f) /\ cflowbelow ( pcall(f) /\ cflowbelow(pcall(f))
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Limitations (cont’d)• PCDs cannot make tests that depend on
dynamic values of variables (args)– Otherwise, the matching code cannot be
eliminated – we still must maintain a stack of variable bindings
• The construction of the call graph is complicated by virtual methods– At each virtual method call, we need to
determine what instances might be called– Open issue
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Conclusions
• Primitive language for describing patterns in the call stack using regular expressions
• Meet-over-all-paths analysis enables the compiler to determine aspect applicability statically– Run-time overhead of matching PCDs can be
reduced, and sometimes completely eliminated
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Conclusions (cont’d)
• In practice, static undecidability is limited to a few procedure calls in the program– Large portions of the call graph can still be
woven statically
• In large AO programs, it is important to warn programmers of potential interactions between aspects– Static analysis can detect when different
pieces of advice may both be executed at the same program point
Seminar on Aspect-Oriented Software Development (236800)
Static Analysis of Aspects December 5, 2004
Bibliography1. D. Sereni and Oege de Moor. “Static Analysis of
Aspects”, AOSD 2003
2. H. Masuhara, G. Kiczales and C. Dutchyn. “Compilation Semantics of Aspect-Oriented Programs”, FOAL Workshop at AOSD 2002
3. M. Wand, G. Kiczales and C. Dutchyn. “A Semantics for Advice and Dynamic Join Points in AOP”, FOAL Workshop at AOSD 2002
4. E. Gamma, R. Helm, R. Johnson and J. Vlissides. “Design Patterns”, Addison-Wesley, 1995
5. R.E. Tarjan. “Fast Algorithms for Solving Path Problems”, JACM 28(3), 1981