JVM字节代码指令

字节代码指令由一个标识该指令的操作码和固定数目的参数组成:

  • 操作码是一个无符号字节值——即字节代码名,由助记符号标识。例如,操作码 0 用助 记符号 NOP 表示,对应于不做任何操作的指令。
  • 参数是静态值,确定了精确的指令行为。它们紧跟在操作码之后给出。比如GOTO标记 指令(其操作码的值为 167)以一个指明下一条待执行指令的标记作为参数标记。不要 将指令参数与指令操作数相混淆:参数值是静态已知的,存储在编译后的代码中,而 操作数值来自操作数栈,只有到运行时才能知道。

 

字节代码指令可以分为两类:一小组指令,设计用来在局部变量和操作数栈之间传送值;其 他一些指令仅用于操作数栈:它们从栈中弹出一些值,根据这些值计算一个结果,并将它压回栈 中。

 

ILOAD, LLOAD, FLOAD, DLOAD ALOAD 指令读取一个局部变量,并将它的值压到操 作数栈中。它们的参数是必须读取的局部变量的索引 iILOAD 用于加载一个 booleanbytecharshort int 局部变量。LLOADFLOAD DLOAD 分别用于加载 longfloat double 值。(LLOAD DLOAD 实际加载两个槽 i i+1)。最后,ALOAD 用于加载任意非基元值,即对 象和数组引用。与之对应,ISTORELSTOREFSTOREDSTORE ASTORE 指令从操作数栈 中弹出一个值,并将它存储在由其索引 i 指定的局部变量中。

 

可以看到,xLOAD xSTORE 指令被赋入了类型(事实上,下面将要看出,几乎所有指令 都被赋予了类型)。它用于确保不会执行非法转换。实际上,将一个值存储在局部变量中,然后 再以不同类型加载它,是非法的。例如,ISTORE 1 ALOAD 1 序列是非法的——它允许将一个 任意内存位置存储在局部变量 1 中,并将这个地址转换为对象引用!但是,如果向一个局部变 量中存储一个值,而这个值的类型不同于该局部变量中存储的当前值,却是完全合法的。这意味 着一个局部变量的类型,即这个局部变量中所存值的类型可以在方法执行期间发生变化。

 

上面已经说过,所有其他字节代码指令都仅对操作数栈有效。它们可以划分为以下类别(见 附件 A.1):

 

这些指令用于处理栈上的值:POP弹出栈顶部的值,DUP压入顶部栈值的一个副本, SWAP 弹出两个值,并按逆序压入它们,等等。

 

常量 这些指令在操作数栈压入一个常量值:ACONST_NULL压入nullICONST_0压入 int 值 0,FCONST_0 压入 0fDCONST_0 压入 0dBIPUSH b 压入字节值 bSIPUSH s 压入 short sLDC cst 压入任意 intfloatlongdoubleString class1 常量 cst,等等。

 

算术与逻辑 这些指令从操作数栈弹出数值,合并它们,并将结果压入栈中。它们没有任何 参数。xADDxSUBxMULxDIV xREM 对应于+-*/%运算,其中 x ILF D 之一。类似地,还有其他对应于<<>>>>>|&^运算的指令,用于 处理intlong值。

 

类型变换 这些指令从栈中弹出一个值,将其转换为另一类型,并将结果压入栈中。它们对 应于 Java 中的类型转换表达式。I2F, F2D, L2D 等将数值由一种数值类型转换为另一种 类型。CHECKCAST t 将一个引用值转换为类型 t

 

对象 这些指令用于创建对象、锁定它们、检测它们的类型,等等。例如,NEWtype指令将 一个 type 类型的新对象压入栈中(其中 type 是一个内部名)。

 

字段 这些指令读或写一个字段的值。GETFIELD owner name desc 弹出一个对象引用,并 压和其 name 字段中的值。PUTFIELD owner name desc 弹出一个值和一个对象引用,并 将这个值存储在它的 name 字段中。在这两种情况下,该对象都必须是 owner 类型,它 的字段必须为 desc 类型。GETSTATIC PUTSTATIC 是类似指令,但用于静态字段。

 

方法 这些指令调用一个方法或一个构造器。它们弹出值的个数等于其方法参数个数加 1 (用于目标对象),并压回方法调用的结果。INVOKEVIRTUAL owner name desc 调用在 类 owner 中定义的 name 方法,其方法􏰂述符为 descINVOKESTATIC 用于静态方法, INVOKESPECIAL 用于私有方法和构造器,INVOKEINTERFACE 用于接口中定义的方 法。最后,对于 Java 7 中的类,INVOKEDYNAMIC 用于新动态方法调用机制。

 

数组 这些指令用于读写数组中的值。xALOAD指令弹出一个索引和一个数组,并压入此索 引处数组元素的值。xASTORE 指令弹出一个值、一个索引和一个数组,并将这个值存 储在该数组的这一索引处。这里的 x 可以是 ILFD A,还可以是 BC S

 

跳转 这些指令无条件地或者在某一条件为真时跳转到一条任意指令。它们用于编译iffordowhilebreak continue 指令。例如,IFEQ label 从栈中弹出一个 int 值,如果这个值为 0,则跳转到由这个 label 指定的指令处(否则,正常执行下一 条指令)。还有许多其他跳转指令,比如 IFNE IFGE。最后,TABLESWITCH

LOOKUPSWITCH 对应于 switch Java 指令。

 

返回 最后,xRETURNRETURN指令用于终止一个方法的执行,并将其结果返回给调用 者。RETURN 用于返回 void 的方法,xRETURN 用于其他方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值