Skip to content

Lua虚拟机实现

来点铺垫

Lua会先将脚本编译成字节码,然后由虚拟机执行。Lua closure的底层实现中,Proto.code指向的就是存放字节码的数组。因此虚拟机的效率对Lua的运行至关重要。

栈和寄存器

在Lua 5.0版本之前,Lua采用的是基于栈的虚拟机架构;但从Lua 5.0开始,Lua虚拟机已重构为更高效的基于寄存器的虚拟机实现。在深入介绍Lua虚拟机的底层实现之前,要先理解这两种虚拟机的区别:

  • 在基于栈的虚拟机中,所有操作都通过一个栈来进行。操作数从栈中弹出,计算完成后结果再压入栈中。这种设计简单直观,但在执行效率方面存在一些劣势。
  • 基于寄存器的虚拟机使用一组虚拟寄存器来存储操作数和中间结果。每条指令可以直接引用这些寄存器,避免了频繁的栈操作,显著提升了执行效率。

例如,对于同一段代码:

lua
local a, t, i
a = a + i
a = a + 1
a = t[i]

在基于栈的虚拟机中,可能会按照以下指令执行:

text
PUSHNIL   3   ; local a, t, i
GETLOCAL  0   ; a
GETLOCAL  2   ; i
ADD           ; a = a + i
SETLOCAL  0   ; a
GETLOCAL  0   ; a
ADDI      1   ; a = a + 1
SETLOCAL  0   ; a
GETLOCAL  1   ; t
GETINDEXED 2  ; t[i]
SETLOCAL  0   ; a = t[i]

而在基于寄存器的虚拟机中,指令锐减:

text
LOADNIL 0 2 0   ; local a, t, i
ADD     0 0 2   ; a = a + i
ADD     0 0 250 ; a = a + 1
GETTABLE 0 1 2  ; a = t[i]

NOTE

以上示例来自于Lua官方paper《The implementation of Lua 5.0》,这里俺就偷懒了。

字节码参考

操作码名称类型参数格式功能描述
OP_MOVEMOVEiABCA B将寄存器B的值移动到寄存器A,如果B是临时变量则可能被重用
OP_LOADILOADIiABxA sBx将立即数sBx(有符号整数)加载到寄存器A,sBx范围为-131071到131071
OP_LOADFLOADFiABxA sBx将浮点常量sBx(有符号整数转换为浮点)加载到寄存器A
OP_LOADKLOADKiABxA Bx从常量表中加载索引为Bx的常量到寄存器A,Bx最大值为262143
OP_LOADKXLOADKXiABxA使用EXTRAARG指令的Ax作为常量索引,从常量表加载到寄存器A
OP_LOADFALSELOADFALSEiABCA将false值加载到寄存器A,通常用于布尔表达式或条件判断初始化
OP_LFALSESKIPLFALSESKIPiABCA加载false到寄存器A并跳过下一条指令,用于优化短路逻辑表达式
OP_LOADTRUELOADTRUEiABCA将true值加载到寄存器A,通常用于布尔表达式或条件判断初始化
OP_LOADNILLOADNILiABCA B将nil值加载到从寄存器A到B的所有寄存器,用于变量初始化或清除状态
OP_GETUPVALGETUPVALiABCA B从当前闭包的上值表中获取索引为B的上值到寄存器A,用于访问外层局部变量
OP_SETUPVALSETUPVALiABCA B将寄存器A的值设置到当前闭包的上值表中索引为B的位置,用于修改外层局部变量
OP_GETTABUPGETTABUPiABCA B C从当前闭包的上值表中获取索引为B的上值(必须为表),然后获取该表中键为C的值到寄存器A
OP_GETTABLEGETTABLEiABCA B C从寄存器B(必须为表)中获取键为C的值到寄存器A,如果键不存在则返回nil
OP_GETIGETIiABCA B C从寄存器B(必须为表)中获取整数键C的值到寄存器A,优化了整数键访问性能
OP_GETFIELDGETFIELDiABCA B C从寄存器B(必须为表)中获取字符串键C的值到寄存器A,优化了字符串键访问性能
OP_SETTABUPSETTABUPiABCA B C在当前闭包的上值表中设置索引为A的上值(必须为表)的键B的值为C,用于修改外层表字段
OP_SETTABLESETTABLEiABCA B C设置寄存器A(必须为表)的键B的值为C,如果表不存在会触发错误
OP_SETISETIiABCA B C设置寄存器A(必须为表)的整数键B的值为C,优化了整数键设置性能
OP_SETFIELDSETFIELDiABCA B C设置寄存器A(必须为表)的字符串键B的值为C,优化了字符串键设置性能
OP_NEWTABLENEWTABLEiABCA B C创建新表并存储在寄存器A中,B指定数组部分初始大小,C指定哈希部分初始大小
OP_SELFSELFiABCA B C准备方法调用,将寄存器B的键C方法放入寄存器A和A+1
OP_ADDIADDIiABCA B sC寄存器B加立即数sC结果存入A
OP_ADDKADDKiABCA B C寄存器B加常量C结果存入A
OP_SUBKSUBKiABCA B C寄存器B减常量C结果存入A
OP_MULKMULKiABCA B C寄存器B乘常量C结果存入A
OP_MODKMODKiABCA B C寄存器B模常量C结果存入A
OP_POWKPOWKiABCA B C寄存器B的常量C次方结果存入A
OP_DIVKDIVKiABCA B C寄存器B除常量C结果存入A
OP_IDIVKIDIVKiABCA B C寄存器B整除常量C结果存入A
OP_BANDKBANDKiABCA B C寄存器B与常量C按位与结果存入A
OP_BORKBORKiABCA B C寄存器B或常量C按位或结果存入A
OP_BXORKBXORKiABCA B C寄存器B异或常量C按位异或结果存入A
OP_SHRISHRIiABCA B sC寄存器B右移立即数sC结果存入A
OP_SHLISHLIiABCA B sC寄存器B左移立即数sC结果存入A
OP_ADDADDiABCA B C寄存器B加寄存器C结果存入A
OP_SUBSUBiABCA B C寄存器B减寄存器C结果存入A
OP_MULMULiABCA B C寄存器B乘寄存器C结果存入A
OP_MODMODiABCA B C寄存器B模寄存器C结果存入A
OP_POWPOWiABCA B C寄存器B的寄存器C次方结果存入A
OP_DIVDIViABCA B C寄存器B除寄存器C结果存入A
OP_IDIVIDIViABCA B C寄存器B整除寄存器C结果存入A
OP_BANDBANDiABCA B C寄存器B与寄存器C按位与结果存入A
OP_BORBORiABCA B C寄存器B或寄存器C按位或结果存入A
OP_BXORBXORiABCA B C寄存器B异或寄存器C按位异或结果存入A
OP_SHLSHLiABCA B C寄存器B左移寄存器C结果存入A
OP_SHRSHRiABCA B C寄存器B右移寄存器C结果存入A
OP_MMBINMMBINiABCA B C调用寄存器B的元方法处理二元操作C
OP_MMBINIMMBINIiABCA sB C k调用寄存器A的元方法处理立即数二元操作
OP_MMBINKMMBINKiABCA B C k调用寄存器A的元方法处理常量二元操作
OP_UNMUNMiABCA B寄存器B取负结果存入A
OP_BNOTBNOTiABCA B寄存器B按位取反结果存入A
OP_NOTNOTiABCA B寄存器B逻辑取反结果存入A
OP_LENLENiABCA B获取寄存器B的长度存入A
OP_CONCATCONCATiABCA B C连接寄存器B到C的字符串存入A
OP_CLOSECLOSEiABCA关闭寄存器A到A的局部变量
OP_TBCTBCiABCA标记寄存器A为待关闭
OP_JMPJMPisJsJ无条件跳转sJ
OP_EQEQiABCA B k比较寄存器B和C是否相等
OP_LTLTiABCA B k比较寄存器B是否小于C
OP_LELEiABCA B k比较寄存器B是否小于等于C
OP_EQKEQKiABCA B k比较寄存器B和常量C是否相等
OP_EQIEQIiABCA sB k比较寄存器A和立即数sB是否相等
OP_LTILTIiABCA sB k比较寄存器A是否小于立即数sB
OP_LEILEIiABCA sB k比较寄存器A是否小于等于立即数sB
OP_GTIGTIiABCA sB k比较寄存器A是否大于立即数sB
OP_GEIGEIiABCA sB k比较寄存器A是否大于等于立即数sB
OP_TESTTESTiABCA k测试寄存器A是否为真
OP_TESTSETTESTSETiABCA B k测试寄存器B是否为真并存入A
OP_CALLCALLiABCA B C调用寄存器A的函数,参数B-1个,结果C-1个
OP_TAILCALLTAILCALLiABCA B C k尾调用寄存器A的函数
OP_RETURNRETURNiABCA B从函数返回寄存器A到B的值
OP_RETURN0RETURN0iABC返回0个值
OP_RETURN1RETURN1iABCA返回寄存器A的1个值
OP_FORLOOPFORLOOPiAsBxA sBx数字for循环
OP_FORPREPFORPREPiAsBxA sBx数字for循环准备
OP_TFORPREPTFORPREPiAsBxA sBx通用for循环准备
OP_TFORCALLTFORCALLiABCA B C通用for循环调用
OP_TFORLOOPTFORLOOPiAsBxA sBx通用for循环
OP_SETLISTSETLISTiABCA B C设置列表元素
OP_CLOSURECLOSUREiABxA Bx创建闭包
OP_VARARGVARARGiABCA B处理可变参数
OP_VARARGPREPVARARGPREPiABCA准备可变参数
OP_EXTRAARGEXTRAARGiAxAx额外参数

本站页面由VitePress驱动,内容基于 CC BY-NC 4.0 许可发布。