Lua源码阅读:基本数据类型

7.2k 词

关于Lua中基本数据类型的底层实现方式,本篇是IState。

lState

lua_State

在lState.h中定义了lua_State的结构体,这是每个 Lua 函数都会接受的表示当前状态的结构,最主要的成员包括运行栈 stack, 栈用于表示函数调用、传递参数及返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

** 'per thread' state
*/
struct {
CommonHeader; /* */
lu_byte status; /* 解析容器的,用于记录中间状态 */

global_State *l_G; /* 全局状态机 */

/*调用栈:调用栈的信息管理*/
CallInfo *ci; /* call info for current function 当前函数的运行信息 */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) 调用栈的头部指针 */

/* 数据栈:栈指针地址管理 */
StkId top; /* first free slot in the stack 指向线程栈的栈顶 */
StkId stack_last; /* last free slot in the stack 线程栈的最后一个位置 */
StkId stack; /* stack base 栈的指针,当前运行的位置 */

GCObject *gclist; /* GC列表 */
const Instruction *oldpc; /* last pc traced 在当前thread 的解释执行指令的过程中,指向最后一次执行的指令的指针 */
struct *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
UpVal *openupval; /* list of open upvalues in this stack */

/* Hook 相关管理 - 服务于debug模块 */
lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
lu_byte hookmask;
lu_byte allowhook;

/* 跟C语言通信 管理 */
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
};

GCUnion

1
2
3
4
5
6
7
8
9
10
11
12

** Union of all collectable objects (only for conversions)
*/
union GCUnion {
GCObject gc; /* common header */
struct TString ts;
struct Udata u;
union Closure cl;
struct Table h;
struct Proto p;
struct th; /* thread */
};

global_state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

** 'global state', shared by all threads of this state
** lua全局状态机
** 作用:管理全局数据、全局字符串表、内存管理函数
*/
typedef struct global_State {
const lua_Number *version; /* pointer to version number 版本号 */

/* 内存管理 */
lua_Alloc frealloc; /* function to reallocate memory Lua的全局内存分配器 */
void *ud; /* auxiliary data to 'frealloc' 分配器的userdata */

lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte gcrunning; /* true if GC is running */
GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */

Mbuffer buff; /* temporary buffer for string concatenation */

/* 字符串管理 */
stringtable strt; /* hash table for strings */

/* GC管理 */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */

/* 线程管理 */
struct *mainthread; /* 主线程 */
struct *twups; /* list of threads with open upvalues 闭包了当前线程变量的其他线程列表 */

/* 错误处理 */
lua_CFunction panic; /* to be called in unprotected errors */
TString *memerrmsg; /* memory-error message */

/* 虚函数表 */
TString *tmname[TM_N]; /* array with tag-method names 预定义方法名字数组 */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types 每个基本类型一个metatable */
} global_State;

创建栈结构:

lua_newstate主要用于创建一个主线程栈结构,分配lua_State和global_State。

对外通过lua_State结构暴露给用户,而global_State挂载在lua_State上。

通过这种结构,每个线程会独立维护自己的线程栈和函数栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
global_State *g;
/* 分配一个lua_State结构的内容块 */
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL;
L = &l->l.l;
g = &l->g;
L->next = NULL;
L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);

/* 初始化一个线程的栈结构数据 */
preinit_thread(L, g);
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
g->gckind = KGC_NORMAL;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */
close_state(L);
L = NULL;
}
return L;
}


** preinitialize a thread with consistent values without allocating
** any memory (to avoid errors)
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; /* 将global_State结构挂载在lua_State上 #define G(L) (L->l_G) */
L->stack = NULL;
L->ci = NULL;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
L->nCcalls = 0;
L->hook = NULL;
L->hookmask = 0;
L->basehookcount = 0;
L->allowhook = 1;
resethookcount(L);
L->openupval = NULL;
L->nny = 1;
L->status = LUA_OK;
L->errfunc = 0;
}

销毁栈结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 关闭lua栈 */
LUA_API void lua_close (lua_State *L) {
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
close_state(L);
}

/* 释放lua栈结构 */
static void close_state (lua_State *L) {
global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread 释放栈结构的upvalues */
luaC_freeallobjects(L); /* collect all objects 释放全部对象 */
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
}

数据栈与调用栈:

数据栈结构由一个StkID结构存储。lua中的数据分为值类型和引用类型。引用类型需要GC机制管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
union Value {
GCObject *gc; /* collectable objects 存放所有需要垃圾回收的类型的对象 */
void *p; /* light userdata 存放轻量用户数据 */
int b; /* booleans */
lua_CFunction f; /* light C functions 存放一个方法 */
lua_Integer i; /* integer numbers 存放int数字 */
lua_Number n; /* float numbers 存放float数字 */
};

struct lua_TValue {
TValuefields;
};

// #define TValuefields Value value_; int tt_

typedef TValue *StkId; /* index to stack elements */

调用栈存放在CallInfo中,以数组的形式存放在虚拟机的对象里。其中CallInfo中的ci->func指向正在执行的函数在数据栈上的位置l->top(正在调用的函数一定位于数据栈上。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that
** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation
** function can be called with the correct top.
*/
typedef struct CallInfo {
StkId func; /* function index in the stack func 指向正在执行的函数在数据栈上的位置 */
StkId top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
const Instruction *savedpc;
} l;
struct { /* only for C functions */
lua_KFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
lua_KContext ctx; /* context info. in case of yields */
} c;
} u;
ptrdiff_t extra;
short nresults; /* expected number of results from this function */
lu_byte callstatus;
} CallInfo;

栈初始化和释放: