Download - Region Pointcut for AspectJ
Region Pointcut for AspectJ
Shumpei Akai
Shigeru Chiba
Muga Nishizawa
Background: Synchronization
Granularity of synchronization alters performance– Fine-grained: Increase concurrency– Coarse-grained: Less overhead
Which granularity is better on a given machine?
Motivating example: Javassist
A bug report of synchronization for Javassist
[http://jira.jboss.org/jira/browse/JASSIST-28]
– Adding synchronization to fix the bug.
– coarse-grained is chosen in this case.
Separate synchronization code as an aspect– enable choosing
appropriate granularity.
public class ProxyFactory { public Class createClass() { if (thisClass == null) { ClassLoader cl = getClassLoader(); synchronized (proxyCache) { if (useCache){createClass2(cl);} else {createClass3(cl);} }} return thisClass;} private void createClass2(ClassLoader cl) { CacheKey key = new CacheKey(…); synchronized (proxyCache) { HashMap cacheForTheLoader =…; if (cacheForTheLoader == null) { cacheForTheLoader = new HashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); }else {...}} synchronized (key) { Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = new WeakReference(…); }else{thisClass = c;} }}}
Coarse-grained
candidate
Fine-grained
Separating synchronization with AOP
New pointcuts are needed– AspectJ provides execution, call, get, set
pointcuts They pick out Join “points”.
– But synchronization is applied to a “range” of code.
Join points are not suitable Need to pick out regions (or pieces of code)
Region pointcut
Regions are treated like join points– Use pattern matching– Static analysis and code transformation
Regions are determined by static analysis.
Extension to AspectJ
region[pc1;pc2;pc3;…]
A new pointcut for a region– Specify a sequence of join points– Find a matching path
public void foo() { … obj.criticalSectionBegin();//from here if(…){ a(); } … obj.criticalSectionEnd();//to here …}
void around():region[ call(* *. criticalSectionBegin()); call(* *.a()); call(* *. criticalSectionEnd());]{ synchronized(someObject){ proceed(); }}
New pointcut: all()
all(pc1, pc2, pc3, …)– Matches a sequence including the join points all
the pointcuts pc1, pc2, pc3, … match in some order.
– The order of pointcuts does not matter. because the order of join points may be changed by
refactoring
Example of all()
region[ all( call(* *.a()), call(* *.b()), call(* *.c()) )]
{ a(); … b(); … c();}
{ b(); … c(); … a();}
{ c(); … b(); c(); … a();}
matches
A region may conflict with a control structure
If a region intersects a control structure– we cannot weave an
around advice
public void foo() { ... for(int i=0;i<100;i++){ bar(); beginCriticalSection(); // begin ... } endCriticalSection(); // end ...}
void around():region[ call(* *. criticalSectionBegin()); call(* *. criticalSectionEnd())]{ /* do something*/ }
Region adjustment
Solves the conflict– Expand a selected
region: to fit a control structure to include the first and
the last selected join points
– A minimum region satisfying the criteria above is selected
public void foo() { ... for(int i=0;i<100;i++){ bar(); beginCriticalSection(); // begin ... } endCriticalSection(); // end ...}
Context passing
Synchronization needs a lock object– Contexts must be available in an advice body
args(), target() are available in a pattern– Specified values must be accessible at the
beginning of the region
Example of context passing
… List list = ... ; ... for(int index = 0; i < 100; i++){ beginCriticalSection(); ... Object o=list.get(index); ... endCriticalSection(); } ...
pointcut pc(List l,int i) : region[ call(* *.beginCriticalSection()); call(* List+.get(int)) && target(l) && args(i) ; call(* *.endCriticalSection()); ];
Implementation
We implemented by extending abc– abc: The AspectBench Compiler for AspectJ
Need information, where blocks, control structures and statements start/end– Add new instruction into Jimple
public void toBeAdvised(int x){ a(); b(x); c();}
original method
Around advice
In abc, some join points (e.g. execution) are split into static methods to weave an around advice– Local variables are passed through arguments– We adopt this mechanism
This causes a few problems for the region pointcut
public void toBeAdvised(int x){ advice(x);}
public static void advice(int x){ beforeJoinPoint(); shadow(x); afterJoinPoint();}
public static shadow(int x){ a(); b(x); c();}
woven method advice original join point
Support an around advice : assignment (problem)
Assignment does not change the value of the local variable– Local variables are
replicated.
public void toBeAdvised(int x){ String s="initial string"; a(); s="string was replaced"; b(); System.out.println(s); // what is the value of s?}
void around(): region[call(* *.a());call(* *.b())] { proceed(); }
Support an around advice : assignment (solution)
Share an object between the region and the original method– Each field contains a
value of a local variable
public void toBeAdvised(int x){ String s="initial string"; $localStorage = new LocalStorage(); $localStorage.s=s;
s=$localStorage.s; a(); s="string was replaced"; b(); $localStorage.s=s;
s=$localStorage.s; System.out.println(s);}
Support an around advice : jumps (problem)
Jumps (break or continue) to outside of region are unavailable
public void includeJump(){ labelOfFor: for(;;){ a(); if(isFinished()){ break; //goto label0; } b(); } //label0:}void around():
region[call(* *.a());call(* *.b())] { proceed(); }
Support an around advice : jumps (solution)
Transform the bytecode– Share the ID for each
jump target– Jump to the tail of the
region– After region, check the
ID and jump
public void includeJump(){labelOfFor: for(;;){ a(); if(isFinished()){ $i=0; goto endLabel; } b(); endLabel: switch($i){ case 0: goto label0; } } label0:}
Applying to Javassist (coarse-grained)
Fixed Javassist’s synchronization problem using region pointcut
static WeakHashMap proxyCache;public Class createClass() { if (thisClass == null) { ClassLoader cl = …; if (useCache) createClass2(cl); else createClass3(cl); } return thisClass;}
void around(): region[ get(static boolean *.useCache); call(* *.createClass2(..)); ] { synchronized(ProxyFactory.class) { proceed(); } }
Applying to javassist (fine-grained)
void around():region[ call(* WeakHashMap.get(..)); call(* WeakHashMap.put(..));]{ synchronized( ProxyFactory.proxyCache){ proceed(); }}
static WeakHashMap proxyCache;private void createClass2(ClassLoader cl) { CacheKey key =…; HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl); if (cacheForTheLoader == null) { proxyCache.put(...); }else{...}
Related work
Tracematch [Allan et al. ’05]– History-based pointcut– Dynamic pattern matching with execution history
LoopsAJ [Harbulot et al. ’06]– Picking out loops
Conclusion
Region pointcut:– Picks out regions as join points– We extended abc
Solved some design issues to weave an around advice
Work in progress– Formalize the pattern matching semantics using
hedge automata– Case study