Lua源码分析,原创[持续更新中]

关于Lua源码的基础型别、内存分配、字符串存储、垃圾回收机制、table原理等部分讲解,我发现有位仁兄写得相当之好,强烈推荐大家先认真阅读下面这篇文章,链接如下:

http://simohayha.iteye.com/blog/517748

本文将只对Lua的字节码和虚拟机的运行相关内容做重点分析

LUA OPCODE格式分析:

Lopcodes.c

Lua Opcode的格式关键在下面这个宏:

#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))

t(7)

a(6)

b(4~5)

c(2~3)

m(0~1)

如图,第0~1bit为m位, 2~3bit 为c位,4~5 bit为b位,6bit为a位,7bit为t位

t,a,b,c,m四部分,一起组成1 byte的opcode。下面依次分析下t,a,b,c,m各自扮演什么角色。

lua所有指令编码都在下面这个结构中 :

const lu_byte luaP_opmodes[NUM_OPCODES] = {

/* T A B C mode opcode */

opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */

,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */

......(此处略去78行,有需要请参考附录A LUA OPCODE一览)

,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */

};

enum OpArgMask {

OpArgN, /* 参数未被使用 */

OpArgU, /* 已使用参数 */

OpArgR, /* 该参数是寄存器或跳转偏移 */

OpArgK /* 该参数是个常量或寄存器常量, K乃const之意 */

};

结合上面定义以及源码注释,不难分析出如下结论:

含义

t

是否是测试操作,测试意味着跳转,跳转和测试指令该位为1

a

是否是寄存器操作

b

B参数,OpArgMask类型

c

C参数,OpArgMask类型

m

op mode

LUA 指令格式分析:

任意一条指令由操作码(opcode)和操作数组成。

上一章主要对操作码的格式进行了分析,下面来整体分析下Lua中单条指令的格式。

Lua中单条指令为32位,依参数的类型和个数不同,有三种模式:

高 -------------------------> 低

iABC:

B(23~31)

C(14~22)

A(6~13)

opcode(0~5)

iABx:

Bx( 14~31 )

A(6~13)

opcode(0~5)

iAsBx:

sBx( 14~31 )

A(6~13)

opcode(0~5)

三种模式中i表示6位的opcode,iABC表示三个参数的指令,iABx将iABC中的B和C合并为18位的无符号数,

iAsBx将iABC中的B和C合并为18位的有符号数。

相关元素SIZE和POS定义如下:

#define SIZE_C 9

#define SIZE_B 9

#define SIZE_Bx (SIZE_C + SIZE_B)

#define SIZE_A 8

#define SIZE_OP 6

#define POS_OP 0

#define POS_A (POS_OP + SIZE_OP)

#define POS_C (POS_A + SIZE_A)

#define POS_B (POS_C + SIZE_C)

#define POS_Bx POS_C

附录A

LUA OPCODE一览:

const lu_byte luaP_opmodes[NUM_OPCODES] = {

/* T A B C mode opcode */

opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */

,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */

,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */

,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */

,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */

,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */

,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */

,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */

,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */

,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */

,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */

,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */

,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */

,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */

,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */

,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */

,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */

,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */

,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */

,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */

,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */

,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */

,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */

,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */

,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */

,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */

,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */

,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */

,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */

,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */

,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */

,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */

,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */

};

typedef enum {

/*----------------------------------------------------------------------

name args description

------------------------------------------------------------------------*/

OP_MOVE,/* A B R(A) := R(B) */

OP_LOADK,/* A Bx R(A) := Kst(Bx) */

OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */

OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */

OP_GETUPVAL,/* A B R(A) := UpValue[B] */

OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */

OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */

OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */

OP_SETUPVAL,/* A B UpValue[B] := R(A) */

OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */

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(C)] */

OP_ADD,/* A B C R(A) := RK(B) + RK(C) */

OP_SUB,/* A B C R(A) := RK(B) - RK(C) */

OP_MUL,/* A B C R(A) := RK(B) * RK(C) */

OP_DIV,/* A B C R(A) := RK(B) / RK(C) */

OP_MOD,/* A B C R(A) := RK(B) % RK(C) */

OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */

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(C) */

OP_JMP,/* sBx pc+=sBx */

OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */

OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */

OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= 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_TFORLOOP,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));

if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */

OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */

OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/

OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */

OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */

} OpCode;