summaryrefslogtreecommitdiff
path: root/src/lua51
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua51')
-rw-r--r--src/lua51/lapi.c2
-rw-r--r--src/lua51/lcode.c17
-rw-r--r--src/lua51/ldebug.h1
-rw-r--r--src/lua51/lfunc.c20
-rw-r--r--src/lua51/lgc.c286
-rw-r--r--src/lua51/lgc.h44
-rw-r--r--src/lua51/llex.h2
-rw-r--r--src/lua51/lobject.h78
-rw-r--r--src/lua51/lopcodes.c1
-rw-r--r--src/lua51/lopcodes.h23
-rw-r--r--src/lua51/lparser.c59
-rw-r--r--src/lua51/lparser.h14
-rw-r--r--src/lua51/lstate.h57
-rw-r--r--src/lua51/lstring.c4
-rw-r--r--src/lua51/ltable.c4
-rw-r--r--src/lua51/lua.c6
-rw-r--r--src/lua51/lundump.c2
-rw-r--r--src/lua51/lvm.c8
18 files changed, 408 insertions, 220 deletions
diff --git a/src/lua51/lapi.c b/src/lua51/lapi.c
index a476634..b640e66 100644
--- a/src/lua51/lapi.c
+++ b/src/lua51/lapi.c
@@ -918,7 +918,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
break;
}
case LUA_GCCOLLECT: {
- luaC_fullgc(L);
+ luaC_fullgc(L); // 一次完成全部GC过程,而不是增量GC
break;
}
case LUA_GCCOUNT: {
diff --git a/src/lua51/lcode.c b/src/lua51/lcode.c
index 8f25b06..640f107 100644
--- a/src/lua51/lcode.c
+++ b/src/lua51/lcode.c
@@ -56,11 +56,12 @@ void luaK_nil (FuncState *fs, int from, int n) {
}
+//c 生成jump指令
int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
fs->jpc = NO_JUMP;
- j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+ j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); // 生成OP_JUMP指令
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
@@ -196,6 +197,7 @@ void luaK_concat (FuncState *fs, int *l1, int l2) {
}
+//c
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
@@ -344,7 +346,7 @@ static int code_label (FuncState *fs, int A, int b, int jump) {
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}
-
+//c! 根据不同的表达式类型,比如NIL,TRUE,NUMBER等生成对应的字节码
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e);
switch (e->k) {
@@ -360,7 +362,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
break;
}
- case VKNUM: {
+ case VKNUM: { // 将常量设置到寄存器
luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
break;
}
@@ -416,10 +418,11 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
}
+//c! 根据expdesc结构生成字节码
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
- luaK_dischargevars(fs, e);
- freeexp(fs, e);
- luaK_reserveregs(fs, 1);
+ luaK_dischargevars(fs, e); // 根据变量的作用域来决定这个变量是否需要重定向,即VNONRELOC或VRELOC
+ freeexp(fs, e); // 如果不需要重定向,释放expdesc寄存器
+ luaK_reserveregs(fs, 1); //申请一个寄存器
exp2reg(fs, e, fs->freereg - 1);
}
@@ -791,7 +794,7 @@ void luaK_fixline (FuncState *fs, int line) {
}
-//c 指令生成
+//c 指令生成的唯一入口
static int luaK_code (FuncState *fs, Instruction i, int line) {
Proto *f = fs->f;
dischargejpc(fs); /* `pc' will change */
diff --git a/src/lua51/ldebug.h b/src/lua51/ldebug.h
index ba28a97..156503e 100644
--- a/src/lua51/ldebug.h
+++ b/src/lua51/ldebug.h
@@ -9,6 +9,7 @@
#include "lstate.h"
+#include "misc.h"
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
diff --git a/src/lua51/lfunc.c b/src/lua51/lfunc.c
index df2c8e3..5835295 100644
--- a/src/lua51/lfunc.c
+++ b/src/lua51/lfunc.c
@@ -32,6 +32,7 @@ Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
//c 新建lua closure
//c nelems upvalue的个数
+//c 这个方法有两个地方调用,一个是f_parser,在代码编译后生成一个闭包;一个是闭包内嵌方法执行到OP_CLOSURE指令时新建闭包
Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
luaC_link(L, obj2gco(c), LUA_TFUNCTION); //c 加入GC链表
@@ -43,7 +44,7 @@ Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
}
-//c 新建一个closed upvalue
+//c 新建一个upvalue,默认是closed
UpVal *luaF_newupval (lua_State *L) {
UpVal *uv = luaM_new(L, UpVal);
luaC_link(L, obj2gco(uv), LUA_TUPVAL); //c 加入GC链表
@@ -53,6 +54,7 @@ UpVal *luaF_newupval (lua_State *L) {
}
+//c 设置upvalue的数据指针指向stack中某个值level
UpVal *luaF_findupval (lua_State *L, StkId level) {
global_State *g = G(L);
GCObject **pp = &L->openupval;
@@ -82,6 +84,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
}
+// 把uv从global_state->uvhead或者lua_state->openupval中删除
static void unlinkupval (UpVal *uv) {
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
@@ -89,6 +92,7 @@ static void unlinkupval (UpVal *uv) {
}
+//c 从global_state->uvhead中删除并释放内存
void luaF_freeupval (lua_State *L, UpVal *uv) {
if (uv->v != &uv->u.value) /* is it open? */
unlinkupval(uv); /* remove from open list */
@@ -96,19 +100,23 @@ void luaF_freeupval (lua_State *L, UpVal *uv) {
}
+//c 设置闭包的upvalue
void luaF_close (lua_State *L, StkId level) {
+ log("luaF_close()");
UpVal *uv;
global_State *g = G(L);
while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
GCObject *o = obj2gco(uv);
- lua_assert(!isblack(o) && uv->v != &uv->u.value);
+ lua_assert(!isblack(o) && uv->v != &uv->u.value); //必须是 open upvalue
L->openupval = uv->next; /* remove from `open' list */
- if (isdead(g, o))
+ if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
- else {
- unlinkupval(uv);
- setobj(L, &uv->u.value, uv->v);
+ else {
+ unlinkupval(uv); // 从L->openupval中删除
+
+ setobj(L, &uv->u.value, uv->v); // 拷贝到upvalue的value字段,upvalue储存值
uv->v = &uv->u.value; /* now current value lives here */
+
luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
}
}
diff --git a/src/lua51/lgc.c b/src/lua51/lgc.c
index ae845e9..afebe04 100644
--- a/src/lua51/lgc.c
+++ b/src/lua51/lgc.c
@@ -48,15 +48,18 @@
#define VALUEWEAK bitmask(VALUEWEAKBIT)
-// 标记对象,有点类似一个安全声明,mark了的对象不会被回收,会被标记为灰色(大多数情况下)或黑色
+// markvalue和markobject不同之处在于类型不同,一个接受TValue*类型,一个接受任意合理的指针类型
+
+// 标记值为灰色
#define markvalue(g,o) { checkconsistency(o); \
if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
+// 标记对象为灰色
#define markobject(g,t) { if (iswhite(obj2gco(t))) \
reallymarkobject(g, obj2gco(t)); }
-// 手动GC
+// 设置GC阈值
// estimate 使用中的内存大小估值
// gcpause 控制两次GC间隔的百分数
#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
@@ -69,37 +72,52 @@ static void removeentry (Node *n) {
}
-//c 标记object(不标记这个object引用的object,udata除外,需要标记udata的mt和env)
-//c 至于标记object引用的object留在扫描阶段
+//c 扫描标记object为灰色(不标记这个object引用的object,udata除外,需要标记udata的mt和env)
+//c 至于标记object引用的object留在扫描阶段,这样做是为了缩短时间
static void reallymarkobject (global_State *g, GCObject *o) {
lua_assert(iswhite(o) && !isdead(g, o));
- //改为灰色
+
+ //标记为灰色
white2gray(o);
- //对于大部分类型,都是把gcobject加到gray链表
+
switch (o->gch.tt) {
case LUA_TSTRING: {
// 字符串不会引用其他数据,所以略过,不用加到gray list
return;
}
+
case LUA_TUSERDATA: {
- // udata本身也不会引用其他对象,所以不需要扫描,直接标记为黑色
+ // udata本身也不会引用其他对象(除了元表和环境表),所以不需要扫描,直接标记为黑色
Table *mt = gco2u(o)->metatable;
// 直接标记为黑色
gray2black(o); /* udata are never gray */
- // 标记一下它的mt和env表
+ // 顺便标记一下它的元表和env表,userdata只会引用元表和环境表
if (mt) markobject(g, mt);
markobject(g, gco2u(o)->env);
return;
}
+
case LUA_TUPVAL: {
- UpVal *uv = gco2uv(o);
+ log("reallymarkobject().LUA_TUPVAL");
+ UpVal *uv = gco2uv(o);
+ // 把upvalue引用的对象标记为灰色
markvalue(g, uv->v);
- // 当这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系
- // 直接标记黑色
- if (uv->v == &uv->u.value) /* closed? */
- gray2black(o); /* open upvalues are never black */
+ // 如果这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系
+ // 直接把upvalue标记为黑色,upvalue自己保存这个变量
+ if (uv->v == &uv->u.value) /* closed? */
+ {
+ log("closed upvalue");
+ gray2black(o); /* open upvalues are never black */
+ }
+ // open的upvalue永远不会是黑色的(因为没有意义),需要持续检查,在remarkupvals()函数
+ // open upvalue不在gray链中维护,而在global_State的uvhead,等到atomic()的时候再mark
+ // 所以这里没有把open upvalue放入灰链
+ // 参见remarkupvals()
return;
}
+
+ // 对于 function, table, thread, proto, 将它们加入gray链
+
case LUA_TFUNCTION: {
gco2cl(o)->c.gclist = g->gray;
g->gray = o;
@@ -124,29 +142,35 @@ static void reallymarkobject (global_State *g, GCObject *o) {
}
}
-
+// 将g->tmudata链中的udata标记为灰色
static void marktmu (global_State *g) {
GCObject *u = g->tmudata;
if (u) {
do {
u = u->gch.next;
+
+ // 将这个udata标记为灰色
makewhite(g, u); /* may be marked, if left from previous GC */
reallymarkobject(g, u);
+
} while (u != g->tmudata);
}
}
-//c 处理 userdata,userdata都在atomic里面处理,而不是propagatemark
-//c userdata都跟在mainthread之后(这是一个hack的做法,统一放在一个地方,方便处理)
+//c 将需要调用__gc和不需要的udata分开
+// 处理 userdata,userdata都在atomic里面处理,而不是propagatemark
+// userdata都跟在mainthread之后(这是一个hack的做法,统一放在一个地方,方便处理)
/* move `dead' udata that need finalization to list `tmudata' */
size_t luaC_separateudata (lua_State *L, int all) {
global_State *g = G(L);
size_t deadmem = 0;
+
// udata的链表
GCObject **p = &g->mainthread->next;
GCObject *curr;
+
while ((curr = *p) != NULL) /*遍历*/{
- //udata创建的时候是白色,加载mainthread后面
+ //userdata创建的时候是白色,加在mainthread后面
if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) // 如果该udata不需要回收,跳过
p = &curr->gch.next; /* don't bother with them */
else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { // 如果没注册__gc
@@ -154,7 +178,7 @@ size_t luaC_separateudata (lua_State *L, int all) {
markfinalized(gco2u(curr)); /* don't need finalization */
p = &curr->gch.next;
}
- else { /* must call its gc method */
+ else { /* must call its gc method */ // 加入G(L)->tmudata链
deadmem += sizeudata(gco2u(curr));
// 标记为finalized后,还需要加入G(L)->tmudata链表
markfinalized(gco2u(curr));
@@ -187,7 +211,8 @@ static int traversetable (global_State *g, Table *h) {
if (mode && ttisstring(mode)) { /* is there a weak mode? */
weakkey = (strchr(svalue(mode), 'k') != NULL);
weakvalue = (strchr(svalue(mode), 'v') != NULL);
- if (weakkey || weakvalue) { /* is really weak? */
+ if (weakkey || weakvalue) { /* is really weak? */
+ // 如果是弱表,加到g->weak链表,在扫描的第二阶段atomic处理
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
(weakvalue << VALUEWEAKBIT));
@@ -196,9 +221,11 @@ static int traversetable (global_State *g, Table *h) {
g->weak = obj2gco(h); /* ... so put in the appropriate list */
}
}
- if (weakkey && weakvalue) return 1; // 如果是弱表,返回1
- // 如果不是弱表,遍历table的散列部分和数组部分所有元素
+ if (weakkey && weakvalue)
+ return 1; // 如果是弱表,返回1,从black置回gray以备atomic重新扫描
+
+ // 如果不是弱表,遍历table的散列部分和数组部分所有元素并标记,加入灰链
//数组
if (!weakvalue) {
@@ -220,6 +247,7 @@ static int traversetable (global_State *g, Table *h) {
if (!weakvalue) markvalue(g, gval(n));
}
}
+
return weakkey || weakvalue;
}
@@ -236,7 +264,7 @@ static void traverseproto (global_State *g, Proto *f) {
// 标记常量
for (i=0; i<f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
- // 标记upvalue
+ // 标记upvalue名
for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */
if (f->upvalues[i])
stringmark(f->upvalues[i]);
@@ -254,11 +282,13 @@ static void traverseproto (global_State *g, Proto *f) {
}
-
+// 遍历闭包,标记env, proto, upvalue为灰色,加入灰链
static void traverseclosure (global_State *g, Closure *cl) {
markobject(g, cl->c.env);
+
if (cl->c.isC) {
int i;
+ // 标记upvalue
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
markvalue(g, &cl->c.upvalue[i]);
}
@@ -266,6 +296,7 @@ static void traverseclosure (global_State *g, Closure *cl) {
int i;
lua_assert(cl->l.nupvalues == cl->l.p->nups);
markobject(g, cl->l.p);
+ // 标记upvalue
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
markobject(g, cl->l.upvals[i]);
}
@@ -304,20 +335,32 @@ static void traversestack (global_State *g, lua_State *l) {
}
-//c 扫描和标记操作入口
/*
** traverse one gray object, turning it to black.
** Returns `quantity' traversed.
*/
+//c 将对象从灰->黑并从灰色链删除,表示这个对象以及所引用的对象都已经标记过
+// 只遍历*一个*灰色对象,增量地把对象分布到不同的step中(因为遍历对象的引用是非常慢的)
+// 和reallymarkobject的区别在后者不会标记所引用的对象(除了userdata),而这个会调用
+// traverse*()进行标记,采用广度优先
static l_mem propagatemark (global_State *g) {
- GCObject *o = g->gray;
+ GCObject *o = g->gray; // 拿到gray的第一个,只处理这一个
lua_assert(isgray(o));
- gray2black(o);//预先标记为黑色
- //只有table、function、thread、proto会引用其他对象
+
+ gray2black(o);//预先标记为黑色,对于特殊的四个类型需要递归它引用的对象
+
+//下面四个语句将对象o排除出gray链即这个对象已经被标记为了黑色,且被引用对象也遍历过了
+//g->gray = h->gclist;
+//g->gray = cl->c.gclist;
+//g->gray = th->gclist;
+//g->gray = p->gclist;
+
+ //只有 table、function、thread、proto 会引用其他对象,需要递归遍历他们引用的对象
+ //刚开始进入GCSpropagate阶段时会遍历lua_State, global table, register table
switch (o->gch.tt) {
case LUA_TTABLE: { //扫描table,尝试标记数组和哈希部分
Table *h = gco2h(o);
- g->gray = h->gclist;
+ g->gray = h->gclist;
// 如果是弱表,回退回灰色状态
if (traversetable(g, h)) /* table is weak? */
black2gray(o); /* keep it gray */
@@ -333,12 +376,13 @@ static l_mem propagatemark (global_State *g) {
}
case LUA_TTHREAD: { //扫描线程对象, 因为lua_State关联的数据变化频繁,所以从graylist中拿出来放到grayaginlist中
lua_State *th = gco2th(o);
+
// 将lua_state从gray中删除,加到grayagain里
- g->gray = th->gclist;
- th->gclist = g->grayagain;
+ g->gray = th->gclist; // 从gray链删除
+ th->gclist = g->grayagain; // 加入grayagin链
g->grayagain = o;
- // 颜色退回为灰色
- black2gray(o);
+ black2gray(o);// 颜色退回为灰色,便于在后续grayagin处理
+
traversestack(g, th);
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * th->size_ci;
@@ -354,7 +398,7 @@ static l_mem propagatemark (global_State *g) {
sizeof(LocVar) * p->sizelocvars +
sizeof(TString *) * p->sizeupvalues;
}
- default:
+ default: // 其余类型不会引用其他对象
lua_assert(0);
return 0;
}
@@ -416,6 +460,7 @@ static void cleartable (GCObject *l) {
}
+//c 释放对象内存
static void freeobj (lua_State *L, GCObject *o) {
switch (o->gch.tt) {
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
@@ -445,7 +490,9 @@ static void freeobj (lua_State *L, GCObject *o) {
//c p刚进来是这个散列桶的第一个字符串
#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
-
+//c 回收 count 个(字符串)链表
+// p是在rootgc链上的位置
+// count 每次回收的对象个数
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
GCObject *curr;
global_State *g = G(L);
@@ -456,12 +503,12 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
sweepwholelist(L, &gco2th(curr)->openupval);
if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */
lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
- makewhite(g, curr); /* make it white (for next cycle) */
- p = &curr->gch.next;
+ makewhite(g, curr); /* make it white (for next cycle) */ // 重新标记为白色,等待下次GC
+ p = &curr->gch.next; //
}
else { /* must erase `curr' */
lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
- *p = curr->gch.next;
+ *p = curr->gch.next; // 将这个对象从rootgc中删除
if (curr == g->rootgc) /* is the first element of the list? */
g->rootgc = curr->gch.next; /* adjust first */
//c! 回收对象,根据类型调用不同的内存释放方法
@@ -473,12 +520,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
//c 检查字符串桶的大小,如果太大了,将空的桶删掉,重新分配桶
-//c
static void checkSizes (lua_State *L) {
global_State *g = G(L);
/* check size of string hash */
- //c 如果桶的总大小是用到的桶位(即字符串数量)的4倍,且是MINSTRTABSIZE的2倍
- //c 给桶瘦身
+ // 如果桶的总大小是用到的桶位(即字符串数量)的4倍,且是MINSTRTABSIZE的2倍
+ // 给桶瘦身
if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
g->strt.size > MINSTRTABSIZE*2)
luaS_resize(L, g->strt.size/2); /* table is too big */
@@ -550,46 +596,53 @@ static void markmt (global_State *g) {
}
-//c 初始化root
-//c 将mainthread,
+//c GC初始化,根查找阶段,一步完成
+//c 将mainthread
/* mark root set */
static void markroot (lua_State *L) {
global_State *g = G(L);
- // 清空
+
+ // 1. 清空链表准备这次GC流程
g->gray = NULL;
g->grayagain = NULL;
g->weak = NULL;
- // 标记mainthread
+
+ // 2. 标记mainthread、全局表、注册表为灰色并加入链表gray
+ // 从这几个开始在扫描阶段将它们引用的对象依次遍历
markobject(g, g->mainthread);
- /* make global table be traversed before main stack */
- // 标记 _G 为灰色
- markvalue(g, gt(g->mainthread));
- // 标记注册表为灰色
+ markvalue(g, gt(g->mainthread));/* make global table be traversed before main stack */
markvalue(g, registry(L));
- markmt(g);
+ markmt(g); /*基本类型的元方法*/
+
//GC 切换到扫描阶段
g->gcstate = GCSpropagate;
}
+//c 扫描open状态的upvalue,之所以在
static void remarkupvals (global_State *g) {
UpVal *uv;
for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- if (isgray(obj2gco(uv)))
+ if (isgray(obj2gco(uv))) // 在reallymarkobject的LUA_TUPVAL处理,对于open的upvalue会标记为灰色,等到这里处理
markvalue(g, uv->v);
}
}
-//c 原子化处理grayagain
+//c 原子化一步扫描剩余的部分
+// 1. open状态的upvalue
+// 2. weak表内容、当前的lua_State、基本类型的元表
+// 3. grayagin链
+// 4. userdata
static void atomic (lua_State *L) {
global_State *g = G(L);
size_t udsize; /* total size of userdata to be finalized */
- /* remark occasional upvalues of (maybe) dead threads */
- remarkupvals(g);
- /* traverse objects cautch by write barrier and by 'remarkupvals' */
- propagateall(g);
+
+ //扫描open状态的upvalue
+ remarkupvals(g);/* remark occasional upvalues of (maybe) dead threads */ // 这个调用之后gray链上会有新的内容(upvalue引用的对象),所以还需要调用下一个函数
+ propagateall(g);/* traverse objects cautch by write barrier and by 'remarkupvals' */
+
/* remark weak tables */
g->gray = g->weak;
g->weak = NULL;
@@ -597,44 +650,61 @@ static void atomic (lua_State *L) {
markobject(g, L); /* mark running thread */
markmt(g); /* mark basic metatables (again) */
propagateall(g);
+
/* remark gray again */
g->gray = g->grayagain;
g->grayagain = NULL;
propagateall(g);
- // 处理udata
- udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
- marktmu(g); /* mark `preserved' userdata */
+
+ // 处理userdata
+ udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ // 将需要调用__gc和不需要的udata分开
+ marktmu(g); /* mark `preserved' userdata */ // 将tmudata链里的udata标记为灰色并加入gray链
udsize += propagateall(g); /* remark, to propagate `preserveness' */
+
cleartable(g->weak); /* remove collected objects from weak tables */
- /* flip current white */
- g->currentwhite = cast_byte(otherwhite(g));
+
+ // 结束atomic
+ g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
g->sweepstrgc = 0;
- // 设置当前清理的位置
- g->sweepgc = &g->rootgc;
- // 切换到回收字符串阶段
- g->gcstate = GCSsweepstring;
+ g->sweepgc = &g->rootgc;// 标记当前回收到的位置在rootgc中的位置
+ g->gcstate = GCSsweepstring; // 切换到回收字符串阶段
g->estimate = g->totalbytes - udsize; /* first estimate */
}
-//c! 单步GC的入口
+//c! GC的入口,会根据当前GC的状态进不同的流程
static l_mem singlestep (lua_State *L) {
global_State *g = G(L);
/*lua_checkmemory(L);*/
+/* 分为几大步执行
+ 1. GCSpause 初始化
+ 2. GCSpropagate 扫描
+ gray
+ grayagain
+ 3. GCSsweepstring 回收字符串
+ 4. GCSsweep 回收其他类型
+ 5. GCSfinalize 结束
+*/
switch (g->gcstate) {
- case GCSpause: { // 初始化
+ case GCSpause: { // 初始化,原子操作
markroot(L); /* start a new collection */
return 0;
}
+
case GCSpropagate: { // 扫描并标记
- if (g->gray) // gray list不为空
- return propagatemark(g);
+ //总的分两步,先按照一定的粒度逐个遍历gray链,然后原子化处理grayagin链表
+ if (g->gray) // 如果gray没处理完,处理gray链
+ //1.遍历gray链表标记所有数据和引用的数据,有些数据被加入grayagain链表,比如thread
+ return propagatemark(g); //遍历一个
else { /* no more `gray' objects */
+ //2.使用atomic函数遍历grayagin
atomic(L); /* finish mark phase */
return 0;
}
}
+
case GCSsweepstring: { // 回收字符串
+ // 每次回收一个字符串链表
lu_mem old = g->totalbytes;
// 回收g->sweepstrgc位置的散列桶
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
@@ -644,8 +714,10 @@ static l_mem singlestep (lua_State *L) {
g->estimate -= old - g->totalbytes;
return GCSWEEPCOST;
}
+
case GCSsweep: { // 回收字符串以外的其他类型
lu_mem old = g->totalbytes;
+ // 回收 GCSWEEPMAX 个对象
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
if (*g->sweepgc == NULL) { /* nothing more to sweep? */
checkSizes(L);
@@ -655,9 +727,11 @@ static l_mem singlestep (lua_State *L) {
g->estimate -= old - g->totalbytes;
return GCSWEEPMAX*GCSWEEPCOST;
}
+
case GCSfinalize: { // 结束阶段,专门处理 tmudata ,调用userdata的__gc方法,释放native引用
+ // 每次处理一个udata
if (g->tmudata) {
- GCTM(L);
+ GCTM(L); //调用__gc方法
if (g->estimate > GCFINALIZECOST)
g->estimate -= GCFINALIZECOST;
return GCFINALIZECOST;
@@ -669,6 +743,7 @@ static l_mem singlestep (lua_State *L) {
return 0;
}
}
+
default: lua_assert(0); return 0;
}
}
@@ -677,7 +752,7 @@ static l_mem singlestep (lua_State *L) {
//c! GC 入口
void luaC_step (lua_State *L) {
global_State *g = G(L);
- l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
+ l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; // 本次回收计划回收的内存大小,会影响每次gc执行singlestep的次数
if (lim == 0)
lim = (MAX_LUMEM-1)/2; /* no limit */
g->gcdept += g->totalbytes - g->GCthreshold;
@@ -699,8 +774,9 @@ void luaC_step (lua_State *L) {
}
}
-
+//c STW(stop-the-world) GC,一次性清理GC
void luaC_fullgc (lua_State *L) {
+ log("luaC_fullgc");
global_State *g = G(L);
if (g->gcstate <= GCSpropagate) {
/* reset sweep marks to sweep all elements (returning them to white) */
@@ -725,62 +801,96 @@ void luaC_fullgc (lua_State *L) {
setthreshold(g);
}
+//屏障是为了应对在“扫描”阶段新建对象时的情况
-//c 向前避障
+//c 向前屏障,指新建的数据从白色->灰色加入灰色链
+// o 黑 v 白
+// 在lgc.h里面定义的几个宏会限定barrier操作不会发生在GCSpause和GCSfinalize阶段,这两个阶段不需要屏蔽操作,正常处理即可
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L);
+
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
- lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+ // GCSfinalize下不会有黑色对象和GCSpause下不会有白色对象
+ lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
lua_assert(ttype(&o->gch) != LUA_TTABLE);
+
/* must keep invariant? */
if (g->gcstate == GCSpropagate)// 如果在扫描阶段,把新建的v加入gray链
reallymarkobject(g, v); /* restore invariant */
- else /* don't mind */ // 否则标记为白色,等待下一次GC
+ else /* don't mind */ // 如果在清除阶段,正常处理,标记为当前白,等待下一次GC
makewhite(g, o); /* mark as white just to avoid other barriers */
}
-//c 向后避障只作用于 table,将table加入 grayagain 链表
+//c 向后屏障只作用于 table,将table从黑色变灰加入*grayagain*链表(而不是gray链表)
+// 指新建数据的引用者从黑色->灰色
+// 之所以table采用向后屏障,而不是向前屏障,将table重新设为灰色并加入*grayagin*在atomic处理
+// 是由于table的1对N特点,避免多次新建项导致的不必要消耗,同时加入grayagin而不是gray,是为了
+// 避免一个对象频繁的“被退回-扫描-回退-扫描”过程,在扫描步骤中一旦这个表被修改了且已经标为了黑
+// 色, 直接把它加到grayagin里处理,而不是像其他类型处理一样使用向前屏障
void luaC_barrierback (lua_State *L, Table *t) {
global_State *g = G(L);
GCObject *o = obj2gco(t);
+
lua_assert(isblack(o) && !isdead(g, o));
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+
black2gray(o); /* make table gray (again) */
- // 加到grayagin list里
+
+ // 加到grayagin链
t->gclist = g->grayagain;
g->grayagain = o;
}
-//c! 将一个新建的GCGamobject(udata除外,加载其他地方,具体看luaS_newudata)加入root,并标记为白色
-//c upvalue 不一定会设为white,所以不会调这个函数
-//c 虽然被加入了rootgc,但是不会被轻易回收,lua有双白色缓冲概念
-//c 分为currentwhite和otherwhite。如果某个对象创建在GC的标记阶段以后,它的white和标记时的white不是一个white,
-//c 在回收阶段会判断一下,不会回收这个对象
-//c global_State的currentwhite switch发生在标记阶段后
+//c! luaC_link和luaC_linkupval 函数用于创建对象时调用加入gc链
+
+
+//c! 将一个新建的GCGamobject:function, table, thread(udata除外,加载其他地方,具体看luaS_newudata)
+// 加入rootgc,并标记为白色
+// upvalue 不一定会设为white,所以不会调这个函数
+// 虽然被加入了rootgc,但是不会被轻易回收,lua有双白色缓冲概念
+// 分为currentwhite和otherwhite。如果某个对象创建在GC的标记阶段以后,它的white和标记时的white不是一个white,
+// 在回收阶段会判断一下,不会回收这个对象
+// global_State的currentwhite switch发生在标记阶段后
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
+//log("luaC_link()");
global_State *g = G(L);
+
+ // 将这个新建对象加入rootgc链
o->gch.next = g->rootgc;
g->rootgc = o;
- o->gch.marked = luaC_white(g);//标记为current white
+
+ o->gch.marked = luaC_white(g);//标记为当前白
o->gch.tt = tt;//设置数据类型
}
//c! 将一个upvalue加入root,由于upvalue是对已经存在的对象的间接引用,所以和普通对象不太一样
void luaC_linkupval (lua_State *L, UpVal *uv) {
+ log("luaC_linkupval()");
+
+ // 进这个函数里的upvalue都是close upvalue
+
global_State *g = G(L);
- GCObject *o = obj2gco(uv);
+ GCObject *o = obj2gco(uv); // 这个o是
+
+ // 将这个upvalue加入rootgc链
o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
g->rootgc = o;
+
// 这里和普通对象不一样
- if (isgray(o)) {
- if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接将对象置为黑色
- gray2black(o); /* closed upvalues need barrier */
- luaC_barrier(L, uv, uv->v);
+ if (isgray(o)) { // 在扫描阶段realymarkobject标记为了灰色,
+ if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接标记为黑色
+ log("GCSpropagate");
+ gray2black(o); /* closed upvalues need barrier */
+ luaC_barrier(L, uv, uv->v);
+/* if(valiswhite(uv->v) && isblack(obj2go(uv)))
+ luaC_barrierf(L,obj2gco(uv),gcvalue(uv->v));
+*/
}
else { /* 否则的话和普通对象一样置为白色 */ /* sweep phase: sweep it (turning it into white) */
makewhite(g, o);
+ log("not GCSpropagate");
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
}
}
diff --git a/src/lua51/lgc.h b/src/lua51/lgc.h
index 83007ac..8a23239 100644
--- a/src/lua51/lgc.h
+++ b/src/lua51/lgc.h
@@ -11,15 +11,18 @@
#include "lobject.h"
+#include "misc.h"
-
+//c! GC的几个阶段
+// 时序上:
+// GCSpause > GCSpropagate > GCSsweepstring > GCSsweep > GCSfinalize
/*
** Possible states of the Garbage Collector
*/
-#define GCSpause 0 // 暂停
-#define GCSpropagate 1 // 扫描,正在遍历灰色节点,检查引用情况
+#define GCSpause 0 // 开始
+#define GCSpropagate 1 // 扫描标记,遍历*灰色*节点,检查引用情况
#define GCSsweepstring 2 // 字符串回收阶段
-#define GCSsweep 3 // 除了字符串的其他对象的回收阶段
+#define GCSsweep 3 // 非字符串GC对象的回收
#define GCSfinalize 4 // 终止阶段
@@ -51,19 +54,18 @@
** bit 5 - object is fixed (should not be collected)
** bit 6 - object is "super" fixed (only the main thread)
*/
-
-
-#define WHITE0BIT 0 // 01
-#define WHITE1BIT 1 // 10
-#define BLACKBIT 2
-#define FINALIZEDBIT 3 //标记没有被引用的udata
-#define KEYWEAKBIT 3 //标记弱表的key
+// 这里不需要一个灰色的bit,非白非黑就是灰色
+#define WHITE0BIT 0 // 01
+#define WHITE1BIT 1 // 10
+#define BLACKBIT 2 // 黑色
+#define FINALIZEDBIT 3 // 标记没有被引用的udata
+#define KEYWEAKBIT 3 // 标记弱表的key
#define VALUEWEAKBIT 4 // 标记弱表的value
-#define FIXEDBIT 5 // 标记lua_state主线程对象不可回收
-#define SFIXEDBIT 6 // 标记lua关键字不要回收
+#define FIXEDBIT 5 // 仅用于标记lua_state主线程对象不可回收
+#define SFIXEDBIT 6 // 标记lua关键字字符串不要回收
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) // 结果是11
-
+//region 与颜色相关的宏
#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
#define isgray(x) (!isblack(x) && !iswhite(x))
@@ -71,16 +73,15 @@
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS)
-#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
+#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) // 切换white类型
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
-// g->currentwhite & WHITEBITS是 current white
-// g->currentwhite ^ WHITEBITS是 otherwhite
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
+//endregion 与颜色相关的宏
-// 自动触发回收内存,在每次调用内存分配相关API时进行
+//c! 在每次调用内存分配相关API时自动触发回收内存,
// 触发条件是当前分配的内存大于阈值GCthreshold
// 自动触发不可控,很多人选择关闭它,方法是通过设置一个很大的GCthreshold比如(~0)
#define luaC_checkGC(L) { \
@@ -88,8 +89,8 @@
if (G(L)->totalbytes >= G(L)->GCthreshold) \
luaC_step(L); }
-//c 避障相关操作,分为向前避障 luaC_barrier luaC_objbarrier 和向后避障 luaC_barriert luaC_objbarriert
-
+//c 屏障相关操作,分为向前屏障 luaC_barrier luaC_objbarrier 和向后屏障 luaC_barriert luaC_objbarriert
+// 向后屏障只针对table类型
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrierf(L,obj2gco(p),gcvalue(v)); }
@@ -103,6 +104,9 @@
#define luaC_objbarriert(L,t,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
+
+// API
+
LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
LUAI_FUNC void luaC_callGCTM (lua_State *L);
LUAI_FUNC void luaC_freeall (lua_State *L);
diff --git a/src/lua51/llex.h b/src/lua51/llex.h
index 8a013f9..101ccdb 100644
--- a/src/lua51/llex.h
+++ b/src/lua51/llex.h
@@ -30,7 +30,7 @@ enum RESERVED {
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
- TK_NAME, TK_STRING, TK_EOS
+ TK_NAME, TK_STRING, TK_EOS // TK_EOD = end of file
};
/* number of reserved words */
diff --git a/src/lua51/lobject.h b/src/lua51/lobject.h
index ead9391..5d6df6c 100644
--- a/src/lua51/lobject.h
+++ b/src/lua51/lobject.h
@@ -43,7 +43,7 @@ typedef union GCObject GCObject;
// 需要垃圾回收的类型包含这个头,包含TString, Udata, Proto, UpVal, Closure, Table以及lua_State七个
//c next 指向下一个gc链表的成员
//c tt 数据类型
-//c marked GC标记,用来保存颜色,有白色(2种),灰色和黑色
+//c marked GC标记,用一个字节进行标记,在lgc.h
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
@@ -242,16 +242,16 @@ typedef struct Proto {
CommonHeader;
//c 常量表,能看出来lua保存常量的单元是函数原型,所有代码片段都会被编译为proto
TValue *k; /* constants used by the function */
- //c 函数字节码起始点
+ //c 这个函数的字节码
Instruction *code;
- //c 内部函数
+ //c 这个函数内嵌套的函数
struct Proto **p; /* functions defined inside the function */
int *lineinfo; /* map from opcodes to source lines */
- //c 局部变量
+ //c 局部变量,在lparser.c > registerlocalvar注册
struct LocVar *locvars; /* information about local variables */
- //c upvalues
+ //c upvalue表
TString **upvalues; /* upvalue names */
- TString *source; //文件名
+ TString *source; //c 文件名,只有顶层函数有,内嵌函数这个字段是空的
int sizeupvalues;
int sizek; /* size of `k' */
int sizecode;
@@ -276,7 +276,9 @@ typedef struct Proto {
//c 局部变量
typedef struct LocVar {
- TString *varname;
+ //c 变量名,只会在编译器用到,存在FuncState结构,用来查找局部变量ID
+ TString *varname;
+ //c
int startpc; /* first point where variable is active */
int endpc; /* first point where variable is dead */
} LocVar;
@@ -287,19 +289,30 @@ typedef struct LocVar {
** Upvalues
*/
//c 判断upvalue是关闭的方式是 uv->v == &uv->u.value
-//c upvalue有开闭的概念
-//c 开是指upvalue完全由此方法所有,之前的调用已经结束
-//c 关闭是指upvalue还在之前的栈上
+// upvalue有开闭的概念
+// 开是指upvalue完全由此方法所有,之前的调用已经结束
+// 关闭是指upvalue还在之前的栈上
+typedef struct UpVal {
+ CommonHeader;
+ TValue *v; /* points to stack or to its own value */ //c upvalue的栈地址
+ union {
+ TValue value; /* the value (when closed) */
+ struct { /* double linked list (when open) */
+ struct UpVal *prev;
+ struct UpVal *next;
+ } l;
+ } u;
+} UpVal;
/*
-* function func()
-* local a = 10;
-* local b = function()
-* a = a + 1
-* print(a)
-* end
+* function func()
+* local a = 10;
+* local b = function()
+* a = a + 1
+* print(a)
+* end
* b() -- 这个是开
-* end
-*
+* end
+*
* function func()
* local a = 10;
* local b = function()
@@ -307,22 +320,11 @@ typedef struct LocVar {
* print(a)
* end
* return b
-* end
-*
+* end
+*
* fn = func()
* fn() -- 这个是关
*/
-typedef struct UpVal {
- CommonHeader;
- TValue *v; /* points to stack or to its own value */ //c upvalue的栈地址
- union {
- TValue value; /* the value (when closed) */
- struct { /* double linked list (when open) */
- struct UpVal *prev;
- struct UpVal *next;
- } l;
- } u;
-} UpVal;
/*
@@ -335,6 +337,13 @@ typedef struct UpVal {
typedef struct CClosure {
ClosureHeader;
+ /*
+ CommonHeader; //c gc header
+ lu_byte isC; //c is c closure
+ lu_byte nupvalues; //c number of upvalues
+ GCObject *gclist; //c gclist?
+ struct Table *env //c 这个闭包的环境
+ */
lua_CFunction f;
TValue upvalue[1];
} CClosure;
@@ -342,6 +351,13 @@ typedef struct CClosure {
typedef struct LClosure {
ClosureHeader;
+ /*
+ CommonHeader; //c gc header
+ lu_byte isC; //c is c closure
+ lu_byte nupvalues; //c number of upvalues
+ GCObject *gclist; //c gclist?
+ struct Table *env //c 这个闭包的环境,在luaF_newLclosure设置
+ */
struct Proto *p; // lua闭包的函数原型
UpVal *upvals[1]; // lua闭包的upvalue
} LClosure;
diff --git a/src/lua51/lopcodes.c b/src/lua51/lopcodes.c
index 64652bb..2e1b124 100644
--- a/src/lua51/lopcodes.c
+++ b/src/lua51/lopcodes.c
@@ -10,7 +10,6 @@
#include "lopcodes.h"
-
/* ORDER OP */
const char *const luaP_opnames[NUM_OPCODES+1] = {
diff --git a/src/lua51/lopcodes.h b/src/lua51/lopcodes.h
index 8c0d1a8..f9a9828 100644
--- a/src/lua51/lopcodes.h
+++ b/src/lua51/lopcodes.h
@@ -27,13 +27,6 @@
unsigned argument.
===========================================================================*/
-
-enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
-
-
-/*
-** size and position of opcode arguments.
-*/
/*
三种指令的格式
iABC B:9 C:9 A:8 Opcode:6
@@ -42,6 +35,12 @@ iAsBx sBx:18 A:8 Opcode:6
注:sBx是signed BX
寄存器就是相对于callinfo和lua_state的当前调用的base的某个偏移(即ABC值)
*/
+enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
+
+
+/*
+** size and position of opcode arguments.
+*/
//c 单个指令Instruction的每部分的大小
// 9 + 9 + 8 + 6 = 32 bits
@@ -87,7 +86,7 @@ iAsBx sBx:18 A:8 Opcode:6
/*
** the following macros help to manipulate instructions
*/
-//c 获取和设置Instruction中的某个部分
+//c 获取和设置指令中的某个部分
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
@@ -212,7 +211,9 @@ 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_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
+ //setlist有一个优化,当初始化的数量每超过LFIELDS_PER_FLUSH个时,flush一次,这样能够减少
+ // 比如初始化时元素个数是3个,那么参数C就是1,只需要flush 1次
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)) */
@@ -254,7 +255,7 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
** bit 6: instruction set register A
** bit 7: operator is a test
*/
-//c 指令的参数格式
+//c 指令的参数格式,在luaP_opmodes用到
enum OpArgMask {
OpArgN, /* argument is not used */ // 未使用(没有座位R()和RK()的参数使用)
OpArgU, /* argument is used */ // 使用的
@@ -262,6 +263,8 @@ enum OpArgMask {
OpArgK /* argument is a constant or register/constant */ // 寄存器、常量
};
+//c 限制每个指令的具体格式,用来后续判断,起到分类统一处理指令的作用
+//c 即lvm.c 中 RA(i)等宏中的check_exp,不过这个检查是可以跳过的,在llimits.h中定义
LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES];
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
diff --git a/src/lua51/lparser.c b/src/lua51/lparser.c
index 7da34e7..d868981 100644
--- a/src/lua51/lparser.c
+++ b/src/lua51/lparser.c
@@ -140,6 +140,7 @@ static void checkname(LexState *ls, expdesc *e) {
}
+//c 注册一个局部变量,并返回对应的编号ID
static int registerlocalvar (LexState *ls, TString *varname) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
@@ -157,13 +158,15 @@ static int registerlocalvar (LexState *ls, TString *varname) {
new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
+//c new_localvar() adjustlocalvars() removevars() 用来管理局部变量
+
+//c 对于 local a,b,c = 1, 2,3 这样的语句,生成等号坐标对应的变量
static void new_localvar (LexState *ls, TString *name, int n) {
FuncState *fs = ls->fs;
- luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
- fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
+ luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");//最多支持200个局部变量
+ fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); //
}
-
static void adjustlocalvars (LexState *ls, int nvars) {
FuncState *fs = ls->fs;
fs->nactvar = cast_byte(fs->nactvar + nvars);
@@ -172,7 +175,6 @@ static void adjustlocalvars (LexState *ls, int nvars) {
}
}
-
static void removevars (LexState *ls, int tolevel) {
FuncState *fs = ls->fs;
while (fs->nactvar > tolevel)
@@ -380,22 +382,32 @@ static void close_func (LexState *ls) {
}
-//c! 编译生成字节码,分析阶段的唯一入口,返回proto指针
+//c!! 编译器入口
+//c! 词法分析>语法分析并生成字节码
+//c 编译生成字节码,分析阶段的唯一入口,返回proto指针
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
+ //c 词法分析、语法分析和代码生成过程中的数据都在这里
struct LexState lexstate;
- struct FuncState funcstate; // 分析过程中的临时数据
+ struct FuncState funcstate;
+
lexstate.buff = buff;
luaX_setinput(L, &lexstate, z, luaS_new(L, name));
open_func(&lexstate, &funcstate);
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
- luaX_next(&lexstate); /* read first token */
- chunk(&lexstate);
+
+ // lua通过一次遍历就从源代码生成了字节码,为了加快编译
+ luaX_next(&lexstate); /* read first token */
+ chunk(&lexstate);
+
+ // 代码生成结束进行一些收尾工作
check(&lexstate, TK_EOS);
close_func(&lexstate);
+
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nups == 0);
lua_assert(lexstate.fs == NULL);
- return funcstate.f; //c 最终生成的字节码
+
+ return funcstate.f; //c 最终生成的函数原型
}
@@ -431,12 +443,12 @@ static void yindex (LexState *ls, expdesc *v) {
** =======================================================================
*/
-
+// 存放表消息
struct ConsControl {
- expdesc v; /* last list item read */
- expdesc *t; /* table descriptor */
- int nh; /* total number of `record' elements */
- int na; /* total number of array elements */
+ expdesc v; /* last list item read */ //表在构造过程中最后一个表达式的信息
+ expdesc *t; /* table descriptor */ //表构造表达式的信息
+ int nh; /* total number of `record' elements */ // 初始化表时,散列部分数据数量
+ int na; /* total number of array elements */ // 初始化表时,数组部分数据数量
int tostore; /* number of array elements pending to be stored */
};
@@ -500,12 +512,15 @@ static void constructor (LexState *ls, expdesc *t) {
/* constructor -> ?? */
FuncState *fs = ls->fs;
int line = ls->linenumber;
- int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
+ int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); // 这条指令会被重定向,A参数会被设为寄存器上某个值
+
struct ConsControl cc;
cc.na = cc.nh = cc.tostore = 0;
cc.t = t;
+
init_exp(t, VRELOCABLE, pc);
init_exp(&cc.v, VVOID, 0); /* no value (yet) */
+
luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */
checknext(ls, '{');
do {
@@ -594,12 +609,13 @@ static void body (LexState *ls, expdesc *e, int needself, int line) {
}
+//c 表达式
static int explist1 (LexState *ls, expdesc *v) {
/* explist1 -> expr { `,' expr } */
int n = 1; /* at least one expression */
- expr(ls, v);
+ expr(ls, v); // 先生成lparser.h > expdesc结构
while (testnext(ls, ',')) {
- luaK_exp2nextreg(ls->fs, v);
+ luaK_exp2nextreg(ls->fs, v); // 根据expdesc结构内容生成对应的字节码
expr(ls, v);
n++;
}
@@ -725,6 +741,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
}
+//构造表达式
static void simpleexp (LexState *ls, expdesc *v) {
/* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
constructor | FUNCTION body | primaryexp */
@@ -1177,6 +1194,7 @@ static void localfunc (LexState *ls) {
}
+//c 定义局部变量语句
static void localstat (LexState *ls) {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
@@ -1191,8 +1209,8 @@ static void localstat (LexState *ls) {
e.k = VVOID;
nexps = 0;
}
- adjust_assign(ls, nvars, nexps, &e);
- adjustlocalvars(ls, nvars);
+ adjust_assign(ls, nvars, nexps, &e); // 根据等号左右两边的个数调整,如果右边少于左边,则多余的置为nil
+ adjustlocalvars(ls, nvars); //根据变量数量调整FuncState结构中的nactvar,并调整startpc
}
@@ -1268,7 +1286,7 @@ static void retstat (LexState *ls) {
luaK_ret(fs, first, nret);
}
-
+//c 语法分析,直接生成字节码
static int statement (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */
switch (ls->t.token) {
@@ -1332,6 +1350,7 @@ static void chunk (LexState *ls) {
testnext(ls, ';');
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
+ // 更新寄存器的位置,给本地变量留位置
ls->fs->freereg = ls->fs->nactvar; /* free registers */
}
leavelevel(ls);
diff --git a/src/lua51/lparser.h b/src/lua51/lparser.h
index 18836af..dbd7405 100644
--- a/src/lua51/lparser.h
+++ b/src/lua51/lparser.h
@@ -34,8 +34,9 @@ typedef enum {
VVARARG /* info = instruction pc */
} expkind;
+//c 存放表达式信息
typedef struct expdesc {
- expkind k;
+ expkind k; // 表达式类型
union {
struct { int info, aux; } s;
lua_Number nval;
@@ -54,27 +55,32 @@ typedef struct upvaldesc {
struct BlockCnt; /* defined in lparser.c */
+//c 编译过程(词法分析、语法分析、代码生成阶段)的临时数据结构
+//c 用来辅助生成字节码
/* state needed to generate code for a given function */
typedef struct FuncState {
+ //c 函数字节码
Proto *f; /* current function header */
Table *h; /* table to find (and reuse) elements in `k' */
- struct FuncState *prev; /* enclosing function */
+ //c 指向父函数的指针
+ struct FuncState *prev; /* enclosing function */
struct LexState *ls; /* lexical state */
struct lua_State *L; /* copy of the Lua state */
struct BlockCnt *bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */
int jpc; /* list of pending jumps to `pc' */
- int freereg; /* first free register */
+ int freereg; /* first free register */ // 用来指示局部变量的栈位置
int nk; /* number of elements in `k' */
int np; /* number of elements in `p' */
short nlocvars; /* number of elements in `locvars' */
lu_byte nactvar; /* number of active local variables */
upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */
- unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */
+ unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ // 在函数原型f->locvars的序号
} FuncState;
+//c 编译的唯一入口,包含词法、语法、代码生成
LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
const char *name);
diff --git a/src/lua51/lstate.h b/src/lua51/lstate.h
index 8da0640..cb4244b 100644
--- a/src/lua51/lstate.h
+++ b/src/lua51/lstate.h
@@ -69,7 +69,6 @@ typedef struct CallInfo {
} CallInfo;
-
#define curr_func(L) (clvalue(L->ci->func))
#define ci_func(ci) (clvalue((ci)->func))
#define f_isLua(ci) (!ci_func(ci)->c.isC)
@@ -84,46 +83,61 @@ typedef struct global_State {
stringtable strt; /* hash table for strings */
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to `frealloc' */
- lu_byte currentwhite;//当前白
- //c 当前的GC状态,有5个,在lgc.h定义
+
+//region 与GC相关
+
+ lu_byte currentwhite;//当前的白色类型,用于lgc.h>luaC_white()
+ // 当前的GC状态,有5个,在lgc.h定义
lu_byte gcstate; /* state of garbage collector */
- //c strt中字符串散列桶索引,字符串回收阶段每次回收一个散列桶的字符串,
+ // strt中字符串散列桶索引,字符串回收阶段每次回收一个散列桶的字符串,记录对应的散列桶索引
int sweepstrgc; /* position of sweep in `strt' */
- //c 白色链表。可回收的对象,会在回收阶段被回收
- //c 所有新建的对象都会暂存在这里,但不会被回收,因为lua有双白色机制
+ // 所有新建的对象都会暂存在这里,在GC的清理阶段会增量地遍历整个链表。新建对象会加在最*前面*,见luaC_link()
GCObject *rootgc; /* list of all collectable objects */
- //c 保存rootgc中当前回收到的位置,下次从这个位置继续回收
+ // 保存rootgc中当前回收到的位置,下次从这个位置继续回收
GCObject **sweepgc; /* position of sweep in `rootgc' */
- //c 灰色链表
+ // 灰色链表
GCObject *gray; /* list of gray objects */
- //c 不可被打断的对象的灰色链表,比如LUA_THREAD
+ // 需要一次性扫描处理的,不可被打断的对象的灰色链表,比如LUA_THREAD
GCObject *grayagain; /* list of objects to be traversed atomically */
- //c 弱表
+ // 弱表
GCObject *weak; /* list of weak tables (to be cleared) */
- //c 有__gc方法的userdata,会在GC阶段调用__gc释放native侧的引用
- GCObject *tmudata; /* last element of list of userdata to be GC */
+ // 有__gc方法的userdata,会在GC阶段调用__gc释放native侧的引用。指向链表最后一个
+ GCObject *tmudata; /* last element of list of userdata to be GC */ // taggedmethodudata带__gc的udata
+
+//endregion 与GC有关
+
+//region 与内存管理有关的
+
Mbuffer buff; /* temporary buffer for string concatentation */
+ // GC开始的阈值,
lu_mem GCthreshold;
- //c 开始进行GC的阈值,当超过这个值时开始GC
+ // 开始进行GC的阈值,当超过这个值时开始GC
lu_mem totalbytes; /* number of bytes currently allocated */
- //c 当前使用的内存大小的估计值
+ // 当前使用的内存大小的估计值
lu_mem estimate; /* an estimate of number of bytes actually in use */
+ // 待回收的内存大小
lu_mem gcdept; /* how much GC is `behind schedule' */
- //c 一个百分数,控制下一轮GC开始时机,越大,下次gc开始的时间越长
+ // 一个百分数,控制下一轮GC开始时机,越大,离下次gc开始的时间越长
int gcpause; /* size of pause between successive GCs */
- //c 控制GC回收速度
+ // 控制GC回收速度\gc的粒度
int gcstepmul; /* GC `granularity' */
+
+//endregion 与内存管理有关的
+
lua_CFunction panic; /* to be called in unprotected errors */
- //c 注册表
- TValue l_registry;
- struct lua_State *mainthread;
+
+ TValue l_registry; //全局唯一的注册表,所有lua_State共享一个
+ struct lua_State *mainthread; // 主线程对象,不会被回收
UpVal uvhead; /* head of double-linked list of all open upvalues */
+
+ // 基本类型的元方法
struct Table *mt[NUM_TAGS]; /* metatables for basic types */
TString *tmname[TM_N]; /* array with tag-method names */
+
} global_State;
-//c StkId引用的永远是lua_State栈上的内容
+//c StkId引用的永远是lua_State栈上的内容,准确来说是base+bias
/*
** `per thread' state
*/
@@ -157,8 +171,7 @@ struct lua_State {
int basehookcount;
int hookcount;
lua_Hook hook;
- //c _G global table
- TValue l_gt; /* table of globals */
+ TValue l_gt; /* table of globals */ //全局表 _G global table
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
diff --git a/src/lua51/lstring.c b/src/lua51/lstring.c
index cadbb4b..acfd02f 100644
--- a/src/lua51/lstring.c
+++ b/src/lua51/lstring.c
@@ -63,7 +63,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
ts->tsv.len = l;
ts->tsv.hash = h;
- ts->tsv.marked = luaC_white(G(L));
+ ts->tsv.marked = luaC_white(G(L)); // 标记为当前白
ts->tsv.tt = LUA_TSTRING;
ts->tsv.reserved = 0;
@@ -119,8 +119,8 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
if (s > MAX_SIZET - sizeof(Udata))
luaM_toobig(L);
- // 创建并赋值
u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
+
//c udata和普通对象在GC上的区别在于不调用luaC_link,因为不会加在
//c G(L)->rootgc链上,而是加在G(L)->mainthread后面
//c udata标记为 white
diff --git a/src/lua51/ltable.c b/src/lua51/ltable.c
index 38f4218..20fde8e 100644
--- a/src/lua51/ltable.c
+++ b/src/lua51/ltable.c
@@ -373,7 +373,7 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
//c 新建table
Table *luaH_new (lua_State *L, int narray, int nhash) {
Table *t = luaM_new(L, Table);
- luaC_link(L, obj2gco(t), LUA_TTABLE);
+ luaC_link(L, obj2gco(t), LUA_TTABLE); //标记为白色,并加入rootgc
t->metatable = NULL;
t->flags = cast_byte(~0);
/* temporary values (kept only if some malloc fails) */
@@ -455,7 +455,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
//c 赋值
gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
// #define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
- // 如果当前table是黑色,新建key时需要进行向后避障,将table记为灰色,加入grayagin链表
+ // 如果当前table是黑色,新建key时需要进行向后屏障,将table记为灰色,加入grayagin链表
luaC_barriert(L, t, key);
lua_assert(ttisnil(gval(mp)));
return gval(mp);
diff --git a/src/lua51/lua.c b/src/lua51/lua.c
index eaa70a6..9861e60 100644
--- a/src/lua51/lua.c
+++ b/src/lua51/lua.c
@@ -1,3 +1,5 @@
+#if 0
+
#define COMPILE_LUA_C
#ifdef COMPILE_LUA_C
@@ -395,4 +397,6 @@ int main (int argc, char **argv) {
}
-#endif \ No newline at end of file
+#endif
+
+#endif // #if 0 \ No newline at end of file
diff --git a/src/lua51/lundump.c b/src/lua51/lundump.c
index 564f218..5299f55 100644
--- a/src/lua51/lundump.c
+++ b/src/lua51/lundump.c
@@ -108,7 +108,7 @@ static void LoadConstants(LoadState* S, Proto* f)
for (i=0; i<n; i++)
{
TValue* o=&f->k[i];
- int t=LoadChar(S);
+ int t=LoadChar(S); //c 用一个字节标识类型
switch (t)
{
case LUA_TNIL:
diff --git a/src/lua51/lvm.c b/src/lua51/lvm.c
index ea1d019..8733b07 100644
--- a/src/lua51/lvm.c
+++ b/src/lua51/lvm.c
@@ -143,7 +143,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
setobj2t(L, oldval, val);
h->flags = 0;
- luaC_barriert(L, h, val);
+ luaC_barriert(L, h, val); // 向后屏障
return;
}
/* else will try the tag method */
@@ -344,6 +344,7 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
#define runtime_check(L, c) { if (!(c)) break; }
//c 获得指令中的某个部分的值,并根据opmode进行校验
+//c 这里的base就是luaV_execute中的base
#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
@@ -373,13 +374,14 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
}
-//c 虚拟机主入口
+//c!! 虚拟机主入口
+//c 在执行前,需要调用luaD_precall()设置虚拟机的指针、栈等,指向这个函数
//c 执行lua函数(不含C函数,C函数在luaD_precall执行)
//c 读取字节码并运行,沟通前端和后端的桥梁
//c 在ldo.c->luaD_call函数中执行,前一步是luaD_precall()
void luaV_execute (lua_State *L, int nexeccalls) {
- //c 管理指令和数据栈的4个变量,会随着函数调用而改变
+ //c 管理指令和数据栈的4个变量,会随着函数调用而改变,这样就实现的调用栈
LClosure *cl;// lua closure,包含函数原型、upvalue、环境env
StkId base;// 当前调用的base地址
TValue *k;// 当前函数原型里面的常数表