基础: Lua函数闭包

2022-03-18  本文已影响0人  码上述Andy

函数是所有编程语言的执行单元或者说是行为,函数编译之后由一系列数据组成,比如指令集数组、常量数组、调试信息、本地变量、起始行信息等。lua也一样,函数闭包也是lua中执行单元,lua字节码执行过程中产生的数据结构。通过结构体定义可以看出由函数原型和upvalue数组组成,lua闭包=函数原型+upvalue。而函数原型为编译阶段生成的。分为CClosure和LClosure。
1).具体结构如下:

#define ClosureHeader \
    CommonHeader; lu_byte nupvalues; GCObject *gclist

typedef struct CClosure {
  ClosureHeader;
  lua_CFunction f;
  TValue upvalue[1];  /* list of upvalues */
} CClosure;

typedef struct LClosure {
  ClosureHeader;
  struct Proto *p;
  UpVal *upvals[1];  /* list of upvalues */
} LClosure;

typedef union Closure {
  CClosure c;
  LClosure l;
} Closure;

2).闭包的生成过程:

closure.png

*lauxlib.h/lauxlib.c:luaL_dofile-->luaL_loadfile-->luaL_loadfilex-->lua_load(lapi.c)

*lapi.c:luaD_protectedparser

*ldo.c:luaD_protectedparser-->f_parser-->luaY_parser(文本)/luaU_undump(二进制)

lundump.c:

1.luaU_undump-->luaF_newLclosure:创建一个 closure, 压入栈顶

LClosure *luaF_newLclosure (lua_State *L, int nupvals) {
  GCObject *o = luaC_newobj(L, LUA_VLCL, sizeLclosure(nupvals));
  LClosure *c = gco2lcl(o);
  c->p = NULL;
  c->nupvalues = cast_byte(nupvals);
  while (nupvals--) c->upvals[nupvals] = NULL;
  return c;
}

2.loadFunction:加载Proto(函数原型)

static void loadFunction (LoadState *S, Proto *f, TString *psource) {
  f->source = loadStringN(S, f);
  if (f->source == NULL)  /* no source in dump? */
    f->source = psource;  /* reuse parent's source */
  f->linedefined = loadInt(S);
  f->lastlinedefined = loadInt(S);
  f->numparams = loadByte(S);
  f->is_vararg = loadByte(S);
  f->maxstacksize = loadByte(S);
  loadCode(S, f);
  loadConstants(S, f);
  loadUpvalues(S, f);
  loadProtos(S, f);
  loadDebug(S, f);
}

Proto函数原型,编译生成产物:

typedef struct Proto {
  CommonHeader;
  lu_byte numparams;  /* number of fixed (named) parameters */
  lu_byte is_vararg;
  lu_byte maxstacksize;  /* number of registers needed by this function */
  int sizeupvalues;  /* size of 'upvalues' */
  int sizek;  /* size of 'k' */
  int sizecode;
  int sizelineinfo;
  int sizep;  /* size of 'p' */
  int sizelocvars;
  int sizeabslineinfo;  /* size of 'abslineinfo' */
  int linedefined;  /* debug information  */
  int lastlinedefined;  /* debug information  */
  TValue *k;  /* constants used by the function */
  Instruction *code;  /* opcodes */
  struct Proto **p;  /* functions defined inside the function */
  Upvaldesc *upvalues;  /* upvalue information */
  ls_byte *lineinfo;  /* information about source lines (debug information) */
  AbsLineInfo *abslineinfo;  /* idem */
  LocVar *locvars;  /* information about local variables (debug information) */
  TString  *source;  /* used for debug information */
  GCObject *gclist;
} Proto;

小结:以上为函数闭包的几个核心数据部分。函数原型是编译生成的产物而函数闭包是脚本原型是构建出来的,由数据原型和upvalue组成,内部核心结构:Proto, CallInfo。

上一篇 下一篇

猜你喜欢

热点阅读