diff options
Diffstat (limited to 'src')
32 files changed, 370 insertions, 101 deletions
diff --git a/src/00-misc/math_return_table/init.lua b/src/00-misc/math_return_table/init.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/init.lua diff --git a/src/00-misc/math_return_table/matrix.lua b/src/00-misc/math_return_table/matrix.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/matrix.lua diff --git a/src/00-misc/math_return_table/misc/guid.lua b/src/00-misc/math_return_table/misc/guid.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/misc/guid.lua diff --git a/src/00-misc/math_return_table/misc/init.lua b/src/00-misc/math_return_table/misc/init.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/misc/init.lua diff --git a/src/00-misc/math_return_table/misc/lerp.lua b/src/00-misc/math_return_table/misc/lerp.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/misc/lerp.lua diff --git a/src/00-misc/math_return_table/misc/rand.lua b/src/00-misc/math_return_table/misc/rand.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/misc/rand.lua diff --git a/src/00-misc/math_return_table/misc/uuid.lua b/src/00-misc/math_return_table/misc/uuid.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/misc/uuid.lua diff --git a/src/00-misc/math_return_table/quaternion.lua b/src/00-misc/math_return_table/quaternion.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/quaternion.lua diff --git a/src/00-misc/math_return_table/vector.lua b/src/00-misc/math_return_table/vector.lua new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/00-misc/math_return_table/vector.lua diff --git a/src/00-misc/misc.lua b/src/00-misc/misc.lua index e73d2e3..8894dbb 100644 --- a/src/00-misc/misc.lua +++ b/src/00-misc/misc.lua @@ -1,3 +1,5 @@ -package.preload["00-misc.vec"] = loadfile("00-misc/vec.lua") - -require("00-misc.vec") +a = "a" +b = "b" +c = "c" +c = nil +collectgarbage() diff --git a/src/00-misc/vec.lua b/src/00-misc/vec.lua index 2862a16..9d81f40 100644 --- a/src/00-misc/vec.lua +++ b/src/00-misc/vec.lua @@ -1 +1,2 @@ -print("vec.lua")
\ No newline at end of file +print("vec.lua") + diff --git a/src/lua51/lapi.c b/src/lua51/lapi.c index 5d5145d..0678908 100644 --- a/src/lua51/lapi.c +++ b/src/lua51/lapi.c @@ -801,7 +801,7 @@ static void f_call (lua_State *L, void *ud) { } - +//c LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { struct CallS c; int status; @@ -816,7 +816,7 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { api_checkvalidindex(L, o); func = savestack(L, o); } - c.func = L->top - (nargs+1); /* function to be called */ + c.func = L->top - (nargs+1); /* function to be called */ //调用的函数的指针,是f_parser函数的输出,放在栈顶的那个指针 c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); adjustresults(L, nresults); @@ -859,6 +859,8 @@ LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { } +//c 加载代码,并编译生成函数原型 调用了f_parser +//c load完之后会生成一个closure(包含proto)在栈顶 LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; @@ -866,7 +868,8 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, lua_lock(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); - status = luaD_protectedparser(L, &z, chunkname); + //c 保护模式下编译源代码 + status = luaD_protectedparser(L, &z, chunkname); // 编译 lua_unlock(L); return status; } diff --git a/src/lua51/lauxlib.c b/src/lua51/lauxlib.c index 10f14e2..f1bdd39 100644 --- a/src/lua51/lauxlib.c +++ b/src/lua51/lauxlib.c @@ -548,7 +548,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { return LUA_ERRFILE; } - +//c 进行词法分析和语法分析 LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { LoadF lf; int status, readstatus; diff --git a/src/lua51/lauxlib.h b/src/lua51/lauxlib.h index 3425823..6ac7967 100644 --- a/src/lua51/lauxlib.h +++ b/src/lua51/lauxlib.h @@ -119,7 +119,7 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) /* -** {====================================================== +** ====================================================== ** Generic Buffer manipulation ** ======================================================= */ diff --git a/src/lua51/lcode.c b/src/lua51/lcode.c index 679cb9c..e1da87b 100644 --- a/src/lua51/lcode.c +++ b/src/lua51/lcode.c @@ -786,6 +786,7 @@ void luaK_fixline (FuncState *fs, int line) { } +//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/ldo.c b/src/lua51/ldo.c index d1bf786..eac8d03 100644 --- a/src/lua51/ldo.c +++ b/src/lua51/ldo.c @@ -149,6 +149,7 @@ void luaD_reallocstack (lua_State *L, int newsize) { } +//c void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); @@ -165,7 +166,8 @@ void luaD_growstack (lua_State *L, int n) { luaD_reallocstack(L, L->stacksize + n); } - +//c 当分配的callinfo数组不够大的,以2的指数扩展它 +//c callinfo的大小不会超过LUAI_MAXCALLS static CallInfo *growCI (lua_State *L) { if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); @@ -256,12 +258,14 @@ static StkId tryfuncTM (lua_State *L, StkId func) { } - +//c 如果不够大了,扩容;然后返回++L->ci,即下一个ci #define inc_ci(L) \ ((L->ci == L->end_ci) ? growCI(L) : \ (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) +//c 做函数调用前的准备 +//c 将函数原型的指令code放在savedpc中,准备就绪 int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; @@ -269,7 +273,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = &clvalue(func)->l; - L->ci->savedpc = L->savedpc; + L->ci->savedpc = L->savedpc;//c 先把当前虚拟机执行的位置保存下来,留给后面调用完函数后luad_poscall恢复到这个位置 if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; @@ -294,6 +298,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { L->savedpc = p->code; /* starting point */ ci->tailcalls = 0; ci->nresults = nresults; + //c 将多余的参数赋值为nil,比如函数定义需要3个参数,但是只穿了1个,那么另外两个赋值为nil for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; @@ -305,14 +310,20 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { return PCRLUA; } else { /* if is a C function, call it */ + //c 这里能发现两个限制,一个是函数调用的嵌套限制LUAI_MAXCALL,一个是函数调用需要的数据栈大小不能超过 + //c lua_State数据栈的大小BASIC_STACK_SIZE + EXTRA_STACK(在stack_init函数中) + CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + //c 找一个新的调用CallInfo对象,如果lua_state的callinfo数组不够大了,扩展它,但不能超过LUAI_MAXCALLS + //c 拿到下一个callinfo对象 ci = inc_ci(L); /* now `enter' new function */ - ci->func = restorestack(L, funcr); - L->base = ci->base = ci->func + 1; - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); + ci->func = restorestack(L, funcr);//c callinfo的函数原型 + //c 从这里能看出,lua_state的数据栈的base是跟着调用变动的 + L->base = ci->base = ci->func + 1;//c 设置当前调用的数据栈 + ci->top = L->top + LUA_MINSTACK;//c 设置当前调用的最大数据栈容量 + lua_assert(ci->top <= L->stack_last); //c 调用的栈顶不能超过lua数据栈的上限 ci->nresults = nresults; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); @@ -340,6 +351,7 @@ static StkId callrethooks (lua_State *L, StkId firstResult) { } +//c 函数执行完毕后,将lua_state恢复到上一次函数调用的状态 int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; @@ -350,7 +362,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) { res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; L->base = (ci - 1)->base; /* restore base */ - L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ //c 恢复到调用之前的状态,很好理解,在父函数处这个函数执行完了,可以接着走了 /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); @@ -361,6 +373,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) { } +//c 执行代码的入口,不限于函数(因为lua代码段就是封装为了函数) /* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. @@ -374,6 +387,8 @@ void luaD_call (lua_State *L, StkId func, int nResults) { else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } + //c luad_precall将函数指令放在lua_state的savedpc字段,准备就绪 + //c luaV_execute执行函数原型的指令,是执行指令的入口 if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ luaV_execute(L, 1); /* call it */ L->nCcalls--; @@ -453,6 +468,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) { } +//c 调用函数 int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; @@ -488,6 +504,8 @@ struct SParser { /* data to `f_parser' */ const char *name; }; +//c 词法分析和语法分析,调用luaY_parser +//c 执行完后将closure留在栈顶 static void f_parser (lua_State *L, void *ud) { int i; Proto *tf; @@ -499,18 +517,21 @@ static void f_parser (lua_State *L, void *ud) { &p->buff, p->name); cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; + //c 初始化upvalue for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); - setclvalue(L, L->top, cl); + setclvalue(L, L->top, cl);//把闭包放在栈顶 incr_top(L); } +//c 保护模式下编译代码 int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); + //c在保护模式下执行 f_parser 函数 status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); return status; diff --git a/src/lua51/lgc.c b/src/lua51/lgc.c index e909c79..f4dbdfb 100644 --- a/src/lua51/lgc.c +++ b/src/lua51/lgc.c @@ -48,7 +48,7 @@ #define VALUEWEAK bitmask(VALUEWEAKBIT) - +// 标记对象,有点类似一个安全声明,mark了的对象不会被回收,会被标记为灰色(大多数情况下)或黑色 #define markvalue(g,o) { checkconsistency(o); \ if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } @@ -66,16 +66,24 @@ static void removeentry (Node *n) { } +//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本身也不会引用其他对象,所以不需要扫描,直接标记为黑色 Table *mt = gco2u(o)->metatable; + // 直接标记为黑色 gray2black(o); /* udata are never gray */ + // 标记一下它的mt和env表 if (mt) markobject(g, mt); markobject(g, gco2u(o)->env); return; @@ -83,6 +91,8 @@ static void reallymarkobject (global_State *g, GCObject *o) { case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); + // 当这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系 + // 直接标记黑色 if (uv->v == &uv->u.value) /* closed? */ gray2black(o); /* open upvalues are never black */ return; @@ -154,7 +164,8 @@ size_t luaC_separateudata (lua_State *L, int all) { return deadmem; } - +// 遍历table +// 如果是弱表,返回1 static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; @@ -170,16 +181,23 @@ static int traversetable (global_State *g, Table *h) { h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); + // 加到weak链表 h->gclist = g->weak; /* must be cleared after GC, ... */ g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } - if (weakkey && weakvalue) return 1; + if (weakkey && weakvalue) return 1; // 如果是弱表,返回1 + + // 如果不是弱表,遍历table的散列部分和数组部分所有元素 + + //数组 if (!weakvalue) { i = h->sizearray; while (i--) markvalue(g, &h->array[i]); } + + //散列 i = sizenode(h); while (i--) { Node *n = gnode(h, i); @@ -277,24 +295,25 @@ static void traversestack (global_State *g, lua_State *l) { static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); - gray2black(o); + gray2black(o);//预先标记为黑色 switch (o->gch.tt) { - case LUA_TTABLE: { + case LUA_TTABLE: { //扫描table,尝试标记数组和哈希部分 Table *h = gco2h(o); g->gray = h->gclist; + // 如果是弱表,回退回灰色状态 if (traversetable(g, h)) /* table is weak? */ black2gray(o); /* keep it gray */ return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } - case LUA_TFUNCTION: { + case LUA_TFUNCTION: { //扫描函数,尝试标记env、upvalue Closure *cl = gco2cl(o); g->gray = cl->c.gclist; traverseclosure(g, cl); return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); } - case LUA_TTHREAD: { + case LUA_TTHREAD: { //扫描线程对象, lua_State *th = gco2th(o); g->gray = th->gclist; th->gclist = g->grayagain; @@ -428,11 +447,15 @@ 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 给桶瘦身 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && - g->strt.size > MINSTRTABSIZE*2) + g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ @@ -497,15 +520,21 @@ static void markmt (global_State *g) { } +//c 初始化root +//c 将mainthread, /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); + // 清空 g->gray = NULL; g->grayagain = NULL; g->weak = NULL; + // 标记mainthread markobject(g, g->mainthread); /* make global table be traversed before main stack */ + // 标记 _G 为灰色 markvalue(g, gt(g->mainthread)); + // 标记注册表为灰色 markvalue(g, registry(L)); markmt(g); g->gcstate = GCSpropagate; @@ -553,15 +582,16 @@ static void atomic (lua_State *L) { } +//c! 单步GC的入口 static l_mem singlestep (lua_State *L) { global_State *g = G(L); /*lua_checkmemory(L);*/ switch (g->gcstate) { - case GCSpause: { + case GCSpause: { // 初始化 markroot(L); /* start a new collection */ return 0; } - case GCSpropagate: { + case GCSpropagate: { // 扫描并标记 if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ @@ -681,27 +711,33 @@ void luaC_barrierback (lua_State *L, Table *t) { 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发生在标记阶段后 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { global_State *g = G(L); o->gch.next = g->rootgc; g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; + o->gch.marked = luaC_white(g);//标记为current white + o->gch.tt = tt;//设置数据类型 } - +//c! 将一个upvalue加入root,由于upvalue是对已经存在的对象的间接引用,所以和普通对象不太一样 void luaC_linkupval (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = obj2gco(uv); o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; + // 这里和普通对象不一样 if (isgray(o)) { - if (g->gcstate == GCSpropagate) { + if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接将对象置为黑色 gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } - else { /* sweep phase: sweep it (turning it into white) */ + else { /* 否则的话和普通对象一样置为白色 */ /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } diff --git a/src/lua51/lgc.h b/src/lua51/lgc.h index 5a8dc60..9fa686a 100644 --- a/src/lua51/lgc.h +++ b/src/lua51/lgc.h @@ -14,11 +14,11 @@ /* ** Possible states of the Garbage Collector */ -#define GCSpause 0 -#define GCSpropagate 1 -#define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSpause 0 // 暂停 +#define GCSpropagate 1 // 扫描,正在遍历灰色节点,检查引用情况 +#define GCSsweepstring 2 // 字符串回收阶段 +#define GCSsweep 3 // 除了字符串的其他对象的回收阶段 +#define GCSfinalize 4 // 终止阶段 /* @@ -51,15 +51,15 @@ */ -#define WHITE0BIT 0 -#define WHITE1BIT 1 +#define WHITE0BIT 0 // 01 +#define WHITE1BIT 1 // 10 #define BLACKBIT 2 -#define FINALIZEDBIT 3 -#define KEYWEAKBIT 3 -#define VALUEWEAKBIT 4 -#define FIXEDBIT 5 -#define SFIXEDBIT 6 -#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) +#define FINALIZEDBIT 3 //标记没有被引用的udata +#define KEYWEAKBIT 3 //标记弱表的key +#define VALUEWEAKBIT 4 // 标记弱表的value +#define FIXEDBIT 5 // 标记lua_state主线程对象不可回收 +#define SFIXEDBIT 6 // 标记lua关键字不要回收 +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) // 结果是11 #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) @@ -74,6 +74,8 @@ #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) diff --git a/src/lua51/llex.c b/src/lua51/llex.c index 88c6790..fe4e3ee 100644 --- a/src/lua51/llex.c +++ b/src/lua51/llex.c @@ -33,6 +33,7 @@ #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') +//c 对应RESERVED中的枚举, tokens /* ORDER RESERVED */ const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", @@ -61,12 +62,15 @@ static void save (LexState *ls, int c) { } +//c 设置保留字 void luaX_init (lua_State *L) { int i; for (i=0; i<NUM_RESERVED; i++) { TString *ts = luaS_new(L, luaX_tokens[i]); luaS_fix(ts); /* reserved words are never collected */ lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); + //c 标记这个字符串为保留字,即不为零 + //c luaX_tokens中的索引 ts->tsv.reserved = cast_byte(i+1); /* reserved word */ } } diff --git a/src/lua51/llex.h b/src/lua51/llex.h index a9201ce..8a013f9 100644 --- a/src/lua51/llex.h +++ b/src/lua51/llex.h @@ -17,6 +17,7 @@ #define TOKEN_LEN (sizeof("function")/sizeof(char)) +//c tokens枚举,用来做终结符 /* * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" diff --git a/src/lua51/lobject.h b/src/lua51/lobject.h index f1e447e..af6b63a 100644 --- a/src/lua51/lobject.h +++ b/src/lua51/lobject.h @@ -40,6 +40,10 @@ typedef union GCObject GCObject; ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ +// 需要垃圾回收的类型包含这个头 +//c next 指向下一个gc链表的成员 +//c tt 数据类型 +//c GC标记,用来保存颜色,有白色(2种),灰色和黑色 #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked @@ -53,6 +57,8 @@ typedef struct GCheader { +//c lua_TValue下第二高级的数据封装类型,不含数据类型标识 +//c 包含需要GC的类型和不需要GC的类型 /* ** Union of all Lua values */ @@ -68,8 +74,10 @@ typedef union { ** Tagged Values */ +//c 用在两个地方,lua_TValue和TKey #define TValuefields Value value; int tt +//c 最上层的Value类型,包含值和类型 typedef struct lua_TValue { TValuefields; } TValue; @@ -112,7 +120,7 @@ typedef struct lua_TValue { lua_assert(!iscollectable(obj) || \ ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) - +//c 将TValue结构具体为对应的类型和值;即修改TValue的tt和value部分 /* Macros to set values */ #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) @@ -193,6 +201,9 @@ typedef struct lua_TValue { typedef TValue *StkId; /* index to stack elements */ +//c 字符串 +//c 每个字符串都需要计算hash,用来比较和查找字符串 +//c 如果这个字符串已经存在,不再生成新的字符串,而是使用旧的 /* ** String headers for string table */ @@ -200,8 +211,8 @@ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { CommonHeader; - lu_byte reserved; - unsigned int hash; + lu_byte reserved;//标记字符串是否是lua的关键字,如果是,不会被GC回收 + unsigned int hash;//字符串的哈希值,比较字符串的依据 size_t len; } tsv; } TString; @@ -210,8 +221,7 @@ typedef union TString { #define getstr(ts) cast(const char *, (ts) + 1) #define svalue(o) getstr(rawtsvalue(o)) - - +// userdata,和TString比较像 typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { @@ -223,18 +233,22 @@ typedef union Udata { } Udata; - - +//c! 函数原型,是沟通前端和后端(分析阶段和执行阶段)的数据 +//c! 主要有 字节码、常量、局部变量、upvalue /* ** Function Prototypes */ typedef struct Proto { CommonHeader; + //c 函数的常量 TValue *k; /* constants used by the function */ + //c 函数字节码 Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ + //c 局部变量 struct LocVar *locvars; /* information about local variables */ + //c upvalue TString **upvalues; /* upvalue names */ TString *source; int sizeupvalues; @@ -259,6 +273,7 @@ typedef struct Proto { #define VARARG_NEEDSARG 4 +//c 局部变量 typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ @@ -312,6 +327,7 @@ typedef union Closure { } Closure; +//c 判断函数类型,5.2通过高位判断,在基础类型基础上产生变体 variant #define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) #define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) @@ -319,36 +335,54 @@ typedef union Closure { /* ** Tables */ - +//c 表的某个元素的key typedef union TKey { + //nk 用来拿到下一个node的指针 struct { - TValuefields; + TValuefields; // 就是TValue + //c 指向下一个node struct Node *next; /* for chaining */ - } nk; - TValue tvk; + } nk; // next key + //tvk 用来拿本node的key值 + TValue tvk; // key value } TKey; - +//c 表的单个元素 typedef struct Node { - TValue i_val; - TKey i_key; + TValue i_val;//value + TKey i_key; //key } Node; +//c 表 typedef struct Table { CommonHeader; + //c 标记这个表有哪些元方法,第一次查找时为0,如果有某个元方法,将对应位置为1 + //c 下次查找时就不需要查找字符串了 + //c flag会在luaH_set清空 lu_byte flags; /* 1<<p means tagmethod(p) is not present */ + //c lsizenode=log2(length of hash table) 由此可知散列表大小一定是2的幂 + //c 所以如果散列表要扩展,在原大小基础上扩展一倍 + //c 要得到散列表大小,只需要移位 length of hash table = 1 << lsizenode lu_byte lsizenode; /* log2 of size of `node' array */ + //c 该表的元表 struct Table *metatable; + //c 数组部分 TValue *array; /* array part */ + //c 散列桶起始位置 + //c 多个桶,桶内通过TKey->nk->next连接 Node *node; + //c 空位置 Node *lastfree; /* any free position is before this position */ + //c 在global_State中有关gc的链表的下一个(如果这个对象被加入了的话) GCObject *gclist; + //c 数组部分的大小 int sizearray; /* size of `array' array */ } Table; +//c 计算哈希值,用在很多地方 /* ** `module' operation for hashing (size is always a power of 2) */ diff --git a/src/lua51/lopcodes.c b/src/lua51/lopcodes.c index 4cc7452..64652bb 100644 --- a/src/lua51/lopcodes.c +++ b/src/lua51/lopcodes.c @@ -55,7 +55,12 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { NULL }; - +//c 限制每个指令的具体格式,用来后续判断 +//c t 是不是逻辑判断类指令,如相等,大于,小于 +//c a 此指令会不会赋值给寄存器A +//c b 参数格式OpArgMask,如是寄存器,指令跳转偏移,常数 +//c c 同上 +//c m 指令格式 #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) const lu_byte luaP_opmodes[NUM_OPCODES] = { diff --git a/src/lua51/lopcodes.h b/src/lua51/lopcodes.h index 41224d6..8c0d1a8 100644 --- a/src/lua51/lopcodes.h +++ b/src/lua51/lopcodes.h @@ -34,13 +34,24 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* ** size and position of opcode arguments. */ -#define SIZE_C 9 -#define SIZE_B 9 -#define SIZE_Bx (SIZE_C + SIZE_B) -#define SIZE_A 8 +/* +三种指令的格式 +iABC B:9 C:9 A:8 Opcode:6 +iABx Bx:18 A:8 Opcode:6 +iAsBx sBx:18 A:8 Opcode:6 +注:sBx是signed BX +寄存器就是相对于callinfo和lua_state的当前调用的base的某个偏移(即ABC值) +*/ +//c 单个指令Instruction的每部分的大小 +// 9 + 9 + 8 + 6 = 32 bits +#define SIZE_B 9 +#define SIZE_C 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 #define SIZE_OP 6 +//c 每个部分在Instruction中的偏移量,从低位到高位 #define POS_OP 0 #define POS_A (POS_OP + SIZE_OP) #define POS_C (POS_A + SIZE_A) @@ -76,7 +87,7 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* ** the following macros help to manipulate instructions */ - +//c 获取和设置Instruction中的某个部分 #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)))) @@ -115,9 +126,11 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ ** Macros to operate RK indices */ +//c 高位为1时代表常数 /* this bit 1 means constant (0 means register) */ #define BITRK (1 << (SIZE_B - 1)) +//c 检查x是不是常量,规定高位是1的话就是常量,去常量表里查,而不是寄存器 /* test whether value is a constant */ #define ISK(x) ((x) & BITRK) @@ -241,12 +254,12 @@ 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 指令的参数格式 enum OpArgMask { - OpArgN, /* argument is not used */ - OpArgU, /* argument is used */ - OpArgR, /* argument is a register or a jump offset */ - OpArgK /* argument is a constant or register/constant */ + OpArgN, /* argument is not used */ // 未使用(没有座位R()和RK()的参数使用) + OpArgU, /* argument is used */ // 使用的 + OpArgR, /* argument is a register or a jump offset */ // 寄存器、跳转偏移 + OpArgK /* argument is a constant or register/constant */ // 寄存器、常量 }; LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; diff --git a/src/lua51/lparser.c b/src/lua51/lparser.c index dda7488..7da34e7 100644 --- a/src/lua51/lparser.c +++ b/src/lua51/lparser.c @@ -380,9 +380,10 @@ static void close_func (LexState *ls) { } +//c! 编译生成字节码,分析阶段的唯一入口,返回proto指针 Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { 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); @@ -394,7 +395,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fs == NULL); - return funcstate.f; + return funcstate.f; //c 最终生成的字节码 } diff --git a/src/lua51/lstate.c b/src/lua51/lstate.c index 4313b83..7e55cd0 100644 --- a/src/lua51/lstate.c +++ b/src/lua51/lstate.c @@ -39,6 +39,7 @@ typedef struct LG { +//c 初始化一个lua_state的栈 static void stack_init (lua_State *L1, lua_State *L) { /* initialize CallInfo array */ L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); diff --git a/src/lua51/lstate.h b/src/lua51/lstate.h index 3bc575b..1ec30a8 100644 --- a/src/lua51/lstate.h +++ b/src/lua51/lstate.h @@ -35,20 +35,31 @@ struct lua_longjmp; /* defined in ldo.c */ +//c 散列桶 +//c 全局存放字符串的地方。如果一个字符串在此存在,不用重新生成。 +//c 如果表扩张的太厉害,每个桶的字符串太多,会进行一次rehash,重新分配每个桶的数据量 +//c rehash在lstring.c -> luaS_resize typedef struct stringtable { - GCObject **hash; - lu_int32 nuse; /* number of elements */ - int size; + GCObject **hash; //c 字符串,因为是散列桶,所以是** + lu_int32 nuse; //c 桶用到的容量,因为不一定size都用到了 /* number of elements */ + int size; //c 桶的总容量,是常值 + // nuse和size是用来动态控制桶容量的关键 } stringtable; +//c 当前函数的调用信息,和lua_State的调用部分类似 +//c 都有top, base俩个与栈相关的成员 +//c StkId引用的永远是lua_State栈上的内容 /* ** informations about a call */ typedef struct CallInfo { + //c 当前调用的base值,即在栈上操作的开始位置 StkId base; /* base for this function */ + //c 函数原型在lua_State数据栈上的位置 StkId func; /* function index in the stack */ StkId top; /* top for this function */ + //c 当前执行到的指令位置 const Instruction *savedpc; int nresults; /* expected number of results from this function */ int tailcalls; /* number of tail calls lost under this entry */ @@ -61,31 +72,46 @@ typedef struct CallInfo { #define f_isLua(ci) (!ci_func(ci)->c.isC) #define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) - +//c 当前虚拟机所有协程共用的内容 /* ** `global state', shared by all threads of this state */ typedef struct global_State { + //c string table,开散列表,存储所有的字符串 stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ - lu_byte currentwhite; + lu_byte currentwhite;//当前白 + //c 当前的GC状态,有5个,在lgc.h定义 lu_byte gcstate; /* state of garbage collector */ + //c strt中字符串散列桶索引,字符串回收阶段每次回收一个散列桶的字符串, int sweepstrgc; /* position of sweep in `strt' */ + //c 白色链表。可回收的对象,会在回收阶段被回收 + //c 所有新建的对象都会暂存在这里,但不会被回收,因为lua有双白色机制 GCObject *rootgc; /* list of all collectable objects */ + //c 保存rootgc中当前回收到的位置,下次从这个位置继续回收 GCObject **sweepgc; /* position of sweep in `rootgc' */ + //c 灰色链表 GCObject *gray; /* list of gray objects */ + //c 不可被打断的对象的灰色链表 GCObject *grayagain; /* list of objects to be traversed atomically */ + //c 弱表 GCObject *weak; /* list of weak tables (to be cleared) */ + //c 有__gc方法的userdata GCObject *tmudata; /* last element of list of userdata to be GC */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; + //c 开始进行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开始时机 int gcpause; /* size of pause between successive GCs */ + //c 控制GC回收速度 int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ + //c 注册表 TValue l_registry; struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ @@ -94,20 +120,29 @@ typedef struct global_State { } global_State; +//c 一个lua_state,可以看做是一个 +//c StkId引用的永远是lua_State栈上的内容 /* ** `per thread' state */ struct lua_State { CommonHeader; lu_byte status; + //c 当前栈的下一个可用位置 StkId top; /* first free slot in the stack */ + //c 当前*函数栈*的基地址,给某个函数用,在luad_precall函数中设置L->base = ci->base = ci->func + 1; StkId base; /* base of current function */ global_State *l_G; + //c 当前函数的调用信息,是base_ci数组中的某个 CallInfo *ci; /* call info for current function */ const Instruction *savedpc; /* `savedpc' of current function */ + //c lua_State数据栈的终点 StkId stack_last; /* last free slot in the stack */ + //c 数据栈(栈数组的起始地址)(数据栈的起始点) StkId stack; /* stack base */ + //c callinfo数组的终点 CallInfo *end_ci; /* points after end of ci array*/ + //c callinfo 数组, 沿着base_ci遍历可以得到完整的lua调用链 CallInfo *base_ci; /* array of CallInfo's */ int stacksize; int size_ci; /* size of array `base_ci' */ @@ -118,6 +153,7 @@ struct lua_State { int basehookcount; int hookcount; lua_Hook hook; + //c _G global table TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ @@ -130,6 +166,10 @@ struct lua_State { #define G(L) (L->l_G) +//c 需要GC的类型基类,通过GCObject能够引用到GCheader中定义的/ +//c #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked +//c 这种写法是一种实现C继承的方式 +//c 每个 /* ** Union of all collectable objects */ @@ -144,7 +184,7 @@ union GCObject { struct lua_State th; /* thread */ }; - +//c TValue\GCObject 获取union中的内容 /* macros to convert a GCObject into a specific value */ #define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) diff --git a/src/lua51/lstring.c b/src/lua51/lstring.c index 4911315..ec1fcdb 100644 --- a/src/lua51/lstring.c +++ b/src/lua51/lstring.c @@ -19,25 +19,29 @@ +//c 重新分配global_State->strt每个桶的数据量 +//c 当桶的大小远超字符串容量,重新分配大小,删掉一些空桶(空位) void luaS_resize (lua_State *L, int newsize) { GCObject **newhash; stringtable *tb; int i; - if (G(L)->gcstate == GCSsweepstring) + if (G(L)->gcstate == GCSsweepstring)//如果GC在回收字符串阶段,不要rehash return; /* cannot resize during GC traverse */ - newhash = luaM_newvector(L, newsize, GCObject *); - tb = &G(L)->strt; + newhash = luaM_newvector(L, newsize, GCObject *); //建立一个新的散列桶,并清空 + tb = &G(L)->strt;//旧的散列桶 for (i=0; i<newsize; i++) newhash[i] = NULL; - /* rehash */ + //遍历就的散列桶,并填入新的散列桶 + /* rehash */ for (i=0; i<tb->size; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ unsigned int h = gco2ts(p)->hash; + //新的散列值 int h1 = lmod(h, newsize); /* new position */ lua_assert(cast_int(h%newsize) == lmod(h, newsize)); - p->gch.next = newhash[h1]; /* chain it */ - newhash[h1] = p; + p->gch.next = newhash[h1];//c 接在同一个hash的最前面 /* chain it */ + newhash[h1] = p; //c 将p作为桶内第一个存起来 p = next; } } @@ -47,6 +51,7 @@ void luaS_resize (lua_State *L, int newsize) { } +//c 新建字符串 static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { TString *ts; @@ -62,42 +67,53 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ tb = &G(L)->strt; + // 计算hash值 h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ tb->hash[h] = obj2gco(ts); tb->nuse++; + //c 给字符串通扩容,如果字符串数量大于桶容量 + //c 给桶扩容为2倍 if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } +//c 创建字符串 TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; + //c 如果字符串非常长,不要逐位计算散列值,每step步取一个字符计算即可 for (l1=l; l1>=step; l1-=step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { TString *ts = rawgco2ts(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {//c 如果散列值相同,用memcmp快速对比 + //c 如果字符串被标记了回收(gch.marked),重新标记它不要回收 /* string may be dead */ if (isdead(G(L), o)) changewhite(o); return ts; } } + //c 如果global->strt里没有这个字符串,新建立一个,并加到哈希桶里 return newlstr(L, str, l, h); /* not found */ } - +//c 创建userdata +//c userdata的gc和普通对象(udata和uv除外的)是分开的 Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; 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 u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; @@ -105,7 +121,10 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { u->uv.env = e; /* chain it on udata list (after main thread) */ u->uv.next = G(L)->mainthread->next; - G(L)->mainthread->next = obj2gco(u); - return u; + // 可见所有userdata都跟在mainthread之后第一个 + // 这样是为了方便,是一个hack + // 由于userdata可能会定义了__gc,所以统一处理 + G(L)->mainthread->next = obj2gco(u); + return u; } diff --git a/src/lua51/ltable.c b/src/lua51/ltable.c index ec84f4f..f489a03 100644 --- a/src/lua51/ltable.c +++ b/src/lua51/ltable.c @@ -159,6 +159,9 @@ static int findindex (lua_State *L, Table *t, StkId key) { } +//c table的遍历操作,返回下一个node +//c 先计算key的hash,如果在array范围内,在array中找,否则在hash中找 +//c 注意实际上不会两个for循环都走 int luaH_next (lua_State *L, Table *t, StkId key) { int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ @@ -208,8 +211,10 @@ static int computesizes (int nums[], int *narray) { } +//c 返回1或0,是否将这个key算进要加入表的数组部分 static int countint (const TValue *key, int *nums) { int k = arrayindex(key); + //c 所以数字key的最大范围是0~MAXASIZE if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[ceillog2(k)]++; /* count as such */ return 1; @@ -294,6 +299,9 @@ static void setnodevector (lua_State *L, Table *t, int size) { } +//c 重新分配table的哈希部分大小为 +//nasize 是 array size +//nhsize 是 hash table size static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; @@ -330,18 +338,26 @@ void luaH_resizearray (lua_State *L, Table *t, int nasize) { } +//c 给table的散列桶部分重新hash +//c 用于给table扩容 static void rehash (lua_State *L, Table *t, const TValue *ek) { + //c 先计算落在2^(i-1)~2^i范围内的各个区间的元素数量,用于决策新容量 int nasize, na; + //c 以2的指数级扩展的数组,记录的是指数。能看出来表的最大大小是2^MAXBITS int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ int i; int totaluse; for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + //c 遍历数组部分和散列桶部分,找出正整数key的值的数量,以此更新nums[] nasize = numusearray(t, nums); /* count keys in array part */ totaluse = nasize; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ /* count extra key */ + //c 加上这个key(如果在范围内的话) nasize += countint(ek, nums); totaluse++; + //c 找到一个位置i,这个位置之前的元素个数大于50%,即2^i/2。这个位置之后意味着太空了,效率比较低 + //c 这个位置 /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ @@ -354,7 +370,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); @@ -388,7 +404,7 @@ static Node *getfreepos (Table *t) { } - +//c 表新建key /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main @@ -398,30 +414,41 @@ static Node *getfreepos (Table *t) { */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || mp == dummynode) { + if (!ttisnil(gval(mp)) || mp == dummynode) {//c mainposition上已经有数据 Node *othern; Node *n = getfreepos(t); /* get a free place */ + //c 如果没有空位,扩展hash table大小为2倍 if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ + //c 扩展完大小后重试 return luaH_set(L, t, key); /* re-insert key into grown table */ } lua_assert(n != dummynode); + //c 先看一下现在mainposition上的这个node,它的mainposition是不是这个值 + //c 不是的话给新的key让路 othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ + // 把mp空出来,mp里的值移到n(freeposition) /* yes; move colliding node into free position */ + //? 这行没看懂 while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); + //mp是要赋值的位置,即新key的元素的位置 } else { /* colliding node is in its own main position */ /* new node will go into free position */ + //c 将free position插入到mp后第一个 gnext(n) = gnext(mp); /* chain new position */ gnext(mp) = n; + //c 修改一下mp指针,指向freeposition,留个后续使用 mp = n; } } + //c 如果mainposition位置上是空的,可以直接用mp位置存 + //c 赋值 gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); @@ -553,6 +580,7 @@ static int unbound_search (Table *t, unsigned int j) { } +//c 获得table长度 /* ** Try to find a boundary in table `t'. A `boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). @@ -560,7 +588,9 @@ static int unbound_search (Table *t, unsigned int j) { int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { + // 二分查找,找到 /* there is a boundary in the array part: (binary) search for it */ + // i是左界,j是右界 unsigned int i = 0; while (j - i > 1) { unsigned int m = (i+j)/2; diff --git a/src/lua51/lua.h b/src/lua51/lua.h index a4b73e7..9f45735 100644 --- a/src/lua51/lua.h +++ b/src/lua51/lua.h @@ -71,6 +71,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); */ #define LUA_TNONE (-1) +//c 对外的基础类型,但是内部会区分闭包(C\Lua)、函数(C\Lua)、userdata的类型 #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 diff --git a/src/lua51/lvm.c b/src/lua51/lvm.c index e0a0cd8..85e214a 100644 --- a/src/lua51/lvm.c +++ b/src/lua51/lvm.c @@ -343,7 +343,7 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, */ #define runtime_check(L, c) { if (!(c)) break; } - +//c 获得指令中的某个部分的值,并根据opmode进行校验 #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)) @@ -374,17 +374,25 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, +//c 执行lua函数(不含C函数,C函数在luaD_precall执行) +//c 读取字节码并运行,沟通前端和后端的桥梁 +//c 在ldo.c->luaD_call函数中执行,前一步是luaD_precall() void luaV_execute (lua_State *L, int nexeccalls) { - LClosure *cl; - StkId base; - TValue *k; - const Instruction *pc; + //c 管理指令和数据栈的4个变量,会随着函数调用而改变 + LClosure *cl;// lua closure,包含函数原型、upvalue、环境env + StkId base;// 当前调用的base地址 + TValue *k;// 当前函数原型里面的常数表 + const Instruction *pc; //c 执行的指令 + + //c 此函数已经返回或调用了其他函数 reentry: /* entry point */ - lua_assert(isLua(L->ci)); - pc = L->savedpc; + lua_assert(isLua(L->ci)); // 做一个防护,重入必然是lua代码,OP_CALL和OP_TAILCALL会用luaD_precall处理C函数调用 + + pc = L->savedpc;//c 最开始是luaD_precall中赋值的函数原型的指令开头 cl = &clvalue(L->ci->func)->l; base = L->base; - k = cl->p->k; + k = cl->p->k; //c 当前函数原型的常量,所有函数调用都会用到的 + /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; diff --git a/src/math/math.cpp b/src/math/math.cpp new file mode 100644 index 0000000..acb215f --- /dev/null +++ b/src/math/math.cpp @@ -0,0 +1,37 @@ +#include "math.h" + +#pragma comment(lib, "lua.lib") + +#define MATH_API __declspec(dllexport) + +MATH_API int /*__cdecl*/ luaopen_math_vector(lua_State* L) +{ + lua_pushstring(L, "math.vector module"); + + return 1; +} + + +extern "C" MATH_API int /*__cdecl*/ luaopen_math_matrix(lua_State* L) +{ + lua_pushstring(L, "math.matrix module"); + + return 1; +} + +extern "C" MATH_API int /*__cdecl*/ luaopen_math_quaternion(lua_State* L) +{ + lua_pushstring(L, "math.quaternion module"); + + return 1; +} + +MATH_API void foo() +{ + +} + +class MATH_API Vector +{ + +}; diff --git a/src/math/math.h b/src/math/math.h new file mode 100644 index 0000000..494b725 --- /dev/null +++ b/src/math/math.h @@ -0,0 +1,9 @@ +#pragma once + +extern "C" { +#include "../lua51/lua.h" +#include "../lua51/lualib.h" +#include "../lua51/lauxlib.h" +} + +//#define MATH_API __declspec(dllexport) |
