Lua虚拟机

Lua是用标准C语言编写,是一门以高效率著称的脚本语言。

为了达到较高的执行效率,lua代码并不是直接被Lua解释器解释执行,而是先由Lua编译器编译为字节码,然后再交给Lua虚拟机执行。

二进制chunk?

在Lua的行话里,一段可以被Lua解释器解释执行的Lua代码就叫作chunk,Lua并不是直接解释执行chunk,先由编译器编译成字节码,编译成的字节码就叫二进制chunk,由虚拟机在执行字节码。

Luac命令介

作为编译器,把Lua源文件编译成二进制chunk文件,也可作为反编译器,分析字节码的内容

// 下载lua代码
// 进入到当前文件夹
cd /Users/qs/Desktop/Jey/lua-5.4.3

// 执行make命令,生成两个可执行程序lua和luac
make

// 把那个两个文件拷贝出来,放到一个bin文件夹中,进入bin,执行./lua,就进入了lua命令行
./lua

// 创建一个hallo.lua文件,print("hallo lua")
nano hallo.lua

// 执行,打印出Hallo lua
./lua hallo.lua 

// 编译成字节码,会编译成一个luac.out文件
./luac hallo.lua

// 执行下面也是可以的
./luac luac.out 

二进制chunk(Binary chunk)的格式

没有标准化,也没有任何官方文档对其进行说明,一切以lua官方实现的源代码为准。

  1. 其设计并没有考虑跨平台,对于需要超过一个字节表示的数据,必须要考虑大小端(Endianness)问题。
    lua官方实现的做法比较简单:编译lua脚本时,直接按照本机的大小端方式生成二进制chunk文件,当加载二进制chunk文件时,会探测被加载文件的大小端方式,如果和本机不匹配,就拒绝加载.

大端序:数据的高位字节存放在地址的低端 低位字节存放在地址高端。
小端序:数据的高位字节存放在地址的高端 低位字节存放在地址低端。

  1. 二进制chunk格式设计也没有考虑不同lua版本之间的兼容问题,当加载二进制chunk文件时,会检测其版本号,如果和当前lua版本不匹配,就拒绝加载

  2. 另外,二进制chunk格式设计也没有被刻意设计得很紧凑。在某些情况下,一段lua代码编译成二进制chunk后,甚至会被文本形式的源代码还要大。
    预编译成二进制chunk主要是为了提升加载速度,因此这也不是很大的问题.

Stack Based VM vs Rigister Based VM

高级编程语言的虚拟机是利用软件技术对硬件进行的模拟和抽象。按照实现方式,可分为两类:基于栈(Stack Based)和基于寄存器(Rigister Based)。
Lua从1.0版本就开始内置了虚拟机,到5.0之前的版本都是基于栈,5.0之后是基于寄存器。

a. 基于栈的虚拟机,会转化成如下指令

push b;     // 将变量b的值压入stack
push c;     // 将变量c的值压入stack
add;        // 将stack顶部的两个值弹出后相加,然后将结果压入stack顶
mov a;      // 将stack顶部结果放到a中

所有的指令执行,都是基于一个操作数栈的。你想要执行任何指令时,对不起,得先入栈,然后算完了再给我出栈。
由于 Stack Based VM 的指令都是基于当前 stack 来查找操作数的,这就相当于所有操作数的存储位置都是运行期决定的,在编译器的代码生成阶段不需要额外为在哪里存储操作数费心,所以 stack based 的编译器实现起来相对比较简单直接,也正因为这个原因,每条指令占用的存储空间也比较小。

但是,对于一个简单的运算,stack based vm 会使用过多的指令组合来完成,这样就增加了整体指令集合的长度。vm 会使用同样多的迭代次数来执行这些指令,这对于效率来说会有很大的影响。并且,由于操作数都要放到stack上面,使得移动这些操作数的内存复制大大增加,这也会影响到效率。

b. 基于寄存器的虚拟机,会转化成如下指令

add a b c; // 将b与c对应的寄存器的值相加,将结果保存在a对应的寄存器中

没有操作数栈这一概念,但是会有许多的虚拟寄存器。这类虚拟寄存器有别于CPU的寄存器,因为CPU寄存器往往是定址的(比如DX本身就是能存东西),而寄存器式的虚拟机中的寄存器通常有两层含义:

(1)寄存器别名(比如lua里的RA、RB、RC、RBx等),它们往往只是起到一个地址映射的功能,它会根据指令中跟操作数相关的字段计算出操作数实际的内存地址,从而取出操作数进行计算;

(2)实际寄存器,有点类似操作数栈,也是一个全局的运行时栈,只不过这个栈是跟函数走的,一个函数对应一个栈帧,栈帧里每个slot就是一个寄存器,第1步中通过别名映射后的地址就是每个slot的地址。

好处是指令条数少,数据转移次数少。坏处是单挑指令长度较长。
具体来看,lua里的实际寄存器数组是用TValue结构的栈来模拟的,这个栈也是lua和C进行交互的虚拟栈。

基于栈的虚拟机需要使用PUSH类指令往栈顶推入值,使用POP类指令从栈顶弹出值,其他指令则是对栈顶值进行操作,因此指令集相对比较大,但是指令的平均长度比较短;

基于寄存器的虚拟机由于可以直接对寄存器进行寻址,所以不需要PUSH或者POP类指令,指令集相对比较小,但是由于需要把寄存器地址编码进指令里,所以指令的平均长度比较长。

Lua函数原型结构

lua编译器以函数为单位对源代码进行编译,每个函数会被编译成一个称之为原型(Prototype)的结构

原型主要包含6部分内容:函数基本信息(basic info:含参数数量、局部变量数量等信息)、字节码(bytecodes)、常量(constants)表、upvalue(闭包捕获的非局部变量)表、调试信息(debug info)、子函数原型列表(sub functions)


截屏2021-04-06 下午8.22.55.png

参考:https://gohalo.me/post/lua-sourcecode.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容