欢迎光临散文网 会员登陆 & 注册

自己动手实现一个有JIT的虚拟机

2022-01-01 17:11 作者:MIAIONE  | 我要投稿

由于发这篇专栏的时候我还在读高二,没学过编译原理,不过我还是去查阅了资料,并试着以我自己的理解实现JITVM。

当你已经熟练了掌握一门编程语言之后,可能你并不满足当前一些语言,于是你觉得自制一门语言,它可以是解释型,也可以是编译型的,目的都是更好的实现及针对化的去满足使用需求,比如一众小游戏基本都有自己的脚本,哪怕再简单的那种,也是对自己游戏开发效率、生态的一种扩充(开发mod),同时删掉一些不太想要的功能,比如游戏脚本我不想让他操作file类,或者runcmd,这些操作都是极为危险的,更何况有人还要发到steam上的创意工坊,于是我们才要自己实现一门比脚本语言性能更好的语言。

然而,当你每开发一个新的项目,就会对你当前的语言有不同的要求,无疑拖慢了开发效率并降低了兼容度,而实现多种语言共同使用一套标准的虚拟机就显得尤为重要。同时考虑到性能,我们还要加入JIT。

这里以JVM的原理为例,因为我并没有深入学过JVM,这里简化来讲,如有不对还请指出:

我们都知道CPU只能运行编译后的机器码,而java编译后是bytecode,即字节码,而我们必须意识到,没有编译过程的代码,一定以某种方式去解释该代码才能运行,所以jvm的底层本质还是会有if去判断代码的,并且我们无需担心if的效率,毕竟if只是写多了很乱而已,效率其实并不低。

以上便是一个VM最最基本、也是最重要的过程--解释非本机代码,并实现方法,也就是说,字节码不直接参与到CPU的执行过程。

而JIT(Just in time compilation)即时编译,才是我们要重点实现的,也是提高性能的根本。

那么,我们该如何去实现一个JIT呢?

我们假设有以下需求的(伪)代码:

static void startGame(String gamePath)

{

Process.Start(gamePath);

}

首先我们进行分析:

1.这是一个static的void,是静态的,void代表不返回,该代码是过程

2.参数为string字符串为常量,甚至实际的时候有可能我们会写死这个程序的路径

3.调用了VM的基本库process,也是静态过程start,传入string


这代码确实很像C#

通过分析我们发现,改该过程可以被简化成以下形势:

startGame("YuanShen.exe");

简化为

Process.Start("YuanShen.exe");

假设process类我们可以编译成本机代码,那么以上代码完全可以被编译成本机代码(数据地址)的形式。

这整个过程,就是JIT做的--把尽可能本机化的代码全部编译成当前平台的本机代码,并把引用放进代码池,运行到这个地方时,直接运行本机代码,而不是在VM内加减寄存器、调用VM方法来进行实现。


于是我们得到JIT一个大概的工作流程:

(代码标准化/统一为字节码)->词法分析->语法分析->语义分析->执行流分析->本机优化->本机代码拼接-->链接VM内数据地址->合成本机代码


其实不难看出,这个过程在编译阶段就执行过一遍,但是他会比字节码编译多一个本机优化,JIT的意义不仅是提高代码的执行效率,也能在不同的平台之上通过获取相关信息进行针对性优化,使得生成的本地代码更快更适应当前平台。


下一篇我们先来实现基础部分,实现一个最简单的VM并在自己的VM运行最简单的代码--hello world!



今天先说到这里吧,手机码字,错误请指出。

自己动手实现一个有JIT的虚拟机的评论 (共 条)

分享到微博请遵守国家法律