深入讲解Lua虚拟机

发布于:2024-10-24 编辑:匿名 来源:网络

作者:郑晓辉 |腾讯游戏客户端开发高级工程师在前面写道:本文所有文字都是我一一手写的,本文后面分享的Demo代码也是我一行行编码的。在我之前很多前辈都研究过Lua虚拟机,所以本文的很多想法肯定是站在这些巨人的肩膀上的。

这篇文章的标题是《Lua虚拟机深入讲解》。其实重点就在这两个字上。

毕竟作者的技术水平有限。但我听说这个名字需要有点奇怪才能让人们阅读这篇文章,因此得名。

谨以此文献给那些对Lua虚拟机感兴趣的人。希望这篇文章能够达到启发他人的效果。

Lua执行流程: Lua代码的整个流程: 如下图所示: 程序员编写Lua文件 -> 语法词法分析生成Lua字节码文件(对应Lua工具链的Luac.exe) -> Lua虚拟机解析字段代码并执行指令集->输出结果。蓝色和绿色部分是本文要讨论的内容。

词法和语法分析:我不打算讲Lua的所有词法分析过程。毕竟如果我浪费太多时间写这个,同学就会问我需求的开发进度怎么样了。

所以长话短说,我会根据我自己的理解。对Lua的理解用一个具体的例子来分析: Lua代码块: If a < b then a = c end 这句话我们程序员都能理解,但是计算机就像是一些男性程序员,负责家里的美丽。

和如花的妻子一样,她只知道这是一个用英文字符拼写出来的毫无意义的字符串。为了让计算机能够理解这句话,我们首先要做的就是分词:既然你看不懂。

我先把这句话一个一个拆成单词,然后告诉你每个单词的意思。分词的结果大概很长。

下面是分词结果(含义) if type_if(if关键字) a type_var(这是一个变量) < type_opless(这是小于数字) B type_var(这是一个变量) then type_then(然后(then then) (then then (then then) 关键字) a Type_Var (这是一个变量) = Type_OpEqual (这是一个等号) c Type_Var (这是一个变量) end? ? ? ? ? Type_End (结束关键字) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?现在计算机终于明白了。原来你写的这行代码有9个单词,每个单词的意思我都明白,那么现在的问题是,计算机还看不懂这句话吗? “吃”,计算机理解“吃”是一个动词,意思是张开嘴,“饭”是一个名词,指的是米饭,但是当你把饭菜放在一起时,计算机不知道它意味着什么。

“张开嘴,把饭放进嘴里,吞进肚子里。”因为计算机只知道“张开嘴”和“米饭”这两个东西,所以计算机无法理解这两个东西之间的联系。

有人可能会说:简单:吃+其他的话。这种结构可以让计算机大致理解将后一个词所代表的东西放入口中的含义,对吗?这种情况适合“吃”这个词,但如果是这样的话,如何让计算机理解“惊喜”这个词呢?那么这就引出了下一个主题:语义解析。

关于语义解析,如果想更深入的了解,可以学习AST(抽象语法树)。然而,对于我们的例子,我们可以通过简单的方式来模拟它来理解它。

对于Lua来说,每个关键字都有自己特殊的结构。因此,Lua的关键字将成为语义分析的重点。

现在我们涉及到 if 的例子: 我们可以简单地用伪代码来表达这个解析过程: 对于 if 语句,我们可以将其抽象成这样的结构: if condition (条件表达式) then dosth (语句块) end 那么对于 if 语句语句块解析的伪代码如下: 代码语言:javascript copy ReadTokenWord(); If(tokenWord.type == Type_If) then ReadCondition() //读取条件表达式 ReadThen() //读取关键字 then ReadCodeBlock() //读取逻辑代码块 ReadEnd() //读取关键字 End End So 依次为 for计算机要理解,我们还是要把这个东西变成数据结构。因为我只是在做一个演示,所以我使用了先验知识。

也就是说,我假设我们的If语句块的逻辑结构是这样的: If 小于条件表达式 then 赋值表达式 End 那么我的Demo中转换成IfStateMent的C++数据结构大致是这样的: OK,所以现在,我们整个词典的语法分析就完成了。但是真正的Lua虚拟机无法执行我们的ifStateMent。

Lua源码中的实现类似于TokenType和结构化的if Statement whileStatement等,而Lua并没有生成完整的语法树。 Lua源码的实现中,会解析一些语句,生成临时语法树,然后翻译成指令集。

它不会等待所有句子都被解析后再进行翻译。语义解析和翻译成指令集是并行的过程。

贴出源码中语义解析的部分实现: 好了,现在我们已经把我们程序员输入的Lua代码变成了数据结构(可以被计算机读取)。下一步就是把这个数据结构变成Lua虚拟机可以理解的东西。

这个东西就是Lua指令集!至于转换过程,对于我们的例子来说,大概是这样的: 代码语言:javascript copy If a < b then a = c end 首先了解一下条件 a

那么 a

LT 后面的指令必须是 JMP 指令。即如果R[10]

同理,继续翻译a=c等。所以 If a < b then a = c end 最终被翻译成: OK 在 demo 中我写的是: OK,现在我们大致了解了如何将 Lua 代码变成指令集了。

现在我们仔细看看Lua5.1指令集: Lua的指令集是定长的,每条指令都是32位,大概是这样的: 每条指令的低六位是指令码,比如0代表MOVE,12代表Add。Lua一共有37条指令,分别是MOVE、LOADK、LOADBOOL、LOADNIL、GETUPVAL、GETGLOBAL、GETTABLE、SETGLOBAL、SETUPVAL、SETTABLE、NEWTABLE、SELF、ADD、SUB、MUL、DIV、MOD、POW、UNM、NOT、LEN ,CONCAT,JMP,EQ,LT,LE,测试,测试集,调用,尾调用,返回,FORLOOP,TFORLOOP,SETLIST,关闭,关闭,VARARG。

我们发现图片上有iABC、iABx、iAsBx。这意味着有些指令格式是OPCODE、A、B、C格式,有些指令是OPCODE A、BX格式,有些指令是OPCODE A、sBX格式。

sBx和bx的区别在于bx是无符号整数,而sbx表示有符号数,即sbx可以是负数。我不打算详细讲每条指令,但我给你举个例子: 指令编码 0x 如何解析这条指令: 0x= 低六位(0~5)是操作码: 01 = 1 = LoadK指令(0~37分别对应上面我列出的38条指令,按顺序,0是Move,1是loadk,2是loadbool...37是vararg)。

LoadK指令格式为iABC(不使用C,仅使用ab)格式。那么让我们继续阅读ab。

a = 低6~13位为= 1,所以a=1 b = 低14~22位为1 = 1,所以b=1 所以0x= LOADK 1, 1 我也写了如何解析指令代码demo中,代码大致是这样的: 所以Lua文件经过Luac编译后生成的Lua字节码。 Lua字节码文件除了指令集之外还包含什么?当然它不会像我上面提到的词法和语法分析演示那么愚蠢。

那么下面我们就来说说Lua字节码文件的结构: Lua字节码文件(*.lua.bytes)包括:文件头+顶层函数: 文件头结构:顶层函数和其他普通函数结构相同:所以我们可以很容易地自己编写代码来解析它。我在后面提供的Demo源码中也实现了字节码文件的解析。

Demo中的例子涉及到Lua源代码以及字节码最终分析得到的信息是: OK,现在本文只剩下最后一件事情了:Lua虚拟机是如何执行这些指令的?大概是这样的: 代码语言:javascript Copy While (命令不为空) 执行命令 获取下一条要执行的命令 End 每个命令应该如何执行? ? ?如果你还有印象的话,我们前面语义分析后转换的指令集如下: a < bLoadK 10, 0: 将_G[ConstVar[0]]加载到10号寄存器中:R[10] = _G[" a"]LoadK 11,1: 加载 _G[ConstVar[1]] 到寄存器 11: R[11] = _G["b"]LT 10,11: 比较是否 R[10]

即如果R[10]

分配过程)。当然,指令后面的文字已经详细描述了指令的执行逻辑,呵呵。

为了真正执行起来,我们的数据结构设计需要1、寄存器:2、常量表:3、全局变量表:为了能够执行我们demo中的例子:我实现了这段代码中涉及到的所有指令代码语言: javascript 复制 insExecute[(int)OP_LOADK] = &LuaVM::LoadK;insExecute[(int)OP_SETGLOBAL] = &LuaVM::SetGlobal;insExecute[(int)OP_GETGLOBAL] = &LuaVM::GetGlobal;insExecute[(int)OP_ADD] = &LuaVM::_Add;insExecute[(int)OP_SUB] = &LuaVM::_Sub;insExecute[(int)OP_MUL] = &LuaVM::_Mul;insExecute[(int)OP_DIV] = &LuaVM::_Div;insExecute[(int) OP_CALL] = &LuaVM::_Call;insExecute[(int)OP_MOD] = &LuaVM::_Mod;insExecute[(int)OP_LT] = &LuaVM::_LT;insExecute[(int)OP_JMP] = &LuaVM::_JMP;insExecute[( int)OP_RETURN] = &LuaVM::_Return;以Add为例: 代码语言: javascript copy bool LuaVM::_Add(LuaInstruction ins){ //R(A):=RK(B)+RK(C) ::: //Todo:必要的参数合法性检查:如果有问题,则抛出异常 // 将ins.bValue表示的数据和ins.cValue表示的数据相加的结果赋值给索引值为ins.aValue的寄存器 luaRegisters[ins .aValue].SetValue( 0、GetBK(ins.bValue) + GetBK(ins.cValue)); return true;} 下面是程序运行效果截图:看完整个流程,其实可以想想这个问题:为什么Lua的执行效率远低于C程序?个人拙见: 1.真假寄存器:Lua指令集中涉及到的寄存器都是模拟寄存器。本质上,它们仍然是内存中的数据。

访问速度取决于CPU对内存的访问速度。 C程序最终可以使用win32指令集或者Arm??指令集来执行。

这里涉及到的寄存器EBX、ESP等都是CPU上的与非门,它们的访问速度=CPU的频率(与CPU访问内存的速度相比,简直是天上地下)。 2、指令集运行的平台:Lua指令集运行的平台就是Lua虚拟机。

C程序指令集直接在硬件支持下运行。 3、C中的数据直接对应内存地址。

Lua中的数据对应于描述该数据的数据结构。因此,分离出这样一层之后,效率就大大降低了。

4、比如Lua的Gc操作等等都是C程序不需要做的事情。 。

。 。

好吧,最后我给大家展示一下我写的这个demo的源码:这个源码是我清明节在家时瞎写的。也就是说,代码还没有耐心编译,清明节有人约我出去喝酒,导致我很长一段时间都处于“我要写完代码了”的心不在焉状态。

快点,我出去喝一杯。”所以有一些编码格式和结构设计随处可见的例子~毕竟只是一个demo。

生活中,要有佛性,顺其自然!如果你真的想了解更多关于Lua虚拟机的知识,那么我建议你有时间和耐心去阅读Lua虚拟机的源码~最后,衷心感谢所有看到最后一句话的同学。感谢您耐心阅读这篇来自技术新手的冗长废话。

深入讲解Lua虚拟机

站长声明

版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。

标签:

相关文章

  • 「褀氏生物」完成数千万元A轮融资

    「褀氏生物」完成数千万元A轮融资

    今日,「褀氏生物」宣布完成数千万元A轮融资。 本轮融资由景泽资本投资,募集资金将用于新产品研发和全球营销渠道建设。 褀氏生物科技成立于2007年,是家主创办的一家以自动化体外诊断系统平台为方向的科技公司。 目前研发方向涵盖细胞学体外诊断、免疫学体外诊断等领域。

    06-18

  • 安徽某县级引导基金招募GP

    安徽某县级引导基金招募GP

    萧县政府产业引导基金子基金管理机构招聘公告 根据《萧县政府产业引导基金管理办法(试行)》(萧政秘【】39号),萧县政府产业引导基金(以下简称(简称“基金之父”)现面向子基金管理机构公开征集。 具体公告如下: 一、子基金基本情况 (一)基金规模 子基金规模原则上不

    06-18

  • 小分子药物开发商“凌科药业”获5000万美元B轮融资,助力药物创新研发

    小分子药物开发商“凌科药业”获5000万美元B轮融资,助力药物创新研发

    投资界(ID:pedaily)8月27日消息,投资界获悉,近期,创新药研发开发公司凌科药业(杭州)有限公司(以下简称“凌科药业”)宣布完成1万美元B轮融资。 本轮融资由礼来亚洲基金领投,联芯资本、杭州和达生物医药产业基金跟投。 此外,现有投资者君联资本、鼎力资本继续加大投

    06-18

  • 佳源科技:2020年亏损近2亿元,同比下降超40%

    佳源科技:2020年亏损近2亿元,同比下降超40%

    今年佳源科技实现营业收入12.02亿元,同比下降16.86%;利润总额2.1亿元,同比下降44.70%;实现归属于母公司所有者的净利润1.85亿元,同比下降43.80%;扣除非经常性损益后归属于母公司所有者的净利润1.63亿元,同比下降48.04%。 听,中小企业反馈平台。 倾听用户需求,倾听创业

    06-18

  • 总投资55亿元的芯投微电子滤波器研发生产总部项目已封顶

    总投资55亿元的芯投微电子滤波器研发生产总部项目已封顶

    芯投微 据芯投微官方微信公众号消息,9月16日,芯投微电子滤波器研发生产总部项目封顶仪式隆重举行。 据悉,该项目总投资55亿元,位于安徽省合肥市高新技术产业开发区。 今年12月正式开工建设,计划于2019年投入运营。 项目建成初期将重点发展射频滤波器设计、研发、生产业务

    06-06

  • 专注敏感数据访问控制,“中图吉人”完成线性资本领投的数千万元Pre-A轮融资

    专注敏感数据访问控制,“中图吉人”完成线性资本领投的数千万元Pre-A轮融资

    投资界动态(ID:pedaily)9月15日消息,专注敏感数据访问控制安防厂商“看图识人”近日完成数千万元Pre-A轮融资。 据介绍,本轮融资由线性资本领投,驰星创投跟投,航程资本提供财务顾问服务。 中图世人成立于今年11月,目前专注于敏感数据访问控制,目标是将每个数字身份与

    06-18

  • 5亿,亿达资本设立无锡人才2号基金

    5亿,亿达资本设立无锡人才2号基金

    据投资界5月17日消息,无锡高新投资亿达鼎奇人才创业投资合伙企业(有限合伙)(简称:亿达无锡人才2号) 2基金)正式注册,基金规模5亿元。 亿达无锡人才二号基金由亿达资本与无锡市滨湖区政府共同发起设立。 主要围绕太湖湾科技创新带建设“十四五”规划,投资符合无锡太湖

    06-17

  • 能链集团获2亿美元战略融资,华兴资本独家FA

    能链集团获2亿美元战略融资,华兴资本独家FA

    能链集团近日宣布完成新一轮2亿美元战略融资,贝恩资本领投,老股东Joy资本持续投入,华兴资本担任独家FA。 独家财务顾问。

    06-17

  • Infinite Fund See Fund二期基金已完成募资6亿

    Infinite Fund See Fund二期基金已完成募资6亿

    投资界(ID:pedaily)5月23日报道,近日,Infinite Fund See Fund二期基金已顺利完成募资6亿,登陆山西。 负责人此前曾透露,See Fund二期基金拥有规模更大的LP资金,并得到了三一重工、中兴通讯等企业的支持。 去年2月,Infinite Fund See Fund完成首笔募资2亿元。 LP阵容极

    06-17

  • VR广告来了,你准备好了吗?

    VR广告来了,你准备好了吗?

    随着扎克伯格在世界移动大会(MWC)上通过VR与记者互动的照片广泛传播,越来越多的人开始关注VR,国内外的各类企业也开始尝试VR创业。 数据显示,短短一年时间,VR技术相关专利申请数量就达到1万件,瞬间爆发。 而考虑到Oculus Rift被Facebook以20亿天价收购的消息,人们也越

    06-18

  • 红杉资本推出规模500-6亿美元的加密货币投资基金

    红杉资本推出规模500-6亿美元的加密货币投资基金

    据The Block报道,红杉资本推出规模500-6亿美元的加密货币投资基金,主要投资流动性代币,包括已在加密货币交易所上市及尚未上市的代币,单个项目投资规模在10万至1万美元之间,计划参与从质押到提供流动性再到治理等流程。 这是红杉资本自2017年成立以来的首只行业专项基金

    06-17

  • 智能硬件厂商,为何要撬动11万亿美元的蛋糕?

    智能硬件厂商,为何要撬动11万亿美元的蛋糕?

    上周(2019年7月7日),麦肯锡全球研究院最新报告发布。 该机构认为,当前市场对物联网的炒作仍然低估了物联网市场的潜力。 同时,麦肯锡还预测,到2020年,物联网产业可为经济市场带来高达11.1万亿美元(约合人民币73万亿元)的价值。 这一数值高于中国每年的GDP产值(10.4万

    06-18