豆瓣读书:https://book.douban.com/subject/30348061/
最近看了一本《自己动手构造编译系统:编译、汇编与链接》感觉收获还是挺大的,
就顺手搜了一下,看看还有没有类似的书籍可以读一下,就找到了这本书。
之前读过一本《深入 Java 虚拟机》算是对于我有关 “虚拟机” 技术的启蒙读物了。
虽然学的时候一知半解,但自此埋下了好奇的种子。
现在看的这本书《自己动手实现 Lua》看起来更接地气一些,
作者带领我们用 go 语言从零实现了 Lua 虚拟机(chunk 的解释器),以及编译器和标准库。
- 准备
- Lua 虚拟机 和 Lua API
- Lua 语法和编译器
- Lua 标准库
如果对虚拟机技术比较感兴趣的话,可以重点读第二部分,
作者解释了二进制 chunk 的构成,虚拟机所支持的指令集,然后一点点把整个虚拟机实现,
支持了以下这些语言特性:算术运算,表操作,函数调用(闭包),FFI 调 Go,元编程,异常处理。
在读这本书之前,我留意了几个重要的点:
- Lua 从 1.0 版本开始就内置了 虚拟机
- Lua 二进制 chunk 的格式(包括 虚拟机指令)并没有标准化,属于官方内部实现细节
- Lua 5.0 之前用的是基于栈的虚拟机(栈机),从 5.0 开始改成基于寄存器的虚拟机(本书介绍)
- JVM 用的是变长指令集,而 Lua 用的是定长指令集(4字节[32 bit])(6bit 操作码/ 26bit 操作数)
- Lua 5.3 总共包含了 47 条指令
- MOVE 指令支持的寄存器数最多为 255 个,所以 Lua 编译器会把函数局部变量限制在 200 个以内
我来重点介绍一下作者在 第二部分(Lua 虚拟机 和 Lua API)的行文思路。
虽然是基于寄存器的虚拟机,但是指令的计算过程,却跟栈机的原理很相似,
即,在计算之前先把操作数压栈,计算完后弹栈,再把结果压栈。
(用寄存器机作为底层实现,是因为这样可以减少指令集,但会增加指令长度)
这个 “栈” 其实就是 Lua 虚拟机最基本的组成部分了,它里面可以加入基本的数据类型,还可以加入表,
甚至函数调用帧也是基于 “栈” 这个数据结构来实现的。
作者从 Lua 栈开始,不断给它增加 API,最后形成的就是 Lua API。
每个 Lua 解释器有一个 lua_State 实例,Lua API 体现为一系列操作 lua_State 结构体的函数。
- Lua 栈(luaStack)(虚拟栈)
- 【字段:slots, top】
- 【方法:check, push, pop, get, set …】
- Lua State(封装了整个 Lua 解释器状态)
- 【字段:stack】
- 【方法:GetTop, CheckStack, Pop, Copy, PushValue, Replace, Insert, Remove, SetTop, TypeName …】
- 扩展 Lua State 接口(算术运算)
- 【方法:Arith, Compare, Len, Concat】
- LuaVM(Lua API 是对用户提供的,Lua VM 是为了内部实现,要扩展 Lua State 又不影响 Lua API)
- 用 Lua State 模拟寄存器
- 【字段:LuaState】
- 【方法:PC, AddPC, Fetch, GetConst, GetRK】
- 扩展 Lua State(表相关的操作)
- luaTable【字段:arr, _map】,并且 Lua 栈(寄存器)中可以直接保存一个 luaTable
- 关于表的操作:从寄存器中拿到表, 拿到索引,进行操作,将结果压栈
- 【方法:NewTable, CreateTable, GetTable, SetField, GetField】
以上就是一个简单的寄存器虚拟机的实现了,可以实现多数寄存器指令的操作。
但为了实现函数调用指令(以及 FFI,元编程 等语言特性),还需要进行以下扩展:
- 扩展 Lua 栈(luaStack)
- 【字段:prev, closure, varargs, pc】
- 让 luaState 充当函数调用栈
- 【方法:pushLuaStack, popLuaStack】
- 【方法:Load, Call】
- Load:加载二进制 chunk,把主函数原型实例化为闭包推入栈顶
- Call:把被调函数推入栈顶,参数入栈,函数执行完后弹栈,把返回值压栈
如此这般,后面 FFI 部分(Lua 调 Go),闭包,元编程,异常处理,就更容易理解了。
总之,本书是一本很值得读的参考书,读起来能对虚拟机的实现细节有直观的认识,
作者在介绍的时候也很细致,美中不足的是字里行间代码片段比较多,而且没有整体的认识。
如果每个章节能有一个概念的整体关系图就好了。
茶余饭后值得阅读消遣一下。