鱼C论坛

 找回密码
 立即注册
查看: 2251|回复: 8

[技术交流] 【解释器原理】进击的虚拟机(入门篇)

[复制链接]
发表于 2017-1-17 22:10:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
大家好,窝是目录(窝在无名侠的无名团队里边叫目录),这是应该是窝的第一个帖子吧。
之前看到网上关于HLLVM(高级语言虚拟机)的东西很少,
so 一下子就忍不住了,
由于不敢在百度贴吧这种坑逼网站发布
之前也了解过fishC论坛,感觉挺不错的,至少没那么多伸手党,也没发生过类似于 Quarrel war Ⅰ 一类的武装冲突。
so 决定了,就在这发。
(psⅠ:先说好了,JIT不关我事蛤。
(psⅡ:由于fishc论坛帖子图片的支持性不是很好,所以这篇文章没有图片。

======================================== The divider Ⅰ ========================================

原理
        首先,我们从原理来讲。
        所谓高级语言虚拟机,就是解释器的一种。而解释器恐怕大家都并不陌生吧:像咱经常用的翻译软件,根据输入的英文,找到对应的中文释义并输出(具体过程可能会更复杂);或者是Shell:根据输入的命令(行?)找到对应的op(操作)并执行。
        从上面的栗子中我们可以发现解释器的基本运行过程(流程):

输入->(保存输入)->匹配操作->(保存结果)->输出

也就是说,解释器的运行流程,是一个交互的过程(不管是人机交互还是文件交互什么的)。
        辣嚒,看似神秘高深的HLLVM就变得很简单了。
        辣嚒,我们从解释器的运行流程开始剖析。
        首先是输入,几乎所有虚拟机都是有数据载入的,我们先从常规的(主流的)载入方式说起,像现在的一些高级语言虚拟机,如JavaVM,PythonVM(pyc载入)等等,都是从磁盘载入的,辣嚒就应该考虑载入位置的问题,
现在有两种方案,一种是虚拟机初始化时载入;另一种是Runtime(运行时)载入;执行个字节码读取一个。很显然,第二种果断干掉,为啥?原因很简单,毕竟并不是所有人都买得起SSD硬盘的(包括楼楼,被DELL坑得好惨),机械硬盘在某种实时性很强的地方是有很大的问题的,一是读取需要旋转磁盘盘片,二是读取的速度不稳定;还有就是跳转指令如LG_IMP_IF_FALSE或LG_LOOP_IF_FALSE很难实现,so 不用我再详细的解释了吧。
        再来就是保存输入,这个不用怎么说,用C++实现很简单,一行std::vector<char> ByteCode;砸下去就完事了,但是用C语言的就尴尬了,必须自己来实现跳表(我觉得也不对吧,毕竟有标准库这种东西),如果是Python……嗯……嗯……(羡慕)。
        再来就是匹配操作,所谓匹配操作是怎么一回事呢?匹配操作就是根据特定的标记符Byte code(字节码)得出所需做的操作。那么,我们把保存在虚拟机内存空间的字节码看作一个字节流,然后用一个大循环来分别解释这些字节码,

  1. While(explain(read_bytecode()));
复制代码


然后就是指令分派,为了让字节码和操作一一对应。这里有有两种方案可以考虑,一种是用一个巨大的函数里边装一个巨大的switch来分派;另一种是用函数指针数组的方式。这种说法可能有些绕口,简单来说就是用函数指针来实现多态性(一种方法,多种操作)。好吧我知道这么解释对不用OOP的人来说和没解释没什么两样。就是说用字节码指令号来作为函数指针的偏移地址(看过窝的一个内存专题的应该知道)

  1. typedef void(*_op)(void) runop;
  2. runop op_list[X] = {……};
复制代码

但由于是用函数指针会降低访问速度,并且内联不能与函数指针配合。
辣嚒我们用一个函数(由于效率问题,最好用内联函数。之所以不用宏替换是为了可读性方面考虑)来解释字节码指令(虽然那个巨大的解释函数窝差点没写吐)

  1. bool explain(const char bytecode) {
  2.         switch(bytecode) {
  3.         ……
  4.         }
  5. }
复制代码

        然后就是保存结果,窝这里所说的保存结果并不是指运算结果如

  1. Bytecode:
  2. PUSH_CONST                1        (4)
  3. PUSH_CONST                2        (9)
  4. POP_ADD

  5. >> 13
复制代码

这样的,
窝所说的运行结果是指日志文件,如出错日志、GC日志、对象活动日志一类的文件,它们通常以xml文件的形式表现,而有些大型的工业级的VM日志甚至由数据库管理。(网上那个说用html文件的形式表现的ZZ粗来,我保证不把你屎打粗来)
        最后,输出应该好理解,一般的输出就是指Basic output(大概是这个吧),这里所说的基本输出并不是指BIOS,而是指像输出流:控制台/文件输出什么的。(就是利用标准库输出)辣嚒,来一段示例:

  1. printf(“Hello_World!”);                                //C
  2. std::cout << “Hello_World!”;                        //C++
  3. qDebug() << “Hello_World!”;                //Qt
  4. System.out.PrintIn(“Hello_World!”);        //Java
  5. print(“Hello_World!”)                                #Python
  6. (print “Hello_World!”)                                #(Lisp)
复制代码

各种语言的标准输出。
当然有些是图形界面输出这我就不说了。
(psⅢ:虚拟机如果加上图形界面,可移植性会大幅度降低,所以javaEE的GUI组件相应速度才如此之慢,所以PHP才被实现为数据处理语言,当然Python那个靠Qt作弊的不算啊<Qt万岁!>

【一个开头忘说了但很重要的东西】
(ps:注意窝下面说的话很可能不正确,甚至是谬论,你只用知道里面的技术就行了,因为窝并不是很懂计算机史。
        最早的虚拟机,是以模拟真实的计算机为目的的,它们与计算机硬件(架构)非常相似,如DosBox等。而随着虚拟机的技术愈发完善,更Light的(注意我这里说的并不是运行速度)、更抽象的虚拟机也逐渐被提出,如PythonVM。人们发现:线程虚拟机并不需要完全模拟计算机,只需要符合 冯·诺依曼 提出的 储存->运行 的规则就行,于是新的计算模型被提出——基于堆栈的虚拟机,而现在,寄存器机和栈机各自的优势并不相同,so 产生了较大的分歧(照现在看来在HLLVM这块应该是基于堆栈大获全胜)。
        那么,该如何选择架构?这个可以从两种架构所对应的指令集来说。首先说栈的指令集:基于栈的指令集代码紧凑,操作数通常<=1,占用较小;而基于寄存器的指令集,由于是多地址,所以通常占用较大。所以,选栈吧骚年。
(ps:以上【一个开头忘说了但很重要的东西】全凭个人主观臆断瞎逼逼,不喜勿喷

======================================== The divider Ⅱ ========================================

实现
好了,原理部分讲完了,接下来该说说具体实现了。
其实挺简单的
就拿窝写的第一个虚拟机来说吧(由于版面问题,现给出部分源码
首先是运行环境,

  1. //==========Domo==========
  2. //std::vector<char> bytecode;        //字节流
  3. //std::vector<long double> const_pool;
  4. unsigned long bytecodepre;
  5. std::stack<long double> op_stack;
  6. //字节码
  7.         enum {
  8.                 op_push,
  9.                 op_pop,
  10.                 op_add,
  11.                 ……
  12.                 op_print,
  13. }:
  14. char bytecode[] = {        //DeBug
  15.         op_push, 1,
  16.         op_push, 2,
  17.         op_push, 3,
  18. op_add,
  19. op_add,
  20. op_print,
  21. };
  22.         //由于需要提高运行效率,所以部分需要宏定义:
  23.         #define Read_bytecode() bytecode[bytecodepre]
  24.         #define bytecodepre_addo() bytecodepre++
  25.         #define bytecodepre_subo() bytecodepre—
  26.         #define bytecodepre_add(X) bytecodepre+X
  27.         #define bytecodepre_sub(X) bytecodepre-X
  28. //主体框架
  29. bool explain(char bytecode) {
  30.         bytecodepre_addo();
  31.         switch(int bytecode) {
  32.         case op_push: {
  33.                 stack.back_push(const_pool[Read_bytecode()]);
  34. } return true;
  35.         ……
  36.         ……
  37. }
  38. };
  39. int main(int argc, char** argv) {
  40.         while(explain(Read_bytecode()));
  41.         return 0;
  42. };
复制代码

好吧窝腾过来的时候偷懒没分文件
(我都好久没碰代码了,再加上被VS惯养了,所以恐怕会有不少错误,所以如果有问题,请在评论区留言,谢谢。
由于作者时间有限,只能完成这么多,所以更高级的虚拟机的设计就留在进阶篇讲解。
欲深入研究HLLVM(高级语言虚拟机),请参阅以下几本书(按排名):
《Python源码剖析》注意是Python源码剖析,但讲的是Python虚拟机
《深入理解Java虚拟机》——JVM高级特性欲最佳实践
《虚拟机的设计与实现C/C++》一个物理学家转程序员的经典著作,但技术较老
-没事还可以去看看Lua虚拟机源码啥的。
Ps:由于本人文笔极差(从文中大量使用括号就能看粗来),所以请各位大大多多支持哈。
同时,我将尽快的将我的各种填好的坑移植到鱼C(OSChina、网易):
(ps:妈蛋,自己挖的坑,含泪也得填完啊。
【解释器原理】进击的高级语言虚拟机(进阶)
        主要衔接入门篇,实现一个(更高级的)虚拟机的对象机制、多线程、栈帧、模块动态加载机制。
【无名学院-目录】内存专题
        从C/C++的各种内存操作符讲起,深入剖析指针与内存,了解其本质,并逐步实现一个智能指针的封装和一个微型内存管理机制(就是窝最新的虚拟机的那套机制。
Java的引用也要讲一些

嗯……这篇文章窝也数了数。嗯,着实为本人平生良心之作,满满的都是干货,绝对没水。所以……嗯…… @无名侠 @无名侠 @无名侠 /傲娇 /傲娇 /傲娇
最后,我想说的是
        励志创造人生,编程改变命运。
谢谢。

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
黑龍 + 5 + 5 哇 好厉害哦。

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2017-1-17 22:36:19 | 显示全部楼层

污名不理我
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-18 04:21:11 | 显示全部楼层
傲娇!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-18 10:57:06 | 显示全部楼层
哇 好厉害哦。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-1-18 11:01:35 | 显示全部楼层

欸,面包店,你咋不是版主了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-18 11:07:22 | 显示全部楼层
CPUfhg 发表于 2017-1-18 11:01
欸,面包店,你咋不是版主了?

谁是面包店
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-1-18 11:08:36 | 显示全部楼层

面包你也不理我
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-1-18 11:23:50 | 显示全部楼层
好吧刚刚又检查了一遍,发现一个很严重的问题——排版乱了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-18 13:13:01 | 显示全部楼层

黑龙版主快快回归`
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-28 20:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表