说明,本文的目的在于从宏观逻辑上介绍清楚绝大多数的字节码指令的含义以及分类 只要认真阅读本文必然能够对字节码指令集有所了解 如果需要了解清楚每一个指令的具体详尽用法,请参阅虚拟机规范
指令简介
计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。 通常一条指令包括两方面的内容: 操作码和操作数,操作码决定要完成的操作,操作数指参加运算的数据及其所在的单元地址。 虚拟机的字节码指令亦是如此含义 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文件只会出现数字形式的操作码 但是为了便于人识别,操作码有他对应的助记符形式 接下来所有的指令的说明,都是以助记符形式表达的 但是要明确,实际的执行运行并不存在助记符这些东西,都是根据操作码的值来执行 指令本身就是为了功能逻辑运算 运算自然要处理数据 所以说指令的设计是逻辑功能点与数据类型的结合 接下来先看下有哪些数据类型和逻辑功能点数据类型
上一篇文章中已经说明JVM支持的数据类型 共有9中基本类型对于基本类型 指令在设计的时候都用一个字母缩写来指代(boolean除外)逻辑功能
指令基本上就是围绕着上面的逻辑功能以及数据类型进行设计的 当然 也有一些并没有明确用字母指代数据类型,比如arraylength 指令,并没有代表数据类型的特殊字符,操作数只能是一个数组类型的对象另外还有一些,比如无条件跳转指令goto 则是与数据类型无关的 接下来将会从各个维度对绝大多数指令进行介绍 注意: 在不同的分类中,有些指令是重复的,因为有很多操作是需要处理数据的 也就是说数据类型相关的指令里面可能跟很多逻辑功能点相关联,比如 加载存储指令,可以加载int 可以加载long等 他在我接下来的说明中,可能不仅仅会出现在数据类型相关的指令中 也会出现在加载存储指令的介绍中,请不要疑惑 就是要从多维度介绍这些指令,才能更好地理解他们