Lua 数据结构--Closure

 在 lua 中函数是作为第一类值存在的,即它和表、字符串、数值一样可以被变量引用。函数有三种类型 lua 函数 (LUA_TLCL)、轻量级 C 函数 (LUA_TLCF)、C 函数 (LUA_TCCL)。其中 LUA_TLCL 和 LUA_TCCL 属于 GCUnion–需要被回收的类型,被称为 Closure。当 LUA_TCCL 不包含 upvalue 时,直接用 C 函数指针即可,不必构造 Closure 对象, 也就是 LUA_TLCF。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* lua.h */

/* Type for C functions registered with Lua */
typedef int (*lua_CFunction) (lua_State *L);


/* lobject.h */

/* Variant tags for functions */
#define LUA_TLCL  (LUA_TFUNCTION | (0 << 4))  /* Lua closure */
#define LUA_TLCF  (LUA_TFUNCTION | (1 << 4))  /* light C function */
#define LUA_TCCL  (LUA_TFUNCTION | (2 << 4))  /* C closure */

/* Closures */
typedef struct CClosure {
  GCObject *next;
  lu_byte tt;
  lu_byte marked;
  lu_byte nupvalues;  /* nums of upvalue */
  GCObject *gclist;
  lua_CFunction f;
  TValue upvalue[1];  /* list of upvalues */
} CClosure;

typedef struct LClosure {
  GCObject *next;
  lu_byte tt;
  lu_byte marked;
  lu_byte nupvalues;  /* nums of upvalue */
  GCObject *gclist;
  struct Proto *p;
  UpVal *upvals[1];   /* list of upvalues */
} LClosure;

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

  lua 的闭包分成两类:CClosure 是 C 的函数闭包。LClosure 是 Lua 的函数闭包。

LClosure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* lobject.h */

/* Function Prototypes */
typedef struct Proto
{
  GCObject *next;
  lu_byte tt;
  lu_byte marked;
  lu_byte numparams;    /* number of fixed parameters */
  lu_byte is_vararg;    /* 2: declared vararg; 1: uses 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 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 */
  int *lineinfo;        /* map from opcodes to source lines (debug information) */
  LocVar *locvars;      /* information about local variables (debug information) */
  Upvaldesc *upvalues;  /* upvalue information */
  struct LClosure *cache;  /* last-created closure with this prototype */
  TString  *source;     /* used for debug information */
  GCObject *gclist;
} Proto;

/* lfunc.h */

/* Upvalues for Lua closures */
struct UpVal
{
  TValue *v;        /* points to stack or to its own value */
  lu_mem refcount;  /* reference counter */
  union {
    struct {        /* (when open) */
      UpVal *next;  /* linked list */
      int touched;  /* mark to avoid cycles with dead threads */
    } open;
    TValue value;   /* (when closed) the value */
  } u;
};

  LClosure 由 Proto 和 UpVal 组成。Proto 描述了 lua 函数的函数原型,记录了函数原型的字节码、函数引用的常量表、调试信息、参数、栈大小等信息。UpVal 保存了对 upvalue 的引用。它直接用一个 TValue 指针引用一个 upvalue 值变量。当被引用的变量还在数据栈上时,这个指针直接指向栈上的 TValue,那么这个 upvalue 被称为开放的。由于 lua 的数据栈的大小可扩展,当数据栈内存延展时 (realloc),其内存地址会发生变化,这时需要将 upvalue 拷贝到 UpVal.u.value 中保存。

CClosure

  CClosure 由 lua_CFunction 和 TValue 组成。C 函数可以用闭包的方式嵌入 lua,与 LClosure 相比 CClosure 天生就是关闭的。因此,直接使用 TValue 来保存 upvalue。而 lua 与 C 交互的函数原型统一使用 lua_CFunction。当某个函数没有 upvalue 时,则不需要创建闭包直接使用 lua_CFunction。也称为 light C function。

你可能感兴趣的:(Lua)