如何加载不同的原始数据到操作数栈

How to load different primitive datas to the operand stack

JVM有两条指令:bipush(操作数应该在Byte.MIN_VALUEByte.MAX_VALUE之间)和sipush(操作数应该在[=15=之间) ] 和 Short.MAX_VALUE)。相应的,ASM中的MethodVisitor提供了API来操作这两条指令:

      public void visitIntInsn(int opcode, int operand)

那么,如何访问ASM中的其他非字节(短)原语呢?比如原始的longdoubleintbooleanfloat数据?这些数据被包装为 LongDoubleInteger.

看起来很奇怪

布尔值只是 JVM 级别的整数。按 0 表示错误,按 1 表示正确。你不需要 bipush,你可以使用 iconst_0iconst_1.

Bytes、shorts、chars 和 int 也都只是 JVM 级别的 int。字节码中没有短原始类型的概念,只有t运行catation函数(i2c和co)。

如果你想压入int值111,你可以使用bipush 111。如果你想推送 1111,你可以使用 sipush 1111。如果你想推送 111111,你可以使用 ldc 111111。它们都只是字节码级别的整数。

对于浮点数、双精度数和多头数,在大多数情况下您必须使用 ldc* 系列指令。对于 0 或 1 常量的特殊情况,您可以改用 lconst_0dconst_1

您可以使用恰当命名的 MethodVisitor.visitLdcInsn 在 ASM 中创建 ldc 指令。

注意ldc需要常量池中space,限制为65534个槽。但是,它足够大,在实际情况下您永远不会 运行 出局。如果你真的想要,你可以在不使用常量池的情况下通过使用数学来构造值来推送更大的原始值。

例如int 111111可以由iconst_3 bipush 15 ishl sipush 12807 iadd生成。 Enjarify 有代码为每个原始类型执行此操作,甚至是双打,尽管出于显而易见的原因,它们通常需要更多的指令来表示。但是,如果您使用的是 ASM,您可能没有做任何不寻常和复杂到需要这种方法的事情。