Jvm 如何将不同的基元数据加载到操作数堆栈
JVM有两条指令:Jvm 如何将不同的基元数据加载到操作数堆栈,jvm,bytecode,java-bytecode-asm,vm-implementation,Jvm,Bytecode,Java Bytecode Asm,Vm Implementation,JVM有两条指令:bipush(操作数值应介于Byte.MIN\u值和Byte.MAX\u值)和sipush(操作数值应介于Short.MIN\u值和Short.MAX\u值之间)。相应地,ASM中的MethodVisitor提供了操作这两条指令的API: public void visitIntInsn(int opcode, int operand) 因此,如何访问ASM中的其他非字节(短)原语?例如,原语long、double、int、boolean和float数据?看起来很
bipush
(操作数值应介于Byte.MIN\u值
和Byte.MAX\u值
)和sipush
(操作数值应介于Short.MIN\u值
和Short.MAX\u值
之间)。相应地,ASM中的MethodVisitor
提供了操作这两条指令的API:
public void visitIntInsn(int opcode, int operand)
因此,如何访问ASM中的其他非字节(短)原语?例如,原语
long
、double
、int
、boolean
和float
数据?看起来很奇怪,这些数据被包装为Long
,Double
,Integer
,布尔值只是JVM级别的整数。按0表示错误,按1表示正确。您不需要使用bipush,只需使用iconst_0
和iconst_1
字节、短字符、字符和整数在JVM级别也是整数。字节码中没有短基元类型的概念,只有截断函数(i2c
和co)
如果要推送int值111,可以使用bipush 111
。如果要按1111,可以使用sipush 1111
。如果要按111111,可以使用ldc 111111
。它们都只是字节码级别的整数
对于浮点、双精度和长精度,在大多数情况下必须使用ldc*
指令系列。对于0或1常量的特殊情况,可以改用lconst_0
、dconst_1
等
您可以在ASM中使用适当命名的创建ldc
指令
请注意,ldc
需要常量池中的空间,该池限制为65534个插槽。然而,它足够大,在实际情况下你永远不会用完。如果确实需要,可以通过使用数学构造值来推送较大的原语值,而无需使用常量池
例如,int 111111可以由iconst_3 bipush 15 ishl sipush 12807 iadd生成。Enjarify为每种灵长类动物都编写了这样的代码,即使是双倍的,尽管出于明显的原因,它们通常需要更多的指令来表示。但是,如果您使用的是ASM,那么您可能没有做任何不寻常和复杂到需要这种方法的事情。布尔值只是JVM级别的整数。按0表示错误,按1表示正确。您不需要使用bipush,只需使用
iconst_0
和iconst_1
字节、短字符、字符和整数在JVM级别也是整数。字节码中没有短基元类型的概念,只有截断函数(i2c
和co)
如果要推送int值111,可以使用bipush 111
。如果要按1111,可以使用sipush 1111
。如果要按111111,可以使用ldc 111111
。它们都只是字节码级别的整数
对于浮点、双精度和长精度,在大多数情况下必须使用ldc*
指令系列。对于0或1常量的特殊情况,可以改用lconst_0
、dconst_1
等
您可以在ASM中使用适当命名的创建ldc
指令
请注意,ldc
需要常量池中的空间,该池限制为65534个插槽。然而,它足够大,在实际情况下你永远不会用完。如果确实需要,可以通过使用数学构造值来推送较大的原语值,而无需使用常量池
例如,int 111111可以由iconst_3 bipush 15 ishl sipush 12807 iadd生成。Enjarify为每种灵长类动物都编写了这样的代码,即使是双倍的,尽管出于明显的原因,它们通常需要更多的指令来表示。但是,如果您使用的是ASM,您可能没有做任何异常和复杂到需要这种方法的事情。请注意,在ASM中,
push(0)
或push(false)
将自动生成iconst\u 0
指令,而不是bipush 0
,因此,您的抽象级别稍微高一点。我不会将复杂的指令序列用于111111
,尤其是因为它不小于常量池中所需的空间。但是,使用类似于iconst_5,i2l
的方法来推动long
常量5L
是合理的,imho.@Holger,这是专门针对常量池中空间耗尽的情况。正如我所说,这不是一种正常的情况。我想,如果您用完了常量池项的最大数量,您可能会达到其他限制,例如最大代码大小或最大方法数。但另一方面,将int常量扩展为long或double是合理的,如iconst\n;i2l
或iconst;i2d不仅在常量池中保存九个字节,在实际方法的代码中甚至保存一个字节。即使使用bipush n,i2…
,与等效的ldc2\u w
指令具有相同的代码大小(同时仍将九个字节保存在池中)…请注意,在ASM中,push(0)
或push(false)
将自动生成iconst\u 0
指令,而不是bipush 0
,因此,您的抽象级别稍微高一点。我不会将复杂的指令序列用于111111
,尤其是因为它不小于常量池中所需的空间。但是,使用类似于iconst_5,i2l
的方法来推动long
常量5L
是合理的,imho.@Holger,这是专门针对常量池中空间耗尽的情况。就像我说的,这不是一个正常的现象。我想,如果你用完了最大数量的固定池项目,你会