Java虚拟机的指令由一个字节长度的、 代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。

字节码与数据类型

在Java虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息。 例如,iload指令用于从局部变量表中加载int型的数据到操作数栈中,而fload指令加载的则是float类型的数据。 这两条指令的操作在虚拟机内部可能会是由同一段代码来实现的,但在Class文件中它们必须拥有各自独立的操作码。

对于大部分与数据类型相关的字节码指令,它们的操作码助记符中都有特殊的字符来表明专门为哪种数据类型服务:i代表对int类型的数据操作,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。 也有一些指令的助记符中没有明确地指明操作类型的字母,如arraylength指令,它没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。 还有另外一些指令,如无条件跳转指令goto则是与数据类型无关的。

加载和存储指令

加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输,这类指令包括如下内容。

  • 将一个局部变量加载到操作栈:iload、 iload_<n>、 lload、 lload_<n>、 fload、 fload_<n>、 dload、 dload_<n>、 aload、 aload_<n>。
  • 将一个数值从操作数栈存储到局部变量表:istore、 istore_<n>、 lstore、 lstore_<n>、fstore、 fstore_<n>、 dstore、 dstore_<n>、 astore、 astore_<n>。
  • 将一个常量加载到操作数栈:bipush、 sipush、 ldc、 ldc_w、 ldc2_w、 aconst_null、iconst_m1、 iconst_<i>、 lconst_<l>、 fconst_<f>、 dconst_<d>。
  • 扩充局部变量表的访问索引的指令:wide。

运算指令

运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。 大体上算术指令可以分为两种:对整型数据进行运算的指令与对浮点型数据进行运算的指令,无论是哪种算术指令,都使用Java虚拟机的数据类型,由于没有直接支持byte、short、 char和boolean类型的算术指令,对于这类数据的运算,应使用操作int类型的指令代替。 整数与浮点数的算术指令在溢出和被零除的时候也有各自不同的行为表现,所有的算术指令如下。

  • 加法指令:iadd、 ladd、 fadd、 dadd。
  • 减法指令:isub、 lsub、 fsub、 dsub。
  • 乘法指令:imul、 lmul、 fmul、 dmul。
  • 除法指令:idiv、 ldiv、 fdiv、 ddiv。
  • 求余指令:irem、 lrem、 frem、 drem。
  • 取反指令:ineg、 lneg、 fneg、 dneg。
  • 位移指令:ishl、 ishr、 iushr、 lshl、 lshr、 lushr。
  • 按位或指令:ior、 lor。
  • 按位与指令:iand、 land。
  • 按位异或指令:ixor、 lxor。
  • 局部变量自增指令:iinc。
  • 比较指令:dcmpg、 dcmpl、 fcmpg、 fcmpl、 lcmp。

类型转换指令

类型转换指令可以将两种不同的数值类型进行相互转换,这些转换操作一般用于实现用户代码中的显式类型转换操作

  • int类型到long、 float或者double类型。
  • long类型到float、 double类型。
  • float类型到double类型。

对象创建与访问指令

虽然类实例和数组都是对象,但Java虚拟机对类实例和数组的创建与操作使用了不同的字节码指令。 对象创建后,就可以通过对象访问指令获取对象实例或者数组实例中的字段或者数组元素,这些指令如下。

  • 创建类实例的指令:new。
  • 创建数组的指令:newarray、 anewarray、 multianewarray。
  • 访问类字段(static字段,或者称为类变量)和实例字段(非static字段,或者称为实例变量)的指令:getfield、 putfield、 getstatic、 putstatic。
  • 把一个数组元素加载到操作数栈的指令:baload、 caload、 saload、 iaload、 laload、faload、 daload、 aaload。
  • 将一个操作数栈的值存储到数组元素中的指令:bastore、 castore、 sastore、 iastore、fastore、 dastore、 aastore。
  • 取数组长度的指令:arraylength。
  • 检查类实例类型的指令:instanceof、 checkcast。

操作数栈管理指令

如同操作一个普通数据结构中的堆栈那样,Java虚拟机提供了一些用于直接操作操作数栈的指令,包括:

  • 将操作数栈的栈顶一个或两个元素出栈:pop、 pop2。
  • 复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶:dup、 dup2、dup_x1、 dup2_x1、 dup_x2、 dup2_x2。
  • 将栈最顶端的两个数值互换:swap。

控制转移指令

控制转移指令可以让Java虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序,从概念模型上理解,可以认为控制转移指令就是在有条件或无条件地修改PC寄存器的值。 控制转移指令如下。

  • 条件分支:ifeq、 iflt、 ifle、 ifne、 ifgt、 ifge、 ifnull、 ifnonnull、 if_icmpeq、 if_icmpne、if_icmplt、 if_icmpgt、 if_icmple、 if_icmpge、 if_acmpeq和if_acmpne。
  • 复合条件分支:tableswitch、 lookupswitch。
  • 无条件分支:goto、 goto_w、 jsr、 jsr_w、 ret。

在Java虚拟机中有专门的指令集用来处理int和reference类型的条件分支比较操作,为了可以无须明显标识一个实体值是否null,也有专门的指令用来检测null值。

方法调用和返回指令

  • invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是Java语言中最常见的方法分派方式。
  • invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
  • invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法、 私有方法和父类方法。
  • invokestatic指令用于调用类方法(static方法)。
  • invokedynamic指令用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面4条调用指令的分派逻辑都固化在Java虚拟机内部,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。

方法调用指令与数据类型无关,而方法返回指令是根据返回值的类型区分的,包括ireturn(当返回值是boolean、 byte、 char、 short和int类型时使用)、 lreturn、 freturn、 dreturn和areturn,另外还有一条return指令供声明为void的方法、 实例初始化方法以及类和接口的类初始化方法使用。

异常处理指令

在Java程序中显式抛出异常的操作(throw语句)都由athrow指令来实现,除了用throw语句显式抛出异常情况之外,Java虚拟机规范还规定了许多运行时异常会在其他Java虚拟机指令检测到异常状况时自动抛出。 例如,在前面介绍的整数运算中,当除数为零时,虚拟机会在idiv或ldiv指令中抛出ArithmeticException异常。

而在Java虚拟机中,处理异常(catch语句)不是由字节码指令来实现的(很久之前曾经使用jsr和ret指令来实现,现在已经不用了),而是采用异常表来完成的。

同步指令

Java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor)来支持的。

方法级的同步是隐式的,即无须通过字节码指令来控制,它实现在方法调用和返回操作之中。 虚拟机可以从方法常量池的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法。 当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。 在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。 如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那么这个同步方法所持有的管程将在异常抛到同步方法之外时自动释放。

同步一段指令集序列通常是由Java语言中的synchronized语句块来表示的,Java虚拟机的指令集中有monitorenter和monitorexit两条指令来支持synchronized关键字的语义,正确实现synchronized关键字需要Javac编译器与Java虚拟机两者共同协作支持


参考文献:深入理解Java虚拟机 周志明 著

深入理解Java虚拟机 - 字节码指令集相关推荐

  1. java 虚拟机 字节码,JAVA虚拟机:虚拟机字节码执行引擎

    "虚拟机"是一个相对"物理机"的概念,这两种机器都有代码执行能力. 物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的. 虚拟机的执行引擎由自己 ...

  2. java虚拟机 — 字节码生成

    1. 总体流程 简单来讲,一款编程语言想兼容底层(跨操作系统)的方式大概有两种:一是通过编译器,如C或C++.但是要针对不同硬件平台和操作系统开发不同的编译器,这样实现十分麻烦.二是通过中间语言,如J ...

  3. Java虚拟机字节码指令概述

    虚拟机字节码指令 Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成. 一 基 ...

  4. Java虚拟机字节码指令

    Java字节码指令 Java 字节码指令及javap 使用说明 ### java字节码指令列表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送 ...

  5. java 虚拟机字节码指令表

    字节码 助记符 指令含义 0x00 nop 什么都不做. 0x01 aconst_null 将 null 推送至栈顶. 0x02 iconst_m1 将 int 型-1 推送至栈顶. 0x03 ico ...

  6. mysql种编译码写在哪_深入理解Java虚拟机(程序编译与代码优化)

    对于性能和效率的追求一直是程序开发中永恒不变的宗旨,除了我们自己在编码过程中要充分考虑代码的性能和效率,虚拟机在编译阶段也会对代码进行优化.本文就从虚拟机层面来看看虚拟机对我们所编写的代码采用了哪些优 ...

  7. 深入理解Java虚拟机(周志明第三版)- 第八章:虚拟机字节码执行引擎

    系列文章目录 第一章: 走近Java 第二章: Java内存区域与内存溢出异常 第三章: Java垃圾收集器与内存分配策略 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言 ...

  8. 深入理解java虚拟机-第五章:虚拟机字节码执行引擎

    本章将介绍虚拟机如何调用方法 一.java虚拟机字节码执行引擎 执行引擎在执行代码的时候可能有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种. 执行流程:输入的是字节码文件 ...

  9. java虚拟机调用linux_Java虚拟机字节码执行引擎

    定义 Java虚拟机字节码执行引擎是jvm最核心的组成部分之一,它做的事情很简单:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果.在不同的虚拟机实现里,执行引擎在执行java代码 ...

最新文章

  1. Java 线程 笔记(1)
  2. 【Java】学习笔记(1)
  3. 【蓝桥杯省赛】冲刺练习题【数学公式】倒计时【06】天(准考证组委会已下发,请查询)
  4. exp/imp和expdp/impdp在功能上的区别:
  5. Inno Setup 如何让生成的setup.exe文件有管理员权限
  6. MAGENTO DEBUG
  7. jQuery 学习笔记之十 (jQuery ajax )
  8. 桌面支持--teamviwer如果没装杀毒软件,会有警告
  9. IMPORT MULTIPLE JS
  10. 安全模式 提权_WEB安全第八章实战篇01 提权安全狗服务器
  11. 收藏几款好用的网页下载工具(网页下载器)
  12. 工业互联网是什么?发展有多厉害?
  13. MongoDB 网页可视化管理(adminMongo 的安装、配置)
  14. 思科(Cisco)交换机路由器命令大全
  15. arg min什么意思
  16. 快速使用easy rule
  17. 【回炉重造系列】之Spring AOP简介
  18. 微服务Feign调用后开启Schedule报错No thread-bound request found: Are you referring to request attributes outsid
  19. 计算机怎么截音乐,电脑怎么剪辑音乐 怎样在电脑上剪辑歌曲
  20. (转自)何新:谈“玄”(一)

热门文章

  1. 图解时间自适应卷积----Time-aware Large Kernel Convolutions
  2. CreateEvent()的参数说明
  3. 打印Excel Word文件变成绿色背景解决方法
  4. 笔记2--认识O(logN)的排序--快速排序
  5. 论文阅读笔记:Global-Locally Self-Attentive Dialogue State Tracker
  6. IIS Web 服务器的权限设置
  7. /etc/init.d/sshd配置SSHD路径忘记修改导致启动失败
  8. 【AU】单链表就地逆置
  9. 沐神的 《动手学深度学习》 课程中的 3.2节 线性回归的从零实现
  10. 94%的市场待开发,这份调研报告直指企业“软肋”!