小研究 - Java虚拟机即时编译器的一种实现原理

news2024/9/28 15:30:00

深入分析了 Kaffe虚拟机的 JIT(Just-In-Time)实现原理,以及在 JI中如何利用Trampoline技术来作为跳板达到提高 Kaffe虚拟机的执行性能,并通在 i386上结合实例来具体了解 Trampoline的实现。最后深入分析了作为 JIT核的翻译器在 JIT中如何将字节码映射成为中间码,并翻译成为本地代码的实现原理。

目录

1 引言

2  Kaffe中 JIT的实现原理

2.1 引入 Trampoline

2.2  Trampoline的实现思路

2.3  Trampoline的源码实现

2.4  翻译器的实现原理

3  结 束 语


1 引言

任何 Java虚拟机实现的核心都是它的执行引擎(如图 1)。Java虚拟机中的执行引擎就好比中央处理器,使得 Java虚拟机重复不断地读取字节码然后解释并执行,直到虚拟机进程退出。

Java虚拟机规范中规定,执行引擎的行为由指令集来规定动作。对于每条指令,规范都详细规定了执行该指令时应该“做什么”,但是没有说明“如何做”,因此 Java虚拟机的实现者可以采取解释执行技术、即时编译(JIT)技术或者直接在专用芯片上执行指令的技术,甚至可以是它们的混合技术。

Kaffe是按照 Java虚拟机规范实现的一种虚拟机。它是基于源代码开放的自由软件,在大部分平台上都能够成功的移植,且性能稳定。其执行引擎的实现(即“如何做”)也具有自身的特点。

Kaffe的执行引擎实现方式有解释执行与即时编译两种方式(可以在安装的时候选择)。解释执行是一种简单的实现方式:执行引擎读取每条字节码指令,然后将每条字节码解释成为本地代码,如此反复。这样的执行引擎实现方式比较简单,但是执行效率非常低下,因为解释工作是逐条地反复进行,导致程序中会有大量代码重复执行而浪费了许多时间。不过,Kaffe的即时编译器的执行效率得到了很大的提高:它是在第一次调用某个方法的时候,才将方法的字节码翻译成为本地代码,并在以后再次调用这个方法的时候,直接调用本地代码。由于是对整段代码的翻译,而且可以缓存本地代码,从而极大提高了虚拟机的运行速度。另外它还可以对整段代码进行本地优化,使解释字节码的效率得到大大提高,节约了大量的调用时间和空间。

2  Kaffe中 JIT的实现原理

2.1 引入 Trampoline

Kaffe采用JIT模式运行的时候,JIT会认为它正在执行的总是本地代码,因此需要在运行 Java方法之前将方法翻译成为本地代码。一种可能是在虚拟机装载 class文件的时候,将该类的所有方法都提前预编译为本地代码,这样在需要调用某个方法时,直接调用本地方法即可。但是这样的代价是装载一个类会耗费大量时间,而且经过提前翻译的方法不一定会得到运行,这样造成了时间和空间上的极大浪费,降低了性能。

2.2  Trampoline的实现思路

Kaffe的即时编译器(JIT)采用 Trampoline技术,其基本原理是:

1)创建 Trampoline阶段:每当虚拟机在装载类的时候,会为这个类的所有方法创建一个派遣表,该表中的每一项指向一个被称为 Trampoline的函数(见图 2)。该 Trampoline函数包含有足够的信息来通知一个叫做翻译器的函数来将该调用方法的字节码翻译成为本地代码。

2)调用方法阶段:每当虚拟机第一次调用某个方法的时候,调用者首先在一个派遣表中查找到该
方法,如果该方法还没有被翻译为本地代码,则该方法所指向的Trampoline函数会跳转到第一阶段存储的翻译器函数来负责将该方法的字节码翻译成本地代码。翻译结束之后,派遣表中的该方法被修改成指向翻译后的本地代码内存地址,并且将本地代码的地址返回给调用者。这样,以后再次调用该方法的时候,可以直接从派遣表中跳转到本地代码执行。

如图 2所示,调用路线直接从 a走向 b。Trampoline在其中起到了跳板的作用。

2.3  Trampoline的源码实现

Kaffe虚拟机由于是将字节码翻译成为本地代码,所以根据不同的平台,其实现原理虽然一致,但具体实现细节稍有不同。下面以 Kaffe在 i38平台下为例来分析一下 Trampoline的源代码。

在 Kaffe源代码目录的 config/i386/jit.h中,有一个 methodTrampoline结构体和 FILL_IN_TRAMPO-LINE的宏定义(见图 3)。methodTrampoline就是图2中 Trampoline的数据结构,它有 4个数据项,C语言中定义为 PACKED,表示 fixup项和 call项是紧挨着的,而不是 4字节对齐。FILL_IN_TRAMPOLINE宏的作用就是前面 2.2中描述的第一阶段。call=0xe8是 i386体系结构的汇编代码对应的 call指令。i386_do_fixup_trampoline是一个用汇编代码实现的函数,(int)t是 Trampoline的内存地址,汇编指令call占用 5个字节,所以要减去 5,最后得到的 fixup值是一个偏移量,该偏移量被汇编指令 call(0xe8)调用,方便以后跳转到 i386_do_fixup_trampoline中去执行。meth指向需要翻译成为本地代码的方法字节码。在 i386_do_fixup_trampoline中是作为参数传递给函数 soft_fixup_trampoline的(该函数调用了翻译器 Translate函数)。where指向派遣表中调用方法的位置。where因为和 meth在内存中是紧挨着的,所以最终它也传递给了函数 soft_fixup_trampo-line。

接下来看看 i386_do_fixup_trampoline的巧妙之处:popl%eax是将上面 meth的内存地址传递给%eax,之后压栈(push%eax),就可以将%eax(也就是meth的地址)作为参数传递给 soft_fixup_trampoline函数 了。soft_fixup_trampoline函数 调 用 翻 译 器(Translate方法)将字节码翻译成为本地代码,然后更新派遣表,使之指向本地代码。最后再跳转到本地代码并执行本地代码(见图 4)。

Kaffe针对其它平台也有类似的实现,虽然具体细节略有不同,但是其最终目的都是为了从 Trampo-line跳转到翻译器,把字节码翻译成为本地码。

2.4  翻译器的实现原理

Trampoline只是 Kaffe在 JIT中实现的跳板,而真正的将字节码翻译成本地代码的过程是由 Kaffe的翻译器来完成的。

Kaffe的 JIT在将字节码翻译成本地代码之前,会将字节码先翻译成对应的中间码,被称作 icode(intermediatecode)。Kaffe的中间码指令集的目的是为了在 Kaffe移植到一个新的体系架构过程中最大限度的获得代码重用,获得快速、高效的开发进度。

通过 Trampoline的巧妙设置后,此时翻译器并没有真正的执行,因为这只是在类装载时期完成的,还没有真正的调用 Java方法。而一旦第一次调用某个 Java方法时,JIT就会跳转到翻译器中来翻译字节码为中间码,再翻译为本地代码。翻译器在 JIT中起着核心的作用,主要完成三个步骤:

1)字节码的分析阶段:获得当前方法所需的栈信息(比如栈的大小等)、所有局部变量的有用信息等。

2)翻译阶段:首先将单个字节码指令映射到相应的中间码,然后通过中间码生成被称为“se-quence”对象的链表,这些链表各自对应着跟体系结构相关的本地函数,最后通过这些本地函数将中间码翻译成本地代码。

3)连接阶段:将所有生成的本地代码拷贝到一个新的空间,并且初始化连接。这里的初始化连接表示重写某些因为拷贝到新的空间造成的地址改变等信息。

3  结 束 语

不同虚拟机的执行引擎都有自己的具体实现方式,这里分析了 Kaffe虚拟机在 JIT上的实现原理。通过在不同平台上的运行效果看,Kaffe的 JIT在执行性能上还是有其优势的。

随着 Java虚拟机在各种平台的应用越来越广泛,Java的跨平台性也得到了广泛的认可,从而做好Java虚拟机的移植工作是非常重要的。在移植中,Kaffe执行引擎的移植是重要的一环,在这方面,Kaffe已经做的很出色。通过本文的分析,能够为程序员理解以及移植 Java虚拟机的执行引擎带来一定的参考价值。

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

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

相关文章

websocket和uni-app里使用websocket

一、HTTP是无状态协议 特点: 1、浏览器发送请求时,浏览器和服务器会建立一个连接。完成请求和响应。在http1.0之前,每次请求响应完毕后,会立即断开连接。在http1.1之后,当前网页的所有请求响应完毕后,才断…

64位ATT汇编语言调用自己编写的两个数相加函数,使用printf输出,发现报错Segmentation fault

cat /etc/redhat-release看到操作系统是CentOS Linux release 7.6.1810,uname -r看到内核版本是3.10.0-957.el7.x86_64,gcc --version可以看到gcc版本是12.2.0,gdb --version可以看到gdb版本是12.1。 twoNumberPlus.s里边的内容如下&#x…

开源游戏开发:机会与挑战

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

机器学习技术

机器学习技术是什么? 机器学习技术(Machine Learning,ML)是一种人工智能的分支,它关注如何通过数据和模型,让计算机自动从经验中学习,改进性能,并不断提高任务的准确性。机器学习的…

网络安全(红队)自学学习路线

想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客! 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全…

Go并发可视化解释 - Select语句

昨天,我发布了一篇文章,用可视化的方式解释了Golang中通道(Channel)的工作原理。如果你对通道的理解仍然存在困难,最好呢请在阅读本文之前先查看那篇文章。作为一个快速的复习:Partier、Candier 和 Stringe…

ChatGPT 与 Python进行动态可视化分析

Python数据分析目前最为热门的岗位操作。 想使用Python进行可视化分析,但是又不想写代码,测试,验证。可以交给ChatGPT,open AI 来进行操作。 这样的动态图显示,我们只需要给ChatGPT发送一个指令,人工智能就…

AUTOSAR规范与ECU软件开发(实践篇)6.6 BSW模块代码生成

在BCT界面中配置完所需要的BSW模块后, 可以进行BSW模块相关代码与描述文件的生成, 点击ISOLAR-A主菜单中“ ”右边箭头, 选择Run Configuraions, 如图6.57所示。 将弹出如图6.58所示的界面。 图6.57 Run Configuraions配置&#x…

软件测试 day2

今天目标 能对穷举场景设计测试点 能对限定边界规则设计测试点 能对多条件依赖关系进行设计测试点 能对于项目业务进行设计测试点一、解决穷举场景 重点:使用等价类划分法 1.1 等价类划分法 重点:有效等价和单个无效等价各取1个即可。 步骤:…

R包开发-2.1:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)

目录 0-前言 1-在RStudio中创建R包项目 2-创建R包 2.1通过R函数创建新包 2.2在RStudio通过菜单来创建一个新包 2.3关于R包创建的说明 3-添加R自定义函数 4-添加C函数 0-前言 目标:在RStudio中创建一个R包,这个R包中包含C函数,接口是Rc…

帆软报表系统SSRF

有子曰:“信近于义,言可复也。恭近礼,远耻辱也。因不失其亲,亦可宗也。” SSRF 构造payload,访问漏洞url: /ReportServer?opresource&resourcehttp://x.x.x漏洞证明: 文笔生疏&#xf…

Redisson分布式锁 原理源码 分析

# 基于setnx实现的分布式锁存在的问题: # 为了解决上面的问题,可以用Redisson # Redisson入门 # Redisson可重入锁原理 获取锁的Lua脚本: 释放锁的Lua脚本: # 锁重试原理分析 tryLock()底层代码分析 tim…

在metallb基础上使用 ingress-nginx

vi nginx-ingress.yaml 由于使用了metallb ,这里需要把对外暴露service的方式改成 LoadBalancer type: LoadBalancer#type: NodePort apiVersion: v1 kind: Namespace metadata:name: ingress-nginx --- apiVersion: v1 automountServiceAccountToken: true kind…

2022年09月 C/C++(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:最长上升子序列 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5…

计算机丢失msvcp110.dll是什么意思?有哪些方法可以修复

今天&#xff0c;我将和大家一起探讨一个关于计算机的问题——“计算机丢失msvcp110.dll是什么意思&#xff1f;有哪些方法可以修复&#xff1f;”这个问题在我们的日常生活中非常常见&#xff0c;尤其是在使用Windows系统的过程中&#xff0c;可能会遇到这样的问题。那么&…

基于Java+SpringBoot+Vue前后端分离体育馆管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

代码随想录算法训练营第四十六天|139.单词拆分、多重背包、背包问题总结

139.单词拆分 ★ 文档讲解 &#xff1a; 代码随想录 - 139.单词拆分 状态&#xff1a;再次回顾。&#xff08;★&#xff1a;需要多次回顾并重点回顾&#xff09; 本题其实不套完全背包思路来理解反而更简单易懂一点。 动态规划五部曲&#xff1a; 确定dp数组&#xff08;dp ta…

基于Red Hat Enterprise Linux 7操作系统的PostgresSql15的备份恢复(实践笔记)

零、前言 本文是基于阿里云ECS服务器进行的实践操作&#xff0c;操作系统版本&#xff1a;Red Hat Enterprise Linux 7 PG数据库版本&#xff1a;PostgresSql 15 PG安装方式&#xff1a;yum 由于本人新接触pg数据&#xff0c;本次也是出于好奇&#xff0c;就对pg数据库的pg_du…

二级MySQL(八)——删除表格数据

1、删除特定的数据记录 DELETE FROM tb_student WHERE studentName 黄涛; 删除前&#xff1a; 删除后&#xff1a; 2、带子查询的删除 DELETE FROM tb_student WHERE studentNo (SELECT studentNo FROM tb_student_copy WHERE studentName 孙新); 删除前&#xff1a; 删…

西北大学计算机考研844高分经验分享

西北大学计算机考研844经验分享 个人介绍 ​ 本人是西北大学22级软件工程研究生&#xff0c;考研专业课129分&#xff0c;过去一年里在各大辅导机构任职&#xff0c;辅导考研学生专业课844&#xff0c;辅导总时长达288小时&#xff0c;帮助多名学生专业课高分上岸。 前情回顾…