lua虚拟机
阅读源代码的次序
首先、阅读外围的库是如何实现功能扩展的,
然后、阅读 Lua 的具体实现。
之后、可以开始了解 Lua VM 的实现。
接下来就是分别理解函数调用、返回,string,metatable,table实现
debug模块是一个额外的设施、
最后是parse 等等编译相关的部分。
垃圾收集将是最难的部分,可能会花掉最多的时间去理解细节。Lua GC 的源码剖析
虚拟机核心功能
文件 | 作用 |
---|---|
lua.c | 可执行main函数入口 |
lapi.c | C语言接口 |
ldebug.c | Debug接口 |
ldo.c | 函数调用、栈管理 |
lfunc.c | 函数原型及闭包管理 |
lgc.c | 垃圾回收机制 |
lmem.c | 内存管理 |
lobject.c | 对象操作函数 |
lopcodes.c | 虚拟机字节码定义 |
lstate.c | 全局状态机 管理全局信息 |
lstring.c | 字符串池 |
ltable.c | 表类型的相关操作 |
ltm.c | 元方法 |
lvm.c | 虚拟机 |
lzio.c | 输入流接口 |
源代码解析和预编译
文件 | 作用 |
---|---|
lcode.c | 代码生成器 |
ldump.c | 序列化预编译的Lua字节码 |
llex.c | 词法分析器 |
lparse.c | 解析器 |
lundump.c | 还原预编译的字节码 |
内嵌库
文件 | 作用 |
---|---|
lauxlib.c | 库编写用到的辅助函数库 |
lbaselib.c | 基础库 |
ldblib.c | Debug库 |
linit.c | 内嵌库的初始化 |
liolib.c | IO库 |
lmathlib.c | 数学库 |
loadlib.c | 动态扩展库管理 |
loslib.c | OS库 |
lstrlib.c | 字符串库 |
ltablib.c | 表处理库 |
外部符号的前缀指示其来自的模块:
luaA_-lapi.c
luaB_-lbaselib.c
luaC_-lgc.c 垃圾回收部分
luaD_-ldo.c 函数的运行流程:函数调用及返回
luaE_-lstate.c 虚拟机的当前状态
luaF_-lfunc.c function实现
luaG_-ldebug.c
luaH_-ltable.c table实现
luaI_-lauxlib.c
luaK_-lcode.c
luaL_-lauxlib.c / h,linit.c(公共函数)
luaM_-lmem.c 内存管理
luaO_-lobject.c 不同的数据类型
luaP_-lopcodes.c 虚拟机的行为是由一组 opcode 控制的
luaS_-lstring.c string实现
luaT_-ltm.c 元表
luaU_-lundump.c
luaV_-lvm.c 虚拟机对 opcode 的解析和运作
luaX_-llex.c
luaY_-lparser.c
luaZ_-lzio.c 带缓冲的流处理
lua_-lapi.c / h + luaconf.h,debug.c
luai_-luaconf.h
luaopen_-luaconf.h +库(lbaselib.c,ldblib.c,liolib.c,lmathlib.c,
loadlib.c,loslib.c,lstrlib.c,ltablib.c)
结构体/类型
Value结构体
1 | /* |
TValue结构体
1 | /* |
GCObject
1 | /* |
可回收的类型,都继承自GCObject
- TString
- Udata
- Proto
- Closure
- Table
TString的定义
1 | /* |
Udata定义
1 | /* |
Proto定义:
1 | /* |
Closure分为两种,Lua闭包和C闭包,定义如下:
1 | /* |
Table定义:
1 | typedef struct Table { |
从面向对象的角度分析的话,可以认为这5种内部基础类型,都继承自GCObject。
创建一个内部对象,使用同一个的接口函数luaC_newobj (lua_State *L, int tt, size_t sz)
参数说明:
1 | /* |
GCObjcet类型
通过统一的接口luaC_newobj函数,创建的内部对象都是GCObjcet类型。如果要正常使用,还需要做一次转换,LUA对于这种抽象结构转换为具体对象结构的行为,封装了一套宏函数:
1 | /* macros to convert a GCObject into a specific value */ |
推荐一本书<自己动手实现lua虚拟机>
lundump文件
字节流结构 二进制 chunk
头部header
{
签名, “\x1bLua” (0x1b4c7561)
版本, 0x53
格式(0x00) 0x00
LUAC_DATA 0x1993 0d 0a
cint 4
sizet 8
lua虚拟机指令 4
lua_integer 8
lua_number 8
lua_int 0x5678(判断大小端)
lua_num 370.5 (浮点数格式)
}
函数原型
- 源文件名
以@开头的是源码编译而来,以=开头的,是标准库而来 - 起止行号
两个cint,主函数为0 - 固定参数个数
- 是否是Vararg函数
- 寄存器数量
MaxStackSize, 因为lua是一种栈结构,可以按索引访问,模拟寄存器 - 指令表
- 常量表
- Upvalue表 {Instack,Idx}两个字节
- 子函数原型表
- 行号表. 和指令表中的指令一一对应
- 局部变量表
LocVar
{
}VarName String StartPC Uint32 EndPC Uint32
- Upvalue名列表
行号表、局部变量表、Upvalue名列表 都是调试信息
解析二进制 chunk
//头部header校验
lundump.h 里面看 checkHeader函数
//函数原型
LoadCode(S, f);
LoadConstants(S, f);
LoadUpvalues(S, f);
LoadProtos(S, f);
LoadDebug(S, f);
指令集
lopcodes文件
- 基于栈的虚拟机(Stack Based)
Java、.NET、CLR、Python、ruby、Yarv;
PUSH/POP操作栈,指令集大,平均长度短 - 基于寄存器(Resigter Based), lua_5.0以后
需要把寄存器地址编码进指令,平均长度长
lua采用定长指令集(大约47条指令), 每条指令4字节32位,6位Opcode操作码,26位操作数Operand
指令编码格式
编码模式
按照高26位区分,四种mode, iABC、iABx、iAsBx、iAx
iABC可以携带ABC三个操作数8+9+9比特
iABx携带 A、Bx,8+18
iAx Ax,26
iAsBx As、Bx 8+18
操作码
6位,最多64条指令,参看opcodes
操作数
A主要用来表示目标寄存器索引,OpArgN、U、R、K
指令表
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES]
指令解码
CREATE_ABC、CREATE_ABx、CREATE_Ax
sBx是有符号整数,18位。 Excess-K编码模式,Offset Binary. x-K. K取最大无符号一半
Lua API
主要以Lua_开头的。60多个luaL_开头的辅助函数,付主函数建立在基础函数之上
Lua栈
Lua栈是宿主语言和Lua语言沟通的桥梁,api基本上也都是操作这个所谓的栈结构lua_state
Lua数据类型
8种, nil、boolean、number、string、table、function、thread、userdata
虚拟机雏形 Lua运算符
程序计数器(Program Counter, 简称PC)记录正在执行的指令。
表
lua表是一个关联数组, 包含哈希表和数组两个部分
函数调用
参数
- 固定参数个数,未传递则nil,多传递则忽略
- 返回值,外部接受几个,多退少补nil的策略,作为函数参数,如数覆盖
load,加载二进制chunk或者源码。把被调函数推入栈顶
call,
交互 lua <-> 其它语言
lua注册表,lua_status里
lua全局环境 G, GlobalTable
闭包和Upvalue
- 一等函数,java不支持,可作为参数传递,返回等
- 变量作用域。 动态作用域、静态作用域
- 闭包。 词法作用域捕获了非局部变量的嵌套函数
Upvalue是lua里面的术语,就是闭包内部捕获的非局部变量。
嵌套函数,捕获外围的外围的函数的变量,外围函数会捕获更外围的局部变量。扁平闭包。
_ENV — 全局环境 隐式的Upvalue
元变成 Metaprogram
值类型默认没有元表,元表nil。 字符串提供了默认元表。
迭代器
迭代器模式.
数值for循环是借助FORPREP和FORLOOP两条指令完成
通用for循环,TFORCALL和TFORLOOP两条指令
异常和错误处理
Lua语法和编译器
- 词法分析
- 抽象语法树
- 语法分析
- 代码生成
词法分析
字符流(源码),以’token’的形式分解
类型注释、关键字、标识符、字面量、运算符、分隔符等
lua会忽略 \n \r \t \v \f 空格等空白字符
忽略注释
token -> { … ; : . } .etc
抽象语法树 AST
计算机编程语言一般使用上下文无关文法(Context-free Grammar, CFG)描述,而CFG一般使用巴科斯范式(Backus-Naur Form, BNF)或者其扩展EBNF(Extended BNF)书写
语法分析
YACC、Bison、ANTLR、JavaCC