说明,本文的目的在于从宏观逻辑上介绍清楚绝大多数的字节码指令的含义以及分类
只要认真阅读本文必然能够对字节码指令集有所了解
如果需要了解清楚每一个指令的具体详尽用法,请参阅虚拟机规范

指令简介

计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。
通常一条指令包括两方面的内容: 操作码和操作数,操作码决定要完成的操作,操作数指参加运算的数据及其所在的单元地址。
虚拟机的字节码指令亦是如此含义
class文件相当于JVM的机器语言
class文件是源代码信息的完整表述
方法内的代码被保存到code属性中,字节码指令序列就是方法的调用过程
 
Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的操作码(opcode)
以及跟随其后的零至多个代表此操作所需参数的操作数(operand)所构成
虚拟机中许多指令并不包含操作数.只有一个操作码。
 
如果忽略异常处理,执行逻辑类似
do{
自动计算pc寄存器以及从pc寄存器的位置取出操作码;
if(存在操作数){
取出操作数;
}
执行操作码所定义的操作;
}while(处理下一次循环);
操作数的数量以及长度取决于操作码,如果一个操作数的长度超过了一个字节,那么它将大端排序存储,即高位在前的字节序。
例如,如果要将一个16位长度的无符号整数使用两个无符号字节存储起来(将它们命名为byte]和byte2 )
那这个16位无符号整数的值就是:  (bytel<<8) | byte2.
字节码指令流应当都是单字节对齐的,只有,tableswitch和lookupswitch两个指令例外 这俩货是4字节为单位的
 
限制了操作码长度为一个字节 0~255,   但是也就导致操作码个数不能超过256
放弃编译后代码的操作数对齐 也就省略很多填充和间隔符号
限制长度和放弃对齐也尽可能的让编译后的代码短小精干
但是如果向上面那样如果操作码处理超过一个字节的数据时,就必须在运行时从字节流中重建出具体数据结构,将会有一定程度的性能损失

指令详解

说明:
操作码一个字节长度,也就是8位二进制数字,也就是两位十六进制数字
class文件只会出现数字形式的操作码
但是为了便于人识别,操作码有他对应的助记符形式
接下来所有的指令的说明,都是以助记符形式表达的
但是要明确,实际的执行运行并不存在助记符这些东西,都是根据操作码的值来执行
 
指令本身就是为了功能逻辑运算
运算自然要处理数据
所以说指令的设计是逻辑功能点与数据类型的结合
接下来先看下有哪些数据类型和逻辑功能点
 

数据类型

\"image_5b869c5d_c55\"
 
上一篇文章中已经说明JVM支持的数据类型
共有9中基本类型
对于基本类型  指令在设计的时候都用一个字母缩写来指代(boolean除外)
byte  short  int  long  float  double  char  reference boolean
b s i l f d c a
 

逻辑功能

加载存储指令
算数指令
类型转换指令
对象的创建于操作
操作数栈管理指令
控制转移指令
方法调用和返回指令
抛出异常
同步
 
指令基本上就是围绕着上面的逻辑功能以及数据类型进行设计的
当然  
也有一些并没有明确用字母指代数据类型,比如arraylength 指令,并没有代表数据类型的特殊字符,操作数只能是一个数组类型的对象
另外还有一些,比如无条件跳转指令goto 则是与数据类型无关的
 
接下来将会从各个维度对绝大多数指令进行介绍
注意: 在不同的分类中,有些指令是重复的,因为有很多操作是需要处理数据的
也就是说数据类型相关的指令里面可能跟很多逻辑功能点相关联,比如 加载存储指令,可以加载int 可以加载long等
他在我接下来的说明中,可能不仅仅会出现在数据类型相关的指令中
也会出现在加载存储指令的介绍中,请不要疑惑
就是要从多维度介绍这些指令,才能更好地理解他们

指令-相关计算机英语词汇含义

push push 按 推动 压入
load load 加载 装载 
const const 常数,不变的
store store 存储 保存到
add add 加法
sub subduction 减法
mul multiplication 乘法
div division 除法
inc increase 增加
rem remainder 取余 剩下的留下的
neg negate 取反 否定
sh shift 移位 移动变换
and and
or or
xor exclusive OR 异或
2 to 转换 转变 变成
cmp compare 比较
return return  返回
eq equal 相等
ne not equal 不相等
lt less than 小于
le less than or equal 小于等于
gt greater than 大于
ge greater than or equal 大于等于
if if 条件判断 如果
goto goto 跳转
invoke invoke 调用
dup dump 复制 拷贝 卸下 丢下
 

指令-数据类型相关的指令

java中的操作码长度只有个字节,所以必然,并不会所有的类型都有对应的操作
Java虚拟机指令集对于特定的操作只提供了有限的类型相关指令
有一些单独的指令可以再必要的时候用来将一些不支持的类型转换为可支持的类型
下表中最左边一列的T表示模板,只需要用数据类型的缩写,替换掉T 就可以得到对应的具体的指令
如果下表中为空,说明对这种数据类型不支持这种类型的操作
操作码/类型 byte short int long float double char reference
Tipush bipush sipush            
Tconst     iconst lconst fconst dconst   aconst
Tload     iload lload fload dload   aload
Tstore     istore lstore fstore dstore   astore
Tinc     iinc          
Taload  baload  saload  iaload  laload  faload  daload  caload  aaload
Tastore  bastore  sastore  iastore  lastore  fastore  dastore  castore  aastore
Tadd      iadd  ladd  fadd  dadd    
Tsub      isub  lsub  fsub  dsub    
Tmul      imul lmul  fmul  dmul    
Tdiv      idiv  ldiv  fdiv  ddiv    
Trem      irem  lrem  frem  drem    
Tneg      ineg  lneg  fneg  dneg    
Tshl     ishl lshl        
Tshr     ishr lshr        
Tushr      iushr  lushr        
Tand      iand  land        
Tor     ior  lor        
Txor      ixor  lxor        
i2T  i2b  i2s    i2l  i2f  i2d    
l2T      l2i    l2f  l2d    
f2T      f2i  f2l    f2d    
d2T     d2i  d2l  d2f      
Tcmp       lcmp        
Tcmpl         fcmpl  dcmpl    
Tcmpg          fcmpg  dcmpg    
if_TcmpOP     if_icmpOP          if_acmpOP
Treturn     ireturn  lreturn  freturn  dreturn    areturn
 
从上表的空白处可以看得出来
大部分数据类型相关联的指令,都没有支持整数类型 byte char short ,而且没有任何指令支持boolean类型
因为
编译器会在编译期或者运行期  将byte 和short 类型的数据 带符号扩展 为相应的int类型数据
类似的,boolean 和char类型数据零位扩展为相应的int类型数据
在处理boolean byte short char类型的数组时,也会转换为使用对应的int类型的字节码指令来处理
另外需要格外注意的是,上表是为了呈现部分与数据类型相关联的操作码
并不是说所有的操作码都在上表中,仅仅是和数据类型相关联的才出现在了上表中
 
实际类型与运算类型的对应关系如下,分类后面会说到
实际类型 运算类型 分类
boolean int 1
int int 1
byte int 1
short int 1
int int 1
float float 1
reference
收藏 打印