JVM入门到入土-Java虚拟机寄存器指令集与栈指令集

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集

  • HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤。

  • 由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。

参考资料

  • Java虚拟机规范(JavaSE8)
  • 深入理解Java虚拟机

JVM的两大指令集特点

基于栈式架构的特点

设计和实现更简单,适用于资源受限的系统(HotSpot虚拟机就基于此):

  • 避开了寄存器的分配难题: 使用零地址指令方式分配。
  • 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。
  • 指令集更小编译器容易实现。
  • 不需要硬件支持,可移植性更好,更好实现跨平台

基于寄存器架构的特点

典型的应用是x86的二进制指令集: 比如传统的PC以及Android的Davlik虚拟机。

  • 指令集架构则完全依赖硬件,可移植性差
  • 性能优秀和执行更高效,花费更少的指令去完成一项操作。
  • 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主。

获取栈指令集-指令javap

注意:如果你使用JDK17,可能会出现找不到控制台指令的问题(因为默认安装不会配置该指令),去JDK17的安装目录将bin添加到环境变量即可

先编译一个简单的1+2程序:

public class StackOneTest {public static void main(String[] args) {int a = 1;int b = 2;int c = a+b;}
}

然后使用javap -c class文件全名,我们将在控制台得到如下内容:

D:\CodeProjects\Eclipse\StackTest\bin\testjava>javap -c StackOneTest.class
Compiled from "StackOneTest.java"
public class testjava.StackOneTest {public testjava.StackOneTest();Code:0: aload_01: invokespecial #8                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: istore_38: return
}

由于手里没有基于寄存器的指令集实验环境,可自行查阅查看方法

栈指令集字节码的语义

字节码指令集设计概述

在 Java 虚拟机的指令集中,大多数的指令都包含了其所操作的数据类型信息。例如,iload 指令用于从局部变量表中加载 int 类型的数据到操作数栈中,而 ad 指加载的则是 float 类型的数据。这两个指令的操作可能会是由同一段代码来实现的,但它们必须拥有各自独立的操作码。对于大部分与数据类型相关的字节码指令来说,它们的操作码助记符中都有特殊的字符来表明该指令为哪种数据类型服务:i 代表对 int 型的数据操作,l 代表 longs 代表 shortb 代表 bytec 代表 charf 代表 floatd 代表 doublea 代表 reference。也有一些指令的助记符没有明确用字母指明数据类型,例如 arraylength 指令,它没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。还有另外一些指令,例如,无条件跳转指令 goto 则是与数据类型无关的。

因为 Java 虚拟机的操作码长度只有一个字节,所以包含了数据类型的操作码给指令集的设计带来了很大的压力。如果每一种与数据类型相关的指令都支持 Java 虚拟机的所有运行时数据类型,那恐怕就会超出一个字节所能表示的数量范围了。因此,Java 虚拟机的指令集对于特定的操作只提供了有限的类型相关指令,换句话说,指令集将会故意设计成非完全独立的(not orthogonal,即并非每种数据类型和每一种操作都有对应的指令)。有一些单独的指令可以在必要的时候用来将一些不支持的类型转换为可支持的类型。

表 2-2 列举了 Java 虚拟机所支持的字节码指令集。用数据类型列所代表的特殊字符替换 opcode 列的指令模板中的 T,就可以得到一个具体的字节码指令。如果在表中指令模板与数据类型两列共同确定的单元格为空,则说明虚拟机不支持对这种数据类型执行这项操作。例如,load 指令有操作 int 类型的 iload,但是没有操作 byte 类型的同类指令。请注意,从表 2-2 中可以看出,大部分的指令都没有支持整数类型 bytecharshort,甚至没有任何指令支持 boolean 类型。编译器会在编译期或运行期将 byteshort 类型的数据带符号扩展(sign-extend)为相应的 int 类型数据,将 booleanchar 类型数据零位扩展(zero-extend)为相应的 int 类型数据。与之类似,在处理 booleanbyteshortchar 类型的数组时,也会转换为使用对应的 int 类型的字节码指令来处理。因此,操作数的实际类型为 booleanbytecharshort 的大多数操作,都可以用操作数的运算类型(computational type)为 int 的指令来完成。

from : Java虚拟机规范(JavaSE8)

附表:

在这里插入图片描述

在这里插入图片描述

实际类型与关系映射表:

在这里插入图片描述

加载与存储指令集

加载本地变量到操作数栈的指令:

指令描述
iload将 int 类型加载到操作数栈
iload <n>将指定索引的 int 类型加载到操作数栈
lload_<n>将指定索引的 long 类型加载到操作数栈
fload将 float 类型加载到操作数栈
fload <n>将指定索引的 float 类型加载到操作数栈
dload将 double 类型加载到操作数栈
dload <n>将指定索引的 double 类型加载到操作数栈
aload将引用类型加载到操作数栈
aload <n>将指定索引的引用类型加载到操作数栈

存储操作数栈到局部变量表的指令:

指令描述
istore将 int 类型存储到局部变量表
istore <n>将 int 类型存储到指定索引的局部变量
lstore <n>将 long 类型存储到指定索引的局部变量
fstore将 float 类型存储到局部变量表
fstore <n>将 float 类型存储到指定索引的局部变量
dstore将 double 类型存储到局部变量表
dstore <n>将 double 类型存储到指定索引的局部变量
astore将引用类型存储到局部变量表
astore_<n>将引用类型存储到指定索引的局部变量

加载常量到操作数栈的指令:

指令描述
bipush将带符号的 byte 常量(-128~127)加载到操作数栈
sipush将带符号的 short 常量(-32768~32767)加载到操作数栈
ldc将 int, float 或 String 类型的常量加载到操作数栈
ldc_w与 ldc 类似,但用于更大的常量池索引
ldc2_w将 long 或 double 类型的常量加载到操作数栈
aconst_null将 null 加载到操作数栈
iconst_m1将整数 -1 加载到操作数栈
iconst <i>将整数常量加载到操作数栈
lconst <1>将长整数常量1加载到操作数栈
fconst <f>将浮点数常量加载到操作数栈
dconst <d>将双精度浮点数常量加载到操作数栈

扩充局部变量表的访问索引或立即数的指令:

指令描述
wide扩展下一条指令使用的局部变量索引的宽度

算数指令集

算术指令:

操作类型指令
加法iaddladdfadddadd
减法isubIsubfsubdsub
乘法imulmulfmuldmul
除法idivldivfdivddiv
求余iremIremfremdrem

逻辑位运算指令:

操作类型指令
按位或iorlor
按位与iandland
按位异或ixorlxor

其他运算指令:

操作类型指令
求负值inegInegfnegdneg
移位ishlishriushrIshlIshrlushr
局部变量自增iinc
比较dcmpgdcmplfcmpgfcmplIcmp

栈指令集字节码分析

main方法中的算数字节码

D:\CodeProjects\Eclipse\StackTest\bin\testjava>javap -c StackOneTest.class
Compiled from "StackOneTest.java"
public class testjava.StackOneTest {public testjava.StackOneTest();Code:0: aload_01: invokespecial #8                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: istore_38: return
}

从上述字节码不难看出,JVM先执行了StackOneTest对象的构造,然后将这个对象变量加载到了操作数栈(默认构造器),我们重点来看main中的指令集:

0: iconst_1
1: istore_1
2: iconst_2
3: istore_2

先将两个常量12加载到操作数栈,并且进行了存储,接下来:

4: iload_1
5: iload_2
6: iadd
7: istore_3

加载了两个变量ab到操作数栈,然后使用算数指令进行相加,最后进行存储结果(这里的第三个变量未使用,变量加载可能被编译器优化掉了),我们稍加修改:

在这里插入图片描述

可以发现在使用了第三个变量后,JVM进行了正确的变量加载

含方法的字节码分析

我们增加一个方法来进一步分析:

public class StackOneTest {public static int add(int a, int b) {return a+b;}public static void main(String[] args) {int a = 1;int b = 2;int c = add(a, b);System.out.println(c);}
}

在这里插入图片描述

从这里可知 invokestatic应该为调用方法的指令集,其运行也是和上一个大同小异,不过需要注意不同返回值类型的Treturn指令(T是借用泛型里的一个代号)

多次入栈字节码分析

修改代码:

public class StackOneTest {public static void main(String[] args) {int a = 1;int b = 2;int c = 3;int d = a+b;int e = a+c;}
}

相同方法进行分析:

在这里插入图片描述

可以发现其字节码也是逐行进行操作的,在变量de位置的处理和第一处也是类似的,只不过a进行了重复入栈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/579322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyCharm安装PyQt5一系列工具

目录 目录 一、安装IDE 二、安装Pycharm 三、Pycharm内安装一系列工具 1.新建一个项目 2.点击左上角File-Setting-点击加号 3.添加环境变量 4.配置qtdesigner,pyuic,pyrcc 三、用Pyinstaller打包成exe&#xff08;简单版&#xff09; 四、我的解释器装在了中文路径&a…

如何分析信号的频率信息?

1 简介 当信号的频率信息是已知的&#xff0c;或者近似已知的&#xff0c;则采样频率容易选择&#xff0c;选择最大采样频率的2倍以上(奈奎斯特采样)。 这里&#xff0c;将讨论信号频率未知的情况。尤其是&#xff0c;考虑如何避免混叠错误。 2 低通滤波(反混叠) 去除混叠错…

二、基于图像和结构化数据多模态融合的回归预测网络【框图讲解+源码】

整理读研期间做的项目与日常小实验 本篇未完待续…代码部分整理后补充 0. 背景 实验室有一些材料的SEM&#xff08;扫描电镜&#xff09;图像、也有对应的组分信息&#xff08;结构化数据&#xff0c;包含类别特征和连续的数值特征&#xff09;&#xff0c;以及对应的力学性能…

WEB 3D技术 three.js带着大家简单在文档上过一下集合体 并理解如何在文档中调试参数

前面讲了 自己创建集合体 顶点分组 但是这样其实挺麻烦的 three.js 其实已经给我们封装好了 官网直接搜索 geometry 这边这个立方体 应该算是我们用的最多的 这里 这个就是通过三个参数设置 它们分别对应 高度 宽度 厚度 拉下来 我们看到 其实他有六个参数 前面的 x y z三个…

有什么好用的C/C++源代码混淆工具?

​ 有什么好用的C/C源代码混淆工具&#xff1f; 开始使用ipaguard 前言 iOS加固保护是直接针对ios ipa二进制文件的保护技术&#xff0c;可以对iOS APP中的可执行文件进行深度混淆、加密。使用任何工具都无法逆向、破解还原源文件。对APP进行完整性保护&#xff0c;防止应用…

sqlmap各个命令的解释及其基本用法

各个命令的用法 -h,--help Show basic help message and exit(显示基本帮助消息并退出) -hh Show advanced help message and exit&#xff08;显示高级帮助信息并退出&#xff09; --version Show programs version number and exit&#xff08;显示程序的版本…

力扣刷题记录(18)LeetCode:474、518、377、322

目录 474. 一和零 518. 零钱兑换 II 377. 组合总和 Ⅳ 322. 零钱兑换 总结&#xff1a; 474. 一和零 这道题和前面的思路一样&#xff0c;就是需要将背包扩展到二维。 class Solution { public:int findMaxForm(vector<string>& strs, int m, int n) {vector&l…

C语言结构体内存对齐

文章目录 一、结构体内存对齐问题二、查看结构体成员起始位置三、设置内存对齐方式 一、结构体内存对齐问题 如下的info_s结构体类型&#xff0c;包含一个int型成员age, 一个char型成员gender, 一个int型成员id。 单从数据成员的大小进行分析&#xff0c;整个结构体的大小应为…

输入两个时间,判断时间是否为非工作日,并且是日期否为同一天。是的话返回true,否返回false

工作遇到这么一个逻辑&#xff0c;前端回传两个时间&#xff08;必须是两个那一种&#xff09;。然后&#xff0c;我后端需要判断这两个时间是否为同一天&#xff0c;并且这个时间是否为非工作日&#xff0c;是的话返回true&#xff0c;反之返回false 代码&#xff1a; packa…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Dialog对话框组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Dialog对话框组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Dialog对话框组件 对话框的使用场景也很高频&#xff0c;比如 APP 上架应…

共享和独享的区别是什么?有必要用独享IP吗?

通俗地讲&#xff0c;共享IP就像乘坐公共汽车一样&#xff0c;您可以到达目的地&#xff0c;但将与其他乘客共享旅程&#xff0c;座位很可能是没有的。独享IP就像坐出租车一样&#xff0c;您可以更快到达目的地&#xff0c;由于车上只有您一个人&#xff0c;座位是您一个人专用…

安卓开发转鸿蒙开发到底有多简单?学习鸿蒙开发有什么价值?

相信各位小伙伴们多多少少都了解过鸿蒙了&#xff0c;有些一知半解而有些已经开始学习起来。那这个鸿蒙到底好不好搞&#xff1f;要不要搞&#xff1f; 据了解安卓反正目前工作感觉不好找&#xff0c;即便是上海这样的大城市也难搞&#xff0c;人员挺饱和的。最近临近年关裁员…

浅谈locust 性能压测使用

1. 基本介绍 Locust是一个开源的负载测试工具&#xff0c;用于模拟大量用户并发访问一个系统或服务&#xff0c;以评估其性能和稳定性。编写语言为Python&#xff0c;可通过Python来自定义构建性能压测场景脚本。Locust支持分 布式负载测试&#xff0c;可以通过多个机器协同工…

张江智荟毁约offer

毕业8年后&#xff0c;找工作被国企歧视学历&#xff01;已经收到了offer&#xff0c;在入职前一周被通知要撤回offer&#xff0c;拒绝录用&#xff0c;理由居然是他们只要本科211以上的人 这是我今天&#xff08;2023-12-26&#xff09;亲身经历的事&#xff0c;听说过面试前…

【树莓派4b的uboot编译移植】

树莓派4b的uboot编译移植 引言 0.1、什么是uboot OS跑起来前&#xff0c;需要的一段引导程序负责部署整个计算机系统&#xff0c;引导操作系统内核启动并给内核传参提供一个命令行界面供人操作是一个开源项目&#xff0c;uboot就是universal bootloader&#xff08;通用的启…

词法语法语义分析程序设计及实现,包含出错提示和错误恢复

词法说明 (1)关键字 main, int, char, if, else, for, while, void (2)运算符 - * / < < > > ! (3)界符 ; ( ) { } (4)标识符 ID letter(letter|digit)* (5)整型常数 NUM digit digit* (6)空格 ‘ ‘ ‘\n’ ‘\r’ ‘\t’ 空格用来分隔ID,NUM,运算符,界…

正则表达式:元字符

一、什么事元字符 正则是由一系列的元字符组成的&#xff0c;所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符&#xff0c;元字符是构成正则表达式的基本元件。 二、元字符的分类 1.特殊单字符 表达式含义\d匹配任意一个数字\D匹配任意非数字\w匹配任意一个字母、…

算法练习Day20 (Leetcode/Python-回溯算法)

虽然看似进入了一个新章节&#xff0c;但其实还是前几天二叉树章节的延续。。 回溯算法 &#xff08;以下内容摘抄自代码随想录&#xff09;&#xff1a; 回溯法解决的问题都可以抽象为树形结构&#xff0c;是的&#xff0c;我指的是所有回溯法的问题都可以抽象为树形结构&…

云原生Kubernetes:K8S集群版本升级(v1.22.14 - v1.23.14)

目录 一、理论 1.K8S集群升级 2.环境 3.升级集群&#xff08;v1.23.14&#xff09; 4.验证集群&#xff08;v1.23.14&#xff09; 二、实验 1. 环境 2.升级集群&#xff08;v1.23.14&#xff09; 2.验证集群&#xff08;v1.23.14&#xff09; 一、理论 1.K8S集群升级 …

详解视频美颜SDK:算法优化与性能提升

众所周知&#xff0c;视频美颜SDK的算法优化和性能提升至关重要。下文小编将与大家深度探讨视频美颜SDK的算法原理&#xff0c;以及近期的性能优化措施。 一、常见用法 视频美颜SDK对人脸进行识别&#xff0c;并附加适当的美颜效果。例如&#xff1a; 1.识别、关键点 2.肤色…