[toc]

# Lua 虚拟机到执行代码流程

如上图所示步骤如下:

    1. lua_open->lua_newState 创建一个 luaState虚拟机 ,在这个过程中会触发内存分配
    1. lua_openlibs 这个过程会注入所有的 lib
    1. lua_dofile 会执行对应的 lua 源码,do_file 时会先进行 luaL_loadfile , 然后进入 lua_pcall 执行对应的代码
    1. 最终会进入 f_parser , 通过这个函数开始词法 (lexer) 和语义 (parser) 分析
    1. 先进入 luaX_next (词法分析), 获取到 token
    1. 词法分析结束后进入 chunk (EBNF 语义分析), 生成字节码,返回 Proto 对象回 f_parser
    1. 这些数据包裹到 Closure 上,处理结束后,进入第 3 步里的 lua_pcall , 准备执行字节码
    1. 选择函数的过程需要了解下 lua 中的闭包,(等下讲), 这里说下,lua 中每个闭包语义分析结束后都放到了栈中,所以我们可以通过闭包找到 function 的位置,即下一个待执行块的函数指针 (即前面放入状态机的Closure)
    1. 继续往下执行,最终会进入 luaD_call 函数,luaD_call 进入 luaD_precall 进行函数执行前的准备工作
    • 9.1 从 lua_State 的 CallInfo 数组中得到一个新的 CallInfo 结构体,设置它的 func、base、top 指针
    • 9.2 从 Closure 指针中取出保存下来的 Proto 结构体,这个结构体保存着分析过程完成之后生成的字节码等信息。
    • 9.3 Proto 的 Code 里存放的就是字节码,然后把上面的 CallInfo 里的 top 和 base 赋值给 lua_State 结构体的 topbase
    1. 接着会进入 luaV_execute ,pc 指针存放的是虚拟机的 OpCode
    1. 大循环 luaV_execute 结束后,回到 luaD_poscall 函数 恢复到上一次函数调用的环境

简要的流程如下:

Proto 是语法 / 词法分析阶段和执行指令的 上下文(数据传输结构体)

接下来介绍 Lua 中的几个关键组件

# 数据结构与栈

Lua 虚拟机相关的数据结构与栈 lua_State 中的 TValue env; 就是对应虚拟机的模拟栈数组,然后虚拟机主要包含以下几个相关成员
- stack : 栈数组的起始位置
- base: 当前函数栈的基地址 - top: 当前函数栈下一个可用位置 其中执行函数与栈的关系如下: 由上图可以看出,每个函数执行 Callinfo 都维护了 func 指针和 top 以及 base 指针,top 和 base 维护的是 函数的参数 Tips: 栈是从下往上扩展的 注意:
Lua 栈大小是有限的,CallInfo 也是有数量限制的

# 指令的解析

接下来分析指令是如何生成的
我们知道 Lua 里函数可以嵌套函数,我们称这个为 闭包 Lua 中使用 FuncState暂存这些信息 ,然后通过这些信息来生成 OpCode

1
2
3
4
5
--最外层FuncState fs1
local function a() --函数a的FuncState fsa
local function b() --函数b的FuncState fsb
end
end

闭包: 即把每个函数当做一个结构 上面的函数的依赖关系如下: FuncState 和 Proto 之间的依赖关系如上图所示

# 指令格式

Lua 虚拟机的指令格式如下图上所示 Lua 中解析指令是从低位到高位解析的 首先是解析 OpCode
, 紧接着跟上三个操作数, A,B,C 指令列表在 Lua设计与实现这本书的P48

更新于

请我喝[茶]~( ̄▽ ̄)~*

Solvarg 微信支付

微信支付

Solvarg 支付宝

支付宝

Solvarg 贝宝

贝宝