lua 字节码(bytecode)
lua字节码
lua虚拟机最终执行的是经过lua编译器编译的字节码,这里暂不关系Chunk生成字节码过程, 只关系字节码本身,字节码的格式到底是什么样?具体的含义是什么?
字节码格式
lua字节码指令是由4个字节32位组成, 这时32是如何规划的,简单说那些位代表这个指令是 什么,那些位是操作数据,这里通过一个案例来看看bytecode结构,然后再解释bytecode具 体的结构。
源码案例:
--test function 1
function max(num1, num2)
if (num1 > num2) then
r = num1
else
r = num2
end
return r
end
--test function 2
function add(num1, num2)
return num1 + num2
end
print("hello world")
print("max ", max(10,8))
定义了两个函数,max和add函数,函数实现比较简单,暂且不关心,然后调用系统函数print 输出hello world,接着调用max函数,add函数没有调用。看看这段代码被lua编译器编译后 的结果到底是什么?使用lua5.2.1版本lauc编译器,指令为luac -l test.lua进行编译。
对应字节码:
main <test.lua:0,0> (15 instructions at 0000000000180370)
0+ params, 5 slots, 1 upvalue, 0 locals, 7 constants, 2 functions
1 [9] CLOSURE 0 0 ; 0000000000180640
2 [2] SETTABUP 0 -1 0 ; _ENV "max"
3 [14] CLOSURE 0 1 ; 00000000001809C0
4 [12] SETTABUP 0 -2 0 ; _ENV "add"
5 [16] GETTABUP 0 0 -3 ; _ENV "console"
6 [16] LOADK 1 -4 ; "hello world"
7 [16] CALL 0 2 1
8 [17] GETTABUP 0 0 -3 ; _ENV "console"
9 [17] LOADK 1 -5 ; "max "
10 [17] GETTABUP 2 0 -1 ; _ENV "max"
11 [17] LOADK 3 -6 ; 10
12 [17] LOADK 4 -7 ; 8
13 [17] CALL 2 3 0
14 [17] CALL 0 0 1
15 [17] RETURN 0 1
function <test.lua:2,9> (8 instructions at 0000000000180640)
2 params, 3 slots, 1 upvalue, 2 locals, 1 constant, 0 functions
1 [3] LT 0 1 0
2 [3] JMP 0 2 ; to 5
3 [4] SETTABUP 0 -1 0 ; _ENV "r"
4 [4] JMP 0 1 ; to 6
5 [6] SETTABUP 0 -1 1 ; _ENV "r"
6 [8] GETTABUP 2 0 -1 ; _ENV "r"
7 [8] RETURN 2 2
8 [9] RETURN 0 1
function <test.lua:12,14> (3 instructions at 00000000001809C0)
2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions
1 [13] ADD 2 0 1
2 [13] RETURN 2 2
3 [14] RETURN 0 1
指令解释:
上面的源码生成指令可以看出来,每一行是一个指令,每一行指令由5部分组成,分别为: 指令行号 源码行号 指令 操作数 指令描述 通过上面的结果我们可以看出来,每一个lua函数,lua都会生成一段指令块,该指令块包含该 函数的内容指令。值得注意是lua源码会默认生成一个main function,该指令块主要包含lua的 执行过程。
指令分类
四种指令:iABC iABx iAsBx iAx,代码中定义:enum OpMode {iABC, iABx, iAsBx, iAx}; lua所有指令前6位是操作码opcode,剩下组成部分如下:
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
所有指令
这里的指令是5.2.1版本里面所有的指令都定义在lopcode.h头文件中定义,代码如下:
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
OP_LOADKX,/* A R(A) := Kst(extra arg) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
OP_GETTABUP,/* A B C R(A) := UpValue[B][RK©] /
OP_GETTABLE,/ A B C R(A) := R(B)[RK©] */
OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK© /
OP_SETUPVAL,/ A B UpValue[B] := R(A) /
OP_SETTABLE,/ A B C R(A)[RK(B)] := RK© */
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK©] */
OP_ADD,/* A B C R(A) := RK(B) + RK© /
OP_SUB,/ A B C R(A) := RK(B) - RK© /
OP_MUL,/ A B C R(A) := RK(B) * RK© /
OP_DIV,/ A B C R(A) := RK(B) / RK© /
OP_MOD,/ A B C R(A) := RK(B) % RK© /
OP_POW,/ A B C R(A) := RK(B) ^ RK© /
OP_UNM,/ A B R(A) := -R(B) /
OP_NOT,/ A B R(A) := not R(B) /
OP_LEN,/ A B R(A) := length of R(B) */
OP_CONCAT,/* A B C R(A) := R(B)… … …R© */
OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 /
OP_EQ,/ A B C if ((RK(B) == RK©) ~= A) then pc++ /
OP_LT,/ A B C if ((RK(B) < RK©) ~= A) then pc++ /
OP_LE,/ A B C if ((RK(B) <= RK©) ~= A) then pc++ */
OP_TEST,/* A C if not (R(A) <=> C) then pc++ /
OP_TESTSET,/ A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
OP_CALL,/* A B C R(A), … ,R(A+C-2) := R(A)(R(A+1), … ,R(A+B-1)) /
OP_TAILCALL,/ A B C return R(A)(R(A+1), … ,R(A+B-1)) /
OP_RETURN,/ A B return R(A), … ,R(A+B-2) (see note) */
OP_FORLOOP,/* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }/
OP_FORPREP,/ A sBx R(A)-=R(A+2); pc+=sBx */
OP_TFORCALL,/* A C R(A+3), … ,R(A+2+C) := R(A)(R(A+1), R(A+2)); /
OP_TFORLOOP,/ A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG,/* A B R(A), R(A+1), …, R(A+B-2) = vararg */
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */