ch02-Lua虚拟机&指令
栈虚拟机 & 寄存器虚拟机
目前虚拟机有两种实现方式,一种是栈式的,一种是寄存器式的,大多数语言,java,python都用的是栈式的,而lua自从5.0之后用的是寄存器式的,当然,这些寄存器并不是指的CPU中的真实寄存器。
一个简单的a=b+c在栈式虚拟机中,会变成如下指令
push b; // 变量b压入stack
push c; // 变量c压入stack
add; // 栈顶两个值弹出计算,结果压入stack
mov a; // 栈顶结果保存到a而在寄存器式虚拟机中,只有一条指令
add a b c; // 将b和c对应的寄存器里面的值相加,结果保存到a对应的寄存器里所以能大致看出,两种虚拟机上的一些区别:
指令条数:栈式虚拟机多
代码尺寸:栈式虚拟机大
移植性:栈式虚拟机好
指令优化:寄存器式更好
Lua使用一个栈来存放它的寄存器,每个函数都有这么一个TValue的栈,由于每条指令只用8个bit来指定寄存器,所以每个函数最多可以用256个寄存器。
Lua虚拟机
Lua中的指令集
指令格式

Lua中指令格式这个样子,可以看出,Lua的指令是32位的,由低到高进行解释,首先解释低6位的Opcode,称为操作数,然后是A、B、C参数。(Opcode定义在lpcodes.h中,最多支持26-1个操作数)。
二进制chunk
luac会把lua文件编译成二进制文件,会自动为脚本添加一个main主函数。
local global = 1
print("hello world")
function B()
local b = 2
print(b)
return b
end
function A(a)
local c = B() + global
print(c)
end
A(3)上面这段lua代码,用luac -l *.out 就能看到其反编译其二进制chunk的结果
main <notes/test.lua:0,0> (13 instructions, 52 bytes at 0x56239a4f3860)
-- 函数参数数量,寄存器数量,upValue数量,local参数数量,常量数量,内嵌函数数量
0+ params, 3 slots, 0 upvalues, 1 local, 6 constants, 2 functions
1 [1] LOADK 0 -1 ; 1
2 [2] GETGLOBAL 1 -2 ; print
3 [2] LOADK 2 -3 ; "hello world"
4 [2] CALL 1 2 1
5 [8] CLOSURE 1 0 ; 0x56239a4f3ad0
6 [4] SETGLOBAL 1 -4 ; B
7 [14] CLOSURE 1 1 ; 0x56239a4f3c10
8 [14] MOVE 0 0
9 [9] SETGLOBAL 1 -5 ; A
10 [16] GETGLOBAL 1 -5 ; A
11 [16] LOADK 2 -6 ; 3
12 [16] CALL 1 2 1
13 [16] RETURN 0 1
function <notes/test.lua:4,8> (6 instructions, 24 bytes at 0x56239a4f3ad0)
0 params, 3 slots, 0 upvalues, 1 local, 2 constants, 0 functions
1 [5] LOADK 0 -1 ; 2
2 [6] GETGLOBAL 1 -2 ; print
3 [6] MOVE 2 0
4 [6] CALL 1 2 1
5 [7] RETURN 0 2
6 [8] RETURN 0 1
function <notes/test.lua:9,14> (8 instructions, 32 bytes at 0x56239a4f3c10)
1 param, 4 slots, 1 upvalue, 2 locals, 2 constants, 0 functions
1 [11] GETGLOBAL 1 -1 ; B
2 [11] CALL 1 1 2
3 [11] GETUPVAL 2 0 ; global
4 [11] ADD 1 1 2
5 [12] GETGLOBAL 2 -2 ; print
6 [12] MOVE 3 1
7 [12] CALL 2 2 1
8 [14] RETURN 0 1