私は比較的単純なことをしようとしていると思います。メソッド doSomething(int) の次の Java バイトコードを例にとります。
public java.lang.String doSomething(int i);
0 iload_1 [i]
1 invokestatic MyHelper.doSomething(int) : Java.lang.String
4 areturn
このバイトコードは、呼び出しを静的ヘルパーに転送するだけです。
私が今やりたいことは、Javassist を使用して、invokestatic を invokedynamic に置き換えることです。私はASMでこれを行う方法を知っているので、純粋な好奇心のためにそれがどのように機能するかを知りたいと思っていると仮定してください. ここに私が持っているいくつかの質問があります:
1) 次は正しいですか: javassist の CtMethod.instrument() メソッドまたは CtMethod.insertAt() メソッドを使用できません。これらのメソッドは、有効な Java 式を含む文字列を想定しており、Java 構文で invokedynamic を記述できないためです。
2) invokestatic へのパラメーターは、invokevirtual または invokestatic のパラメーターと同じように処理されますよね? つまり、invokevirtual の場合と同じように、invokedynamic の前にパラメーターをスタックに配置しますか?
3) Javassistを使用してinvokedynamicバイトコードを作成するサンプルコードはありますか?
これは私がこれまでに知っていることです: addInvokedynamic() メソッドを持つ Bytecode オブジェクトを作成できます。ただし、これは BootstrapMethodsAttribute 内の BootstrapMethod のインデックスを想定しています。次に、BootstrapMethod は、メソッド参照などを必要とする定数プール内のメソッド ハンドル情報のインデックスを期待します。したがって、基本的には、定数プール エントリ全体を自分で管理する必要があります。これは問題ありませんが、正しく理解できず、後で奇妙な問題が発生するのではないかと心配しています。これを行う簡単な方法 (ヘルパー メソッドなど) はありますか? 私が持っているコードは大まかに次のようになります(上記のinvokestaticを実際に「書き直す」わけではありませんが:
void transform(CtMethod ctmethod, String originalCallDescriptor) {
MethodInfo mInfo = ctmethod.getMethodInfo();
ConstPool pool = ctmethod.getDeclaringClass().getClassFile().getConstPool();
/* add info about the static bootstrap method to the constant pool*/
int mRefIdx = /*somehow create a method reference entry*/
int mHandleIdx = constPool.addMethodHandleInfo(ConstPool.REF_invokeStatic, mRefIdx);
/* create bootstrap methods attribute; there can only be one per class file! */
BootstrapMethodsAttribute.BootstrapMethod[] bms = new BootstrapMethodsAttribute.BootstrapMethod[] {
new BootstrapMethodsAttribute.BootstrapMethod(mHandleIdx, new int[] {})
};
BootstrapMethodsAttribute bmsAttribute = new BootstrapMethodsAttribute(constPool, bms);
mInfo.addAttribute(bmsAttribute);
//... and then later, finally
Bytecode bc = new Bytecode(constPool);
... push parameters ...
bc.addInvokedynamic(0 /*index in bms array*/, mInfo.getName(), originalCallDescriptor);
//replace the original method body with the one containing invokedynamic
mInfo.removeCodeAttribute();
mInfo.setCodeAttribute(bc.toCodeAttribute());
}
あなたの助けと時間をありがとう!