diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lua51/lapi.c | 9 | ||||
| -rw-r--r-- | src/lua51/lauxlib.c | 1 | ||||
| -rw-r--r-- | src/lua51/lauxlib.h | 1 | ||||
| -rw-r--r-- | src/lua51/ldo.c | 47 | ||||
| -rw-r--r-- | src/lua51/lfunc.c | 13 | ||||
| -rw-r--r-- | src/lua51/lobject.h | 39 | ||||
| -rw-r--r-- | src/lua51/lstate.h | 11 | ||||
| -rw-r--r-- | src/lua51/lvm.c | 9 |
8 files changed, 94 insertions, 36 deletions
diff --git a/src/lua51/lapi.c b/src/lua51/lapi.c index eeaa5ad..a476634 100644 --- a/src/lua51/lapi.c +++ b/src/lua51/lapi.c @@ -795,13 +795,14 @@ struct CallS { /* data to `f_call' */ }; +//c 执行字节码,调用luaD_call进入虚拟机主循环 static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); luaD_call(L, c->func, c->nresults); } -//c +//c 执行字节码 LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { struct CallS c; int status; @@ -816,8 +817,10 @@ 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 */ //调用的函数的指针,是f_parser函数的输出,放在栈顶的那个指针 + //c 调用的函数的指针,是f_parser函数的输出,放在栈顶的那个指针 + c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; + //c 进入虚拟机主循环 f_call status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); adjustresults(L, nresults); lua_unlock(L); @@ -868,7 +871,7 @@ 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); - //c 保护模式下编译源代码 + //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 343ec0d..c6ec9b0 100644 --- a/src/lua51/lauxlib.c +++ b/src/lua51/lauxlib.c @@ -579,6 +579,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { lf.extraline = 0; } ungetc(c, lf.f); + //c 在这里编译源代码,生成一个闭包留在栈顶 status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ diff --git a/src/lua51/lauxlib.h b/src/lua51/lauxlib.h index 3425823..51c9528 100644 --- a/src/lua51/lauxlib.h +++ b/src/lua51/lauxlib.h @@ -108,6 +108,7 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) +//c luaL_loadfile() 进行词法\语法分析,lua_pcall在虚拟机执行字节码 #define luaL_dofile(L, fn) \ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) diff --git a/src/lua51/ldo.c b/src/lua51/ldo.c index d9b1ea8..2311d41 100644 --- a/src/lua51/ldo.c +++ b/src/lua51/ldo.c @@ -1,3 +1,6 @@ +//c 函数调用及栈管理 + + /* ** $Id: ldo.c,v 2.38.1.4 2012/01/18 02:27:10 roberto Exp $ ** Stack and Call structure of Lua @@ -266,6 +269,7 @@ static StkId tryfuncTM (lua_State *L, StkId func) { //c 做函数调用前的准备 //c 将函数原型的指令code放在savedpc中,准备就绪 +//c 在 luaD_call 调用 int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; @@ -273,11 +277,12 @@ 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;//c 先把当前虚拟机执行的位置保存下来,留给后面调用完函数后luad_poscall恢复到这个位置 + //c 先把当前虚拟机执行的位置保存下来,留给后面调用完函数后luaD_poscall恢复到这个位置 + L->ci->savedpc = L->savedpc; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; - Proto *p = cl->p; + Proto *p = cl->p; //c 拿到Proto luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); if (!p->is_vararg) { /* no varargs? */ @@ -290,23 +295,27 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { base = adjust_varargs(L, p, nargs); func = restorestack(L, funcr); /* previous call may change the stack */ } - ci = inc_ci(L); /* now `enter' new function */ + + //c 设置这次调用的CallInfo并将 L 的相关指针设到这个调用上。L和ci的top及base一致 + ci = inc_ci(L); /* now `enter' new function */ //c 申请一个新的CallInfo结构 ci->func = func; - L->base = ci->base = base; + L->base = ci->base = base; //c base 一致 ci->top = L->base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); - L->savedpc = p->code; /* starting point */ + L->savedpc = p->code; /* starting point */ //c 设置savedpc为字节码的首地址 ci->tailcalls = 0; ci->nresults = nresults; - //c 将多余的参数赋值为nil,比如函数定义需要3个参数,但是只穿了1个,那么另外两个赋值为nil + //c 将多余的参数赋值为nil,比如函数定义需要3个参数,但是只传了1个,那么另外两个赋值为nil for (st = L->top; st < ci->top; st++) setnilvalue(st); - L->top = ci->top; + L->top = ci->top; //c top一致 + if (L->hookmask & LUA_MASKCALL) { L->savedpc++; /* hooks assume 'pc' is already incremented */ luaD_callhook(L, LUA_HOOKCALL, -1); L->savedpc--; /* correct 'pc' */ } + return PCRLUA; } else { /* if is a C function, call it */ @@ -352,9 +361,11 @@ static StkId callrethooks (lua_State *L, StkId firstResult) { //c 函数执行完毕后,将lua_state恢复到上一次函数调用的状态 +//c 在lvm.c > luaV_execute() 中当执行到OP_RETURN时调用 int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; + //c 本次调用的ci CallInfo *ci; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); @@ -362,7 +373,8 @@ 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 */ //c 恢复到调用之前的状态,很好理解,在父函数处这个函数执行完了,可以接着走了 + //c 恢复到调用之前的状态,很好理解,在父函数处这个函数执行完了,可以接着走了 + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); @@ -390,7 +402,8 @@ void luaD_call (lua_State *L, StkId func, int nResults) { //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 */ + luaV_execute(L, 1); /* call it */ //c 虚拟机主函数 + //c 结束之后还会在luaV_execute里调luaD_poscall L->nCcalls--; luaC_checkGC(L); } @@ -504,11 +517,11 @@ struct SParser { /* data to `f_parser' */ const char *name; }; -//c 词法分析和语法分析,调用luaY_parser +//c 对读入的源代码,执行词法分析和语法分析,调用luaY_parser //c 执行完后将closure留在栈顶 static void f_parser (lua_State *L, void *ud) { int i; - Proto *tf; + Proto *tf; //c 闭包对应的函数原型 Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); @@ -517,12 +530,18 @@ static void f_parser (lua_State *L, void *ud) { //c 如果是source,走编译流程 tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, &p->buff, p->name); + + //c 编译之后会得到Proto* tf, 所有的信息,包括常量表、upvalue、字节码、local变量数量等等都在里面 + cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); - cl->l.p = tf; - //c 初始化upvalue + cl->l.p = tf; //c 设置proto = tf + //c 新建nups个closed upvalue for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); - setclvalue(L, L->top, cl);//把闭包放在栈顶 + + //c 把闭包放在栈顶 + //c lua_pcall会执行这个闭包 + setclvalue(L, L->top, cl); incr_top(L); } diff --git a/src/lua51/lfunc.c b/src/lua51/lfunc.c index 813e88f..df2c8e3 100644 --- a/src/lua51/lfunc.c +++ b/src/lua51/lfunc.c @@ -30,21 +30,24 @@ Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { } +//c 新建lua closure +//c nelems upvalue的个数 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->l.isC = 0; - c->l.env = e; + luaC_link(L, obj2gco(c), LUA_TFUNCTION); //c 加入GC链表 + c->l.isC = 0; //c not c closure + c->l.env = e; //c 设置这个闭包的环境 c->l.nupvalues = cast_byte(nelems); while (nelems--) c->l.upvals[nelems] = NULL; return c; } +//c 新建一个closed upvalue UpVal *luaF_newupval (lua_State *L) { UpVal *uv = luaM_new(L, UpVal); - luaC_link(L, obj2gco(uv), LUA_TUPVAL); - uv->v = &uv->u.value; + luaC_link(L, obj2gco(uv), LUA_TUPVAL); //c 加入GC链表 + uv->v = &uv->u.value; //c closed setnilvalue(uv->v); return uv; } diff --git a/src/lua51/lobject.h b/src/lua51/lobject.h index 4e9daee..ead9391 100644 --- a/src/lua51/lobject.h +++ b/src/lua51/lobject.h @@ -242,14 +242,14 @@ typedef struct Proto { CommonHeader; //c 常量表,能看出来lua保存常量的单元是函数原型,所有代码片段都会被编译为proto TValue *k; /* constants used by the function */ - //c 函数字节码 + //c 函数字节码起始点 Instruction *code; //c 内部函数 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 + //c upvalues TString **upvalues; /* upvalue names */ TString *source; //文件名 int sizeupvalues; @@ -262,9 +262,9 @@ typedef struct Proto { int lastlinedefined; GCObject *gclist; lu_byte nups; /* number of upvalues */ - lu_byte numparams; - lu_byte is_vararg; - lu_byte maxstacksize; + lu_byte numparams; //c 参数个数 + lu_byte is_vararg; //c 是否是可变参数... + lu_byte maxstacksize; //c 最大栈大小, 通常200 } Proto; @@ -286,10 +286,35 @@ typedef struct LocVar { /* ** Upvalues */ -// 判断upvalue是关闭的方式是 uv->v == &uv->u.value +//c 判断upvalue是关闭的方式是 uv->v == &uv->u.value +//c upvalue有开闭的概念 +//c 开是指upvalue完全由此方法所有,之前的调用已经结束 +//c 关闭是指upvalue还在之前的栈上 +/* +* function func() +* local a = 10; +* local b = function() +* a = a + 1 +* print(a) +* end +* b() -- 这个是开 +* end +* +* function func() +* local a = 10; +* local b = function() +* a = a + 1 +* print(a) +* end +* return b +* end +* +* fn = func() +* fn() -- 这个是关 +*/ typedef struct UpVal { CommonHeader; - TValue *v; /* points to stack or to its own value */ + 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) */ diff --git a/src/lua51/lstate.h b/src/lua51/lstate.h index 1c049e1..8da0640 100644 --- a/src/lua51/lstate.h +++ b/src/lua51/lstate.h @@ -58,10 +58,13 @@ typedef struct CallInfo { StkId base; /* base for this function */ //c 函数原型在lua_State数据栈上的位置 StkId func; /* function index in the stack */ + //c 此函数调用过程中的top指针 StkId top; /* top for this function */ //c 当前执行到的指令位置 const Instruction *savedpc; + //c 期待的返回值个数 int nresults; /* expected number of results from this function */ + //c 尾调用个数 int tailcalls; /* number of tail calls lost under this entry */ } CallInfo; @@ -129,11 +132,13 @@ struct lua_State { 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 */ //c 每个方法被调用时都会得到自己的一组虚拟寄存器 + //c 当前函数栈的基地址,给某个函数用,在luad_precall函数中设置L->base = ci->base = ci->func + 1; + //c 每个方法被调用时都会得到自己的一组虚拟“寄存器”,也就是栈上面的数据 + StkId base; /* base of current function */ global_State *l_G; - //c 当前函数的调用信息,是base_ci数组中的某个 + //c 当前执行中函数的调用信息,是base_ci数组中的某个 CallInfo *ci; /* call info for current function */ + //c 当前执行到的指令位置。为了处理函数的调用和恢复,会在luaD_precall和luaD_poscall设置和恢复 const Instruction *savedpc; /* `savedpc' of current function */ //c lua_State数据栈的终点 StkId stack_last; /* last free slot in the stack */ diff --git a/src/lua51/lvm.c b/src/lua51/lvm.c index b353500..ea1d019 100644 --- a/src/lua51/lvm.c +++ b/src/lua51/lvm.c @@ -378,17 +378,18 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, //c 读取字节码并运行,沟通前端和后端的桥梁 //c 在ldo.c->luaD_call函数中执行,前一步是luaD_precall() void luaV_execute (lua_State *L, int nexeccalls) { + //c 管理指令和数据栈的4个变量,会随着函数调用而改变 LClosure *cl;// lua closure,包含函数原型、upvalue、环境env StkId base;// 当前调用的base地址 TValue *k;// 当前函数原型里面的常数表 - const Instruction *pc; //c 执行的指令 + const Instruction *pc; //c 指令指针 //c 此函数已经返回或调用了其他函数 - reentry: /* entry point */ +reentry: /* entry point */ lua_assert(isLua(L->ci)); // 做一个防护,重入必然是lua代码,OP_CALL和OP_TAILCALL会用luaD_precall处理C函数调用 - pc = L->savedpc;//c 最开始是luaD_precall中赋值的函数原型的指令开头 + pc = L->savedpc;//c 最开始是luaD_precall中赋值的函数原型的指令开头,L->savedpc在luaD_precall中设置 cl = &clvalue(L->ci->func)->l; base = L->base; //c base是寄存器开始地址,每个方法被调用时都会得到自己的一组虚拟寄存器 k = cl->p->k; //c 当前函数原型的常量,所有函数调用都会用到的 @@ -650,7 +651,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); L->savedpc = pc; - b = luaD_poscall(L, ra); + b = luaD_poscall(L, ra); //c! 执行结束后,将L恢复到调用前的状态 if (--nexeccalls == 0) /* was previous function running `here'? */ return; /* no: return */ else { /* yes: continue its execution */ |
