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