函数:{"getlocal", db_getlocal}
从db_getlocal开始跟调.该函数是把自身的所有变量打印出来。大体的思路是算到执行码,根据执行码的大小限制,遍历函数保存的变量信息,然后依次打印。
static int db_getlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
/*
根据level算出L->ci 和 L->base_ci之间的偏差值。见段1
*/
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
/*
这里的ar只是有一个偏移值,具体的还在lua_getlocal里边。见段2
*/
name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
if (name) {
lua_xmove(L1, L, 1);
lua_pushstring(L, name);
lua_pushvalue(L, -2);
return 2;
}
else {
lua_pushnil(L);
return 1;
}
}
/*
段1
*/
CallInfo是要调用的函数信息,数组形式。这里通过level来算出是第几个CallInfo.
其中一个CallInfo里可能有tailcalls(这是什么还不知道,也算是一种函数调用的优化吧),而
tailcalls是计算到level里面的。比如
0x40 L->ci
0x30 CI(5)
0x20 CI(0)
0x10 CI(0)
..
0x00 L->base_ci, 可能base在这
括号表示tailcalls,这时level为7,取得的是0x10的目标CI,返回base_ci到0x10的偏差
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
int status;
CallInfo *ci;
lua_lock(L);
/*
L->ci,顶部CallInfo信息
L->base_ci,底部CallInfo信息
*/
for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
level--;
if (f_isLua(ci)) /* Lua function? */
level -= ci->tailcalls; /* skip lost tail calls */
}
if (level == 0 && ci > L->base_ci) { /* level found? */
status = 1;
/*
算出目标CallInfo的偏差值
*/
ar->i_ci = cast_int(ci - L->base_ci);
}
else if (level < 0) { /* level is of a lost tail call? */
status = 1;
ar->i_ci = 0;
}
else status = 0; /* no such level */
lua_unlock(L);
return status;
}
/*
段2
*/
lua_getlocal函数的调用关系层如下
lua_getlocal (lua_State *L, const lua_Debug *ar, int n)
{
//根据ar里的偏差值,取到目标ci
CallInfo *ci = L->base_ci + ar->i_ci;
findlocal
Proto *fp = getluaproto(ci);
name = luaF_getlocalname(fp, n, currentpc(L, ci))
}
重点是findlocal的封装。
getluaproto返回函数的属性,先对currentpc展开
static int currentpc (lua_State *L, CallInfo *ci) {
if (!isLua(ci)) return -1; /* function is not a Lua function? */
/*
取的不一定是最末尾的ci
*/
if (ci == L->ci)
ci->savedpc = L->savedpc;
/*
pcRel宏扩展如下,算出ci的执行码和函数的执行码偏差值。中间可以看成塞入了其他
的信息,比如全局变量也会对这个差值造成影响
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
*/
return pcRel(ci->savedpc, ci_func(ci)->l.p);
}
来到最后的luaF_getlocalname
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
int i;
/*
locvars表示存放的函数变量,大小为f->sizelocvars
startpc...endpc,表示在这个范围内的为active变量。
*/
for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) {
if (pc < f->locvars[i].endpc) { /* is variable active? */
local_number--;
if (local_number == 0)
return getstr(f->locvars[i].varname);
}
}
return NULL; /* not found */
}
跟调了下l.p->code和startpc,endpc两个值,在parse的时候就被设置好。
startpc,endpc被设置成l.p->code类似的边界范围值,比如标识局部变量等。
而ci->savedpc和l.p->code之间势必还插入了其他的值,所以你会看到luaF_getlocalname中的判断过程