An Extension of AspectJ to Weave Aspect into an Arbitrary Code Region 赤井駿平 08M37025 千葉研究室 1 目的:同期の粒度を切り替えたい ライブラリが2種類の同期を提供: – – – 2 高並列性 低オーバーヘッド ライブラリのユーザが最適な粒度を選ぶ – 細かい粒度の同期 粗い粒度の同期 ライブラリ 環境に応じて 良い性能 粗い同期 同期のコードの付替が容易でなければな らない – アスペクトを利用してはどうか? 細かい同 期 Motivation: ライブラリにおける同期処理 2006年にJavassistに 対してバグレポート – Not thread-safe! 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(…); HashMap cacheForTheLoader =…; if (cacheForTheLoader == null) { cacheForTheLoader = new HashMap(); proxyCache.put(cl, cacheForTheLoader); cacheForTheLoader.put(key, key); }else {...} 単純な修正は簡単 – synchronized文を追加 Class c = isValidEntry(key); if (c == null) { createClass3(cl); key.proxyClass = new WeakReference(…); }else{thisClass = c;} 3 }} 修正によるパフォーマンスへの影響 synchronized文の付け方 が問題 – 細かい粒度 – 粗い粒度 4 高い並列性 オーバーヘッドが多い 並列性が低い 少コアのマシンでは早い public class ProxyFactory { public Class createClass() { Coarse-grained if (thisClass == null) { ClassLoader cl = getClassLoader(); synchronized (proxyCache) { if (useCache){createClass2(cl);} else {createClass3(cl);} }} return thisClass;} Fine-grained 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;} }}} アスペクト指向で同期を切り替えたい 横断的関心事をモジュール化 – – – advice join point: プログラム実行中の実行点(メソッド呼び出し, フィールドアクセス…) pointcut: join point を選ぶ手段 advice: 選択したjoin point で実行するコード pointcut void around (): call(* *.foo()) {bar(); proceed() ;} 5 public String toString(){ foo(); return …; } call join point アスペクト指向で同期を切り替えたい 領域に対して around adviceを 織り込みたい void around (): pointcut(coarse_grained_region) { synchronized(…) { proceed(); } } 6 void around (): pointcut(fine_grained_regions) { synchronized(…) { proceed(); } } 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;} }}} Our Proposal Regioncut – 領域を選択する指定子 void around(): region[ call(* Map.get(..)), call(* Map.put(..)) ] { …; proceed(); …;} Assertion for Advice – – 7 fragile性 の問題を解決するため 指定したアドバイスが織り込まれていないと警告 @AssertAdvised(“lock_map”) void foo(){ … } @SolveProblem(“Foo.lock_map”) void around(): … { … } AspectJでは実現不可 Pointcutは領域を選択できない execution “point”のみ選択可能 – – – Call: メソッド呼び出しを選択 Get, set: フィールドアクセスを選択 Execution: メソッドボディを選択 8 around advice を使えばメソッドボディ全体は同期可能 メソッドボディが最適な粒度とは限らない→リファクタリング が必要 全ての粒度の同期の箇所をメソッドに抽出するのは大変 なぜAspectJは同期/領域を扱えないか Fragile性を減らせない – コードが変更されると選択できなくなる可能性 – 同期は必須の関心事 9 領域にはpointcut より指定に多くの情報が必要 pointcut より変更に弱い 同期アスペクトを織り込み忘れると正しく動かない AspectJでは織り込み忘れを発見できない Our Proposal: Regioncut 新しいポイントカット指定子のようなもの – 領域を選択 領域を指定するには – 領域内のexecution pointの中で重要なものを列挙 call, get, set, が使える 選択したい典型的な領域はそれで指定できる region[ call(* Map.get(..)), call(Object nextValue(Object)), call(* Map.put(..)) ] 10 void foo(Map map){ Object o=map.get(key); println(o); o=nextValue(o); map.put(key,o);} 領域の拡大 領域と制御構造が衝突 – void foo(Map map){ around advice を織り込 めない … Object o=map.get(key); 領域を拡大: – – – Conflict println(o); o=nextValue(o); 元の領域を含み 制御構造を含み かつできるだけ小さく if(…){ map.put(key,o); … } … 11 } Expanded Our Proposal: Assertion for Advice Fragile性を 減らすため 織り込まれなくなったアドバイスを見つけて警告 – @AssertAdvised(“<concern_name>”) – adviceが必要なメソッドに付加.関心事の名前を付ける @SolveProblem(“<ClassName>.<concern_name>”) 対象の関心事を解決するadviceに付加 class Foo{ @AssertAdvised(“lock_map”) void foo(Map map){ … 12 } } @SolveProblem(“Foo.lock_map”) void around(): region[ … ]{ synchronize(…){ proceed(); } } Assertion for Advice チェッカー @AssertAdviced の付 いたメソッドが対応する adviceを持つかチェック 以下の場合警告なし: – – 13 adviceがメソッドを呼ん でいる メソッドがadviceを呼ん でいる 間接的にでもOK @SolveProblem(“Foo.lock_map”) void around(): … { … } Call the method @AssertAdvised(“lock_map”) void foo(){ … } Call the advice @SolveProblem(“Foo.lock_map”) void around(): … { … } 2つのチェッカーを開発 静的なチェッカー – – – クラスファイルを解析 コールグラフを調べる 制限 動的なチェッカー – – 14 リフレクションに対応できない 実行時に(呼び出した|呼ばれた)かを調べる 実際に実行された部分のみチェック可能 Implementation the AspectBench Compiler (abc)を拡張 – Regioncut – Assertion for Advice – 15 中間言語Jimpleを解析/変換 dynamic: ASTを変換してダイナミックにチェック static: Sootを利用 10,000+ LOC Implementation Issue(1/2): Around advice abc で around adviceを織り込む場合 – – join points/regions を抽出しメソッドに分ける 問題 ローカル変数を共有できない 領域の外へジャンプできない public void toBeAdvised(int x){ a(); b(x); advice(x); c(); } 16 public static void advice(int x){ beforeJoinPoint(); shadow(x); afterJoinPoint(); } public static shadow(int x){ a(); b(x); c(); } Implementation Issue(2/2): 解決法 ローカル変数を保存するオブジェクト – 引数経由で共有して対処 ジャンプ先を示す値を変数に入れて共有 – 領域を抜けてからジャンプするように変換 share public void toBeAdvised(int x){ advice(x); } 17 public static void advice(Obj o){ beforeJoinPoint(); shadow(x); afterJoinPoint(); } { int x; int jmpTgt; } public static shadow(Obj o){ a(); b(x); c(); } 評価: regioncutの記述力 Hadoopのsynchronized文をアスペクトに分離 – – – – regioncutが領域を十分に選択できるかを評価 Hadoop 0.16.4 通常のpointcutで選択できなかったものは全て選択できた 12の内の8領域が拡大が必要 Synchronized 文 通常のpointcutで選択された regioncutで選択された 18 21 9 12 評価: Assertion が有効に働くか Hadoop を 0.16.4 から 0.18.3 に更新 – – dynamic版を使用 Hadoopの ユニットテストを動か してチェック 19 6個が正しく織り込まれなかっ た 2個は検知 残りは実行されていなかったの で検知不可 旧バージョンでのregioncut 12 正しく織り込まれた 6 assertionで検出された 2 検出されなかった 4 Current Limitation 選択した2つ以上の領域が重なると – – around adviceをweaveできない 何らかの優先順位を付ける必要がある void withConflict(){ beginA(); beginB(); endA(); endB(); } 20 Related Work 領域へのpointcutは重要な問題 限定的な解 – – Loop join point: ループボディにマッチ Synchronized join point: synchronized文にマッチ 同等の解 – Transactional pointcut 21 同じ会議で同時にaccept Conclusion アスペクト指向言語で領域を選択を実現 – – Regioncut Assertion for advice これまでの成果 – 査読付き – 査読なし/ワークショップ 22 GPCE'09, 2009-10, Denver ソフトウェア科学会大会,2008-07,東京 ACP4IS’09, 2009-03, Charlottesville
© Copyright 2024 ExpyDoc