[toc]

# 概述

这系列文章会一步步的拆解 Lua 的实现原理,直到到达 Lua Wrap 与 Lua 本身的数据交互为止

# 宏孩儿实现 GC 对象判定

首先讨论一个问题,在 c 语言里,我们如何判断一个对象是否可 GC?
有 N 种方法吧,这里来讨论下
1. C 没有模板,所以没法 traits,C++ 可以 traits 撸几个特性模板
2. 写一大堆 if
3. 宏孩儿 这是从 Lua 源码中读来的,其实也是 C 语言实现面向对象的一种很棒的实践
下面均是从第 3 条出发,以 Lua 对象为例,步步引出 Lua 的默认对象 Lua 的一个基础类型是 Table ,这个类型的原型如下:

1
2
3
4
5
6
7
8
9
10
11
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int alimit; /* "limit" of 'array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
} Table;

其中 GCObject 和 CommonHeader 的标志如下:

1
2
3
4
5
6
7
8
9
10
11
12
/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
#define CommonHeader struct GCObject *next; lu_byte tt; lu_byte marked


/* Common type for all collectable objects */
typedef struct GCObject {
CommonHeader;
} GCObject;

注释部分说的很明显了,所有可以 GC 的对象都包含 CommonHeader,GCObject 是 CommonHeader 的一个特化,其中农 tt 是用来标志类型的变量 Table 中的元素是各种类型变量,其对象原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define TValuefields   Value value_; lu_byte tt_

typedef struct TValue {
TValuefields;
} TValue;

/*
** Union of all Lua values
*/
typedef union Value {
struct GCObject *gc; /* collectable objects */
void *p; /* light userdata */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value;

可以发现 TValue 的最后一个值中存放了一个 lu_byte tt_ 后面就是通过这个值来判定是否可以 GC 的,如下 (下面是 5.4 的,5.1 的 leisi 类似):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE (1 << 6)

#define iscollectable(o) (rawtt(o) & BIT_ISCOLLECTABLE)

/* mark a tag as collectable */
#define ctb(t) ((t) BIT_ISCOLLECTABLE)

#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc)

/* raw type tag of a TValue */
#define rawtt(o) ((o)->tt_)

#define check_exp(c,e) (lua_assert(c), (e))

这里开始就开始出现宏的骚操作了
Lua 内部定义了一个 BIT_ISCOLLECTABLE 来表示某变量当第六位为 1 时则表示是可 GC 的
然后定义了 iscollectable(O) 宏用来判定是否是可 GC 对象,这里就是第一个宏孩儿的骚操作点: 通过 rawtt(o) 把压力交给编译器
除非你的对象里有 tt_ ,否则编译是不会被通过的。 然后下面还有一个获取 gcvalue 的宏 gcvalue(o) ,这个宏后面有一个 iscollectable(o) ,这个意思就是如果不是 gc 对象,编译器甚至不会通过,把压力全部交给编译器

# Lua 基础对象

上面已经说了一部分继承关系了,下面这张图是《Lua 设计与实现》这本书里的继承图示,在最新的 Lua5.4 中,这层继承关系已经变了, GCheader 已经被干掉了,图上的 GCObject 实际上是 GCUnion
这里还是以 5.1.5 为例