ASM 树 API:使用 LDC 加载一个 Class<?> 常量
ASM Tree API: Using LDC to load a Class<?> constant
我正在用 ASM 编写一个程序,它使用树 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;);
我现在想出了一个临时解决方法。
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);
您的代码是正确的,但不是规范的解决方案。您可以将其简化为
mv.visitLdcInsn(Type.getObjectType(targetClassName));
(在 ASM 中,“对象类型”表示引用类型,另请参见 Type.getObjectType(…)
and 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
,这就足够了,因为它是同一类型,对于原始类型,它将打印相应的包装器类型,但是对于 Type
或 Handle
对象,此反汇编程序将向您显示这些 ASM具体 类 而不是相应的运行时 类 java.lang.Class
、java.lang.invoke.MethodType
或 java.lang.invoke.MethodHandle
,ldc
指令实际上会将其压入操作数堆栈。
我正在用 ASM 编写一个程序,它使用树 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;);
我现在想出了一个临时解决方法。
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);
您的代码是正确的,但不是规范的解决方案。您可以将其简化为
mv.visitLdcInsn(Type.getObjectType(targetClassName));
(在 ASM 中,“对象类型”表示引用类型,另请参见 Type.getObjectType(…)
and 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
,这就足够了,因为它是同一类型,对于原始类型,它将打印相应的包装器类型,但是对于 Type
或 Handle
对象,此反汇编程序将向您显示这些 ASM具体 类 而不是相应的运行时 类 java.lang.Class
、java.lang.invoke.MethodType
或 java.lang.invoke.MethodHandle
,ldc
指令实际上会将其压入操作数堆栈。