1

invokedynamicASM を使用して命令を生成するための次のコードを考えてみましょう。

// BOOTSTRAP = new Handle(->
// CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType methodType, Class<?> someClass)

mv.visitInvokeDynamicInsn("foo", "(I)I", BOOTSTRAP, Type.INT_TYPE);

生成されたクラスをASMifierで逆コンパイルすると該当行が

mv.visitInvokeDynamicInsn("foo", "(I)I", new Handle(/* SNIP (same as BOOTSTRAP) */),
                          Type.getType("LI;"));
                                       ¯¯¯¯¯

ご覧のとおり、Type.INT_TYPEは という名前の参照型へのリテラル参照に変わりましたI。これが存在しないため、JVM は実行時にjava.lang.BootstrapMethodError: java.lang.NoClassDefFoundError: I.

私が代わりにやりたかったのは、 int.class(Classプリミティブ型のインスタンスint、またはInteger.TYPE定数の値)bootstrapの引数としてメソッドに渡すことでしたsomeClass。ただし、ASM はこれを適切に理解またはサポートしていないようです。

これは ASM のバグと見なすことができますか? また、回避策はありますか?

4

2 に答える 2

2

Brett Kail が指摘したようClassに、プリミティブ型の定数をエンコードすることは不可能です。ソース コードのようにリテラルを使用すると、コンパイラはそれを目的のオブジェクトを含むint.classフィールドの読み取り操作としてエンコードします。アノテーションの場合、アノテーション値は ではなく戻り記述子を含むを指すようにエンコードされるため、可能です( JVM 仕様 §4.7.16.1を参照)。java.lang.Integer.TYPEClassCONSTANT_Utf8_infoCONSTANT_Class_info

ブートストラップ メソッドへのエンコードされた静的引数では、Classオブジェクトを としてエンコードする必要があるCONSTANT_Class_infoため、プリミティブ型はサポートされません。JVM 仕様 §4.7.23を参照してください。

bootstrap_arguments 配列の各エントリは、constant_pool テーブルへの有効なインデックスである必要があります。そのインデックスの constant_pool エントリは、、、、、、、、または構造体である必要がありますCONSTANT_String_info… < / p > CONSTANT_Class_infoCONSTANT_Integer_infoCONSTANT_Long_infoCONSTANT_Float_infoCONSTANT_Double_infoCONSTANT_MethodHandle_infoCONSTANT_MethodType_info

回避策は、規則を追加することです。たとえば、常に目的の型の配列型をエンコードし、ブートストラップ メソッドで要素型を抽出します。または、目的の型を a の戻り値の型としてエンコードしますCONSTANT_MethodType_info。後者には、 をサポートするという利点もありvoid.classます。

于 2016-08-22T14:29:14.807 に答える