LUA源码分析九:Debug."getlocal"

 

函数:{"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; i<f->sizelocvars && 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中的判断过程

 

 

你可能感兴趣的:(F#,lua,FP)