ASMではVisitorパターンを使って、バイトコードを生成したり変更したりする。コンパイル後のクラスファイル群は、クラスがあったりメソッドがあったりアノテーションが付いていたりと複雑なツリー状の構造をしているので、ツリーの中のどの要素をどう操作するかを記述していくことになる。
Visitorパターンでは複数の要素を巡って処理するものだが、ASMではVisitorクラスのコンストラクタに別のVisitorオブジェクトを登録するところがポイント。インスタンスを作る時にVisitor1→Visitor2→Visitor3のようにVisitor同士を一方向に繋げるようになっている。ClassReaderやClassWriterのような入出力もVisitorでできているので、既存のクラスファイルを読み込んで、複数箇所を変換して、出力するという一連のバイトコード操作の処理フローを作ることができる。
MethodVisitorの場合、プログラマーの責任において次の順番で呼びだすことが定められている。
visitAnnotationDefault?
( visitAnnotation | visitParameterAnnotation | visitAttribute )*
( visitCode
( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn | visitLocalVariable | visitLineNumber )*
visitMaxs )? visitEnd
ややこしいことに、ClassWriterで出力するためには、フレームとローカル変数、オペランドスタックのサイズを計算する必要がある。ASMに自動計算させることもできるが10%〜2倍程度遅くなる。new ClassWriter(ClassWriter.COMPUTE_FRAMES)を指定してもvisitMaxs()メソッドの呼び出しは省略できないことに注意。引数は無視されるのでvisitMaxs(0,0)でOK。
( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn | visitLocalVariable | visitLineNumber )*
visitMaxs )? visitEnd
ややこしいことに、ClassWriterで出力するためには、フレームとローカル変数、オペランドスタックのサイズを計算する必要がある。ASMに自動計算させることもできるが10%〜2倍程度遅くなる。new ClassWriter(ClassWriter.COMPUTE_FRAMES)を指定してもvisitMaxs()メソッドの呼び出しは省略できないことに注意。引数は無視されるのでvisitMaxs(0,0)でOK。
0 件のコメント:
コメントを投稿