深入了解JAVA技术(8)字节码指令有知道的嘛

字节码指令:Java虚拟机的指令由一个字度长度的,代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随气候的零之多个代表此操作所需参数而构成。Java虚拟机采用面向操作数栈而不是寄存器的架构,大部分的指令都不包含操作数,只有一个操作码。
字节码指令集:是由多个字节码指令组成集,是一种指令集架构。
缺点:字节码指令集限制了Java虚拟机操作码的长度为一个字节,意味着指令集的操作嘛总数不可能超过256条,再一个class文件格式放弃了编译后代码的操作数长度对齐,如果虚拟机处理那些超过一个字节数据的时候,只能从字节中重建出具体数据的结构,可能导致损失一些性能。
优点:放弃了操作数长度对齐,就能省略很多填充和间隔符号。用一个字节来代表操作码,能获取短小精干的便宜代码。实现小数据量,高传输效率

字节码与数据类型

在Java虚拟机的指令集中,大多数指令都包含了其操作所对应的数据类相关信息。比如,iload指令用于从局部变量表中加载int型的数据到操作数栈中。fload指令是操作float类型的数据,这指令的操作在虚拟机内部可能会是同一段代码来实现,在class文件中拥有各自独立的操作码。
对于大部分与数据类型相关的字节码指令,他们操作码助记符中都有特殊字符来表示为那种数据类型服务:i代表int,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。还有一些指令的助剂符中没有明确的指明操作类型的字母。arraylength指令:没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。其中跳转指令goto与数据类型无关。
指令集并非完全独立的,有一些单独的指令可以用来将一些不支持类型转换成可被支持的类型
大部分指令都没有完全支持整数类型byte,char,short和布尔类型。编译器在编译期或者运行期将byte和short类型的数据转化成带符号扩展为相应的int类型数据,Boolean和char类型也是如此。因此,大多数对于Boolean,byte,short,char 类型数据的操作,本质上都是使用相应的int类型作为运算类型

加载和存储指令

加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输
将一个局部变量加载到操作栈:ilaod,ilaod,llaod,llaod,flaod,flaod,dlaod,dlaod,alaod,alaod
将一个数值从操作数栈存储到局部变量表:istore,istore,lstore,lstore,fstore,fstore,dstore,dstore,astore,astore
将一个常量加载到操作数栈:bipush,sipushu,Idc,Idc_w,Idc2_w,aconst_null,iconst_ml,iconst,iconst,iconst,iconst
扩充局部变量表的访问索引的指令:wide。
上面有一部分是以尖括号结尾的指令助记符代表了一组指令

运算指令

运算或算术指令用于对两个操作栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。
由于没有完全支持byte short char boolean 类型的算术指令,这些类型都是通过操做int类型的指令代替

运算指令intlongfloatdouble
加法指令iaddladdfadddadd
减法指令isublsubfsubdsub
乘法指令imullmulfmuldmul
除法指令idivldivfdivddiv
求余指令iremlremfremdrem
取反指令ineglnegfnegdneg
位移指令ishlishriushrlshl
按位或指令iorlor
按位与指令iandland
按位异或指令ixorlxor
局部变量自增指令iinc
比较指令dcmpgdcmplfcmpgfcmpl

类型转换指令

将两种不同的数值类型进行相互转换,实现用户代码中的显示类型转换操作
Java虚拟机直接支持不是显示的转换指令的宽化类型转换(小范围向大范围类型的安全转换):
int类型到long,float,double类型
long类型到float double 类型
float类型到double类型
处理窄化类型转换时,需要显示指令。
转换指令:i2b i2c i2s l2i f2i f2l d2i d2l d2f
缺点:可能会导致转换结果产生不同的正负号,不同的数量级情况,转化会失去精度。
浮点型窄化转换乘整数类型 ,注意一下规则:
浮点值是NaN 转化结果就是int或long的0
浮点值不是无穷大 向零舍入模式取整
如果doublle类型到float类型窄化转换 向最接近数舍入得到一个可以使用float 类型表示的数字 如果转换结果的绝对值太小无法使用float来表示,直接返回0。如果转换结果的绝对值太大无法使用float来表示,直接返回正负无穷大。
尽管数据窄化转换可能会发生上限溢出,下限溢出 精度丢失 但是 永远不可能抛出异常

对象创建与访问指令

类 实例和数组都是对象 但Java虚拟机对类实例和数组的创建与操作使用了不同的呃字节码指令。
指令如下:
创建类实例的指令:new
创建数组的指令:newarray anewarray multianewarray
访问类字段 (static 字段 ,类变量)和实例字段的指令:getfield putfield getstatic putstatic
把一个操作数栈的值存储到数组元素中的指令 : bastore castore sastore iastore fastore dastore aastore
把一个数组元素加载到操作数栈的指令:baload caload saload iaload faload daload aaload
取数组长度的指令:arraylength
检查类实例类型的指令:instanceof checkcast

操作数栈管理指令

Java虚拟机提供了一些用于直接操作操作数栈的指令:
将操作数栈的栈顶一个或两个元素出栈 pop pop2
复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶 dup dup2 dup_x1 dup2_x1 dup_x2 dup2_x2
将栈最顶端的两个值互换 swap

控制转移指令

能够让Java虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序
指令如下:
条件分支:ifeq iflt ifle ifne ifgt ifge ifnull ifnonnull if_icmpeq if_icmpne if_icmplt if_icmpgt if_icmple if_icmpge ifacmpeq if_acmpne
复合条件分支:tablewitch lookupswitch
无条件分支:goto goto_w jsr jsr_w ret
在Java虚拟机中有专门的指令集用来处理int和reference类型的条件分支比较操作,为了可以无须明显标识一个是体制是否null 也有专门的指令用来检测null值,对于 boolean byte char short 条件分支比较操作,都是用int指令完成。对于 long float double 的条件分支比较操作,先执行相应类型的比较运算指令,运算指令会返回一个整型值到操作数栈中,再执行int类型的条件分支比较操作来完成整个分支跳转。因此 Java虚拟机提供的int类型的条件分支指令 最为丰富和强大

方法调用和返回指令

invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派
invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出合适的方法进行调用
invokespecial指令用于调用一些需要特殊处理的实例方法 包括实例初始化方法 私有方法 父类方法
invokestatic指令调用类方法 static方法
invokedynamic指令在运行时动态解析出调用点限定符所引用的 方法 执行该方法
方法调用指令与数据类型无关 方法返回指令 根据返回值的类型区分 包括 ireturn(当返回值是Boolean byte char short int )lreturn fretirn dreturn areturn 另外还有一条return指令提供声明为void方法 实例初始化方法 以及类和 接口的类初始化方法使用

异常处理指令

显示抛出异常的操作 由athrow指令 还有一些在Java虚拟机指令检测到异常状况时自动抛出
在Java虚拟机还可以用处理异常catch语句实现

同步指令

Java虚拟机支持方法级的同步和方法内部一段指令序列的同步 ,都是用管程来支持。
方法级的同步 虚拟机可以从方法常量池的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法。当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标识是否被设置,如果设置 执行线程先持有管程 后执行方法,方法完成时释放管程
方法内部同步 在方法执行期间 执行线程有管程 任何线程都无法获取到同一个管程 同步方法执行期间抛出异常 方法内部无法处理此异常 所持有的管程在异常抛到同步方法之外时自动释放
同步一段指令集序列 由synchronized 语句块来表示,Java虚拟机的指令集有monitorenter monitorexit 来支持synchronized 关键字的语义
在方法中调用过的每条monitorenter都对应着monitorexit指令,不管正常还是异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听不见你的名字

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值