ASM Tree API:使用LDC加载Class <! - ? - >常量

时间:2015-12-31 19:05:34

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

我正在ASM中编写一个程序,它使用Tree API将字节码添加到某些方法中。我已经使用ASMifier来生成创建特定方法所需的代码,但是我遇到了以下问题:

mv.visitLdcInsn(Type.getType('L' + targetClassName + ';'));

我只是将mv初始化为new MethodNode,但不是加载Class,而是上述行在字节码中显示为:

ldc Lsome/test/TestClass; (org.objectweb.asm.Type)

如何让ASM加载java/lang/Class常量而不是org.objectweb.asm.Type常量?

如果相关,则下一行字节码为invokevirtual java/lang/Class getClassLoader(()Ljava/lang/ClassLoader;);

2 个答案:

答案 0 :(得分:3)

您的代码是正确的,但不是规范的解决方案。您可以将其简化为

mv.visitLdcInsn(Type.getObjectType(targetClassName));

(在ASM中,“对象类型”表示引用类型,另请参阅Type.getObjectType(…)the Type.OBJECT sort)。但是,结果是一样的。原因,为什么反汇编输出看起来像

ldc Lsome/test/TestClass; (org.objectweb.asm.Type)

在于反汇编程序。如果你看it’s code for converting an LDC instruction to a String

protected String printLdcInsnNode(LdcInsnNode ldc, ListIterator<?> it) {
    if (ldc.cst instanceof String)
        return nameOpcode(ldc.opcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")";

   return nameOpcode(ldc.opcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")";
}

您将看到它将打印存储在LdcInsnNode中的对象实例的类型,而不是代码最终将在运行时生成的类型。对于String,这就足够了,因为它是相同的类型,对于基元,它将打印相应的包装类型,但对于TypeHandle个对象,此反汇编程序将向您显示这些ASM特定的类而不是相应的运行时类java.lang.Classjava.lang.invoke.MethodTypejava.lang.invoke.MethodHandleldc指令将实际推送到操作数堆栈。

答案 1 :(得分:0)

我现在想出一个临时的解决方法。

mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false);