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

时间:2015-10-17 16:34:52

标签: jvm bytecode java-bytecode-asm vm-implementation

JVM有两条指令:bipush(操作数值应介于Byte.MIN_VALUEByte.MAX_VALUE之间。)和sipush(操作数值应介于Short.MIN_VALUE之间Short.MAX_VALUE)。相应地,ASM中的MethodVisitor提供API来操作这两个指令:

      public void visitIntInsn(int opcode, int operand)

因此,如何访问ASM中的其他非字节(短)基元?例如,原始longdoubleintbooleanfloat数据?看起来很奇怪这些数据包含在LongDoubleInteger

1 个答案:

答案 0 :(得分:5)

布尔值只是JVM级别的整数。将0推送为false,将1推送为true。您不需要使用bipush,只需使用iconst_0iconst_1

字节,短路,字符和整数也都是JVM级别的内容。字节码中没有短基元类型的概念,只有截断函数(i2c和co)。

如果要推送int值111,可以使用bipush 111。如果你想推1111,你会使用sipush 1111。如果要推送111111,则使用ldc 111111。它们都只是字节码级别的内容。

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

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

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

例如,int {11}可以由iconst_3 bipush 15 ishl sipush 12807 iadd生成。 Enjarify有代码为每个主要类型执行此操作,甚至是双倍,尽管他们通常需要更多指令来表示,原因很明显。但是,如果你正在使用ASM,那么你可能没有做任何不寻常和复杂的事情来要求这种方法。