2

他の人が作成したバイトコードを変更するためにASM ライブラリを使用しています。LdcInsnNode任意のクラスの任意のメソッドについて、現在のクラスをスタックに追加するを作成したいと思います。

たとえば、 というクラスを変換するとしcom.example.ExampleClassます。に相当するバイトコードを作成したいと思いますSystem.out.println(ExampleClass.class.getName());

これは比較的単純な作業のようです。Eclipse Bytecode Outline プラグインを使用すると、次のバイトコードが同等であると表示されます。

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC Lcom/example/ExampleClass;.class
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V

次のコードを試しました:

private InsnList printClass() {
    InsnList result = new InsnList();
    result.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
    result.add(new LdcInsnNode("L" + name + ";.class"));
    result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false));
    result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false));
    return result;
}

これは の拡張機能で実行されているClassNodeため、フィールドnameを参照してください。ClassNode.nameこのInsnListメソッドによって返された は、既存のAbstractInsnNodeusingの前に挿入されていInsnList.insertBefore(AbstractInsnNode, printClass())ます。バイトコードがこのポイントに到達すると、次の理由でエラーが発生します。

Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'java/lang/Class'

これは明らかに、LDC 命令が"Lcom/example/ExampleClass;.class"実際のクラスではなく文字列を追加しているためLcom/example/ExampleClass;.classです。

これに対する回避策はありますか? クラスがまだ存在しないため、Classオブジェクトを anに直接追加することは不可能のようです。しかし、オブジェクトLdcInsnNodeをロードする命令を追加する方法はありますか?Class

Object.getClass()私の特定のケースでは、静的コンテキストから動作する必要があるため、メソッドを呼び出すことはオプションではありません。

4

1 に答える 1

2

オブジェクトを参照する必要はありませんClass。実際、(直接) サポートされていません。ClassASM 経由でオペランド スタックにプッシュする場合は、Typeインスタンスとして参照する必要があります。

例えば

new LdcInsnNode(Type.getObjectType(name))

内部名フォームを表すType.getObjectType(…)ことを期待する factory メソッドを使用します。非配列型と同等です。オブジェクトはプリミティブ型またはメソッド型も表す場合があるため、ファクトリ メソッドの選択は重要です。とはどちらも参照型のみをサポートするため、これは自然な組み合わせです。namecom/example/ExampleClassL … ;Type.getType('L'+name+';')TypeldcType.getObjectType

LdcInsnNodeコンストラクターのドキュメントは、数値型とString( Java 5 以降のClassサポートがldc存在しますが、ドキュメントには 1.4.2 へのリンクが含まれています)しか言及されていないため、少し古くなっているようです。MethodVisitor.visitLdcInsn(…)代わりに、バイトコードを生成するときにオブジェクトが最終的に渡される を参照できます。

于 2016-11-15T15:41:09.393 に答える