1.加载存储指令

用于将数据在局部变量表和操作数栈之间出来会传输而已

例如从变量表加载到操作数栈

iload dload

从数栈加载到变量表

istore lstore

将常量加载到操作数栈

bipush sipush

2.基础的运算指令

对两个操作数栈上的值进行特定运算,然后在存入操作数栈中,

可以分为对整形进行运算和堆浮点数型进行运算

iadd ladd

isub等

但是记住一点,JVM虚拟机只有在除数为0的时候才会抛出ArithmeticException异常,任何整形数运算都不应该抛出运行时异常

所以对于出现的异常,我们需要进行专门的捕捉

对于浮点数型的计算,不许遵循在处理时候遵循IEEE 754规范中规定的行为和限制,也就是运算结果舍入到适当的精度,而且如果有两种可表示的形式与该值接近,优先选择有效位为0的,称为最接近数舍入模式

如果某个操作结果没有明确的数学定义,会将以NaN值来表示,所有的NaN作为操作数的算术操作,都会返回NaN

3.类型转换指令

Java支持安全类型转换

从小范围类型向大范围类型转换

int-> long float double等类型

long-> float,double类型

float -> double

也支持非安全类型转换,也就是向下转型

从 long-> int

这样的话,需要使用转换指令 i2b i2c

但是在转换过程中,产生不同的正负号,精度丢失

例如将int转为T的时候,简单的丢弃最低位N个字节外的内容,那么内容就是低于N个字节的内容

向下转型通常的规则为:

如果是Nan,则转换为0

如果不是无穷大,则进行调整取舍

不然转换为类型T中能表示的最大值或者最小值

4.对象创建或者访问指令

例如 创建类指令 new

创建数组指令 newArray anewarray

访问类字段 getfield getstatic

数组元素加载到数组栈中的指令 bload caload sload

将以操作数栈值存储到数组元素汇总的指令 bastore

去数组长度 arraylength

检查实例类型 instanceof

5.操作数栈管理指令

将操作数栈栈顶元素出站 pop pop2

复制栈顶元素重新入站 dup dup2 dup_x2

栈顶端两个数值互换 swap

6.方法调用及返回指令

常见的5种调用方式

invokevirtual 调用实例方法

invokeinterface 调用接口方法,可能是自动装配

invokespecial 调用初始化方法,例如构造器方法

invokedynaic,运行时候动态解析处调用点限定符所引用的方法

返回值常见的有

ireturn

areturn

7.异常处理

使用athorw完成,不是由字节码指令完成,而是采用异常表完成

抛出异常分为显式异常和隐式异常,显式抛的利用throw关键字,隐式抛则是利用了Java虚拟机的异常状态

包含三种代码块

try代码块,标记需要进行异常监控的代码

catch代码块,在try之后,捕获try代码块中触发的某些特定类型的异常,catch还能定义针对这个异常类型的异常处理器,一个try后可以跟着多个catch代码块,捕获不同的异常.

finally 声明一段必定运行的代码

异常实例的构造很昂贵,在构造异常实例的时候,虚拟机生成该异常的栈轨迹,会逐一的访问当前线程的Java栈帧,记录下各种调试信息

每个方法带有一个异常表

一个条目代表着一个异常处理器,从from指针,to指针,target指针和被捕获的异常类型构成

from和to说明了 try 覆盖的范围,target说明catch的起始范围

而最后的finally的代码块位置,则是被复制分别放在了正常执行路径和异常执行路径的出口处

如果一个方法遍历完所有异常表条目,Java虚拟机没有匹配到异常处理器,会弹出当前方法的栈帧,然后遍历上层栈帧,最坏情况,Java虚拟机需要遍历当前线程Java栈上所有的异常表

图片

Suppressed机制可以将一个异常附在另一个异常之上,抛出的异常可以附带多个异常的信息

但是因为finally中缺少对异常信息的引用,所以并不好使

8.同步指令

在很多版本采用的信号量完成的,但在Java中,采用管程实现的

实现于方法调用和返回操作汇总

通过方法表中的ACC_SYNCHRONIZED访问标志是否设置来表示

如果设置了,需要执行线程先获取到管程

关于JAVA虚拟机的指令集中,有monitornter和monitorexit两条指令来支持synchronized关键字语义

发表评论

邮箱地址不会被公开。 必填项已用*标注