lua 字节码(bytecode)

3.8k 词

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 */