私の目標は、コードの各基本ブロックの先頭に少しのインストルメンテーション コードを挿入することです。Javaassist の ControlFlow.Block と CtMethod.insertAt() を使用すると、かなり単純なタスクのように見えます。これまでのところ、関連するコードのチャンクは次のとおりです (変換関数にあります)。
ControlFlow flow=new ControlFlow(m); //m is the CtMethod currently being instrumented
Block[] blockArray=flow.basicBlocks();
for(Block thisbb : blockArray){
//Dynamically Update Method Statistics
String blockUpdate=new String();
String thisbbIndex=Integer.toString(thisbb.index());
blockUpdate+=mse+".setBlockIndex("+thisbbIndex+"); ";
blockUpdate="{ " + blockUpdate + "} ";
//Insert
int pos=m.getMethodInfo().getLineNumber(thisbb.position()); //Source code line position from binary line position
System.out.print("At "+pos+": "+blockUpdate);
int n=m.insertAt(pos, blockUpdate);
System.out.println(" -> "+n);
}
の「line」パラメータCtMethod.insertAt(line,srcCode)
は、バイトコードの行位置ではなく、ソース コードの行位置であることに注意してください。ソース コードでは、いくつかの基本ブロックが同じ行番号を報告しています。出力は次のとおりです。
At 6: { _JDA_mse.setBlockIndex(0); } -> 6
At 8: { _JDA_mse.setBlockIndex(1); } -> 8
At 8: { _JDA_mse.setBlockIndex(2); } -> 8
At 8: { _JDA_mse.setBlockIndex(3); } -> 8
At 8: { _JDA_mse.setBlockIndex(4); } -> 8
At 8: { _JDA_mse.setBlockIndex(5); } -> 8
At 8: { _JDA_mse.setBlockIndex(6); } -> 8
At #
はコードを配置するように要求した場所を-> #
表し、 は実際に挿入されたソース コード内の場所を表します (すべてがうまくいけば、それらは同じになるはずです)。内のすべてが{ ... }
配置したいコードです (_JDA_mse
は Javassist メソッドを使用して関数に追加したローカル変数なので、使用しても問題ありません)。
問題はfor(int i=0; i<size; ++i)
、ソース コードでは分離できないが、バイトコードでは明確に区別される複数の基本ブロックが含まれていることです。これが、複数の基本ブロックが同じソース行にマップされている理由であり、ソース コード行が基本ブロックを記録するのに十分な計測精度を提供していないことを示しています。 提供された CtMethod.insertAt(sourceLine,srcString) を使用する代わりに、CtMethod.insertAt(bytecodePosition,srcString) をエミュレートする方法はありますか?