如何创建一个静态将当前类添加到堆栈的ASM LdcInsnNode?

时间:2016-11-15 07:38:15

标签: java java-bytecode-asm bytecode-manipulation jvm-bytecode

我正在使用ASM library修改其他人创建的字节码。对于任意类中的任意方法,我想创建一个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在现有AbstractInsnNode之前插入此方法返回的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对象直接添加到LdcInsnNode似乎是不可能的,因为该类尚不存在。但是有没有办法添加一个加载Class对象的指令?

在我的特定情况下,调用Object.getClass()方法不是一个选项,因为它需要在静态上下文中工作。

1 个答案:

答案 0 :(得分:2)

您不需要引用Class对象,事实上,它甚至不支持(直接)。如果要通过ASM将Class推送到操作数堆栈,则必须将其称为Type实例。

E.g。

new LdcInsnNode(Type.getObjectType(name))

使用Type.getObjectType(…)工厂方法,该方法希望name代表内部名称格式,例如com/example/ExampleClass周围没有L … ;。对于非数组类型,它等效于Type.getType('L'+name+';')。工厂方法的选择很重要,因为Type对象也可以表示基本类型或方法类型。由于ldcType.getObjectType都只支持引用类型,因此这是自然组合。

似乎LdcInsnNode constructor documentation有点过时了,因为它只提到了数字类型,自{5}以来String Class支持ldc,但文档包含链接到1.4.2)。您可以参考MethodVisitor.visitLdcInsn(…)代替,在生成字节代码时最终将对象传递给该对象。