Lua 5.3 源码分析(二)值 TValue

来源:互联网 发布:骁龙835手机推荐知乎 编辑:程序博客网 时间:2024/06/18 07:28

Lua 5.3 源码分析(二)值 TValue

抽象数据类型(Abstract Data Type)ADT

union Value {    GCObject *gc;    /* collectable objects */    void *p;         /* light userdata */    int b;           /* booleans */    lua_CFunction f; /* light C functions */    lua_Integer i;   /* integer numbers */    lua_Number n;    /* float numbers */};struct lua_TValue {    TValuefields;};#define TValuefields    Value value_; int tt_typedef struct lua_TValue TValue;typedef TValue *StkId;  /* index to stack elements */

其中0-3 bit 表示基本类型; 4-5 bit 表示子类型;第 6 bit 表示是否可GC。这样就可以完整的标记所有的 Lua 类型 。

GET TYPE

这组宏来判断TValue 的具体类型
/* raw type tag of a TValue */
#define rttype(o) ((o)->tt_)

/* tag with no variants (bits 0-3) */#define novariant(x)    ((x) & 0x0F)/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */#define ttype(o)    (rttype(o) & 0x3F)/* type tag of a TValue with no variants (bits 0-3) */#define ttnov(o)    (novariant(rttype(o)))

将这组宏展开就可以对 TValue 类型做判断了:
这里写图片描述

A、B、C 三个地方使用 checktype 宏判断大类型 。(判断 0 - 3 bit 即可)

D 处使用 ( rttype(o) & 0001 1111 )来判断小类型。(判断 4 - 5 bit 即可)

其余地方都使用 cbt 宏来判断可垃圾回收类型。(判断 0 - 6 bit 即可)

比如怎么判断一个 LUA_TNUMBER  是   LUA_TNUMFLT 还是 LUA_TNUMINTdefine LUA_TNUMFLT  (LUA_TNUMBER | (0 << 4))  /*0000 0011 = 0x3 = 3 */define LUA_TNUMINT  (LUA_TNUMBER | (1 << 4))  /* 0001 0011  = 0x13 = 19*//* Variant tags for functions */define LUA_TLCL (LUA_TFUNCTION | (0 << 4))  /* (0110 | 0000 = 0x6 = 6)Lua closure */define LUA_TLCF (LUA_TFUNCTION | (1 << 4))  /* (0110 | 0001 0000 = 0x16 = 22)light C function */define LUA_TCCL (LUA_TFUNCTION | (2 << 4))  /* (0110 | 0010 0000 = 0x26 = 38)C closure *//* Bit mark for collectable types */#define BIT_ISCOLLECTABLE   (1 << 6)/* mark a tag as collectable */#define ctb(t)          ((t) | BIT_ISCOLLECTABLE)#define righttt(obj)        (ttype(obj) == gcvalue(obj)->tt)

针对 GCObject , Lua提供一个判断 TValue 里的 tag type 和GCObject里的tag type是否一致的判断。

GET VALUE

/* Macros to access values */#define ivalue(o)   check_exp(ttisinteger(o), val_(o).i)#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n)#define nvalue(o)   check_exp(ttisnumber(o), \(ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))#define gcvalue(o)  check_exp(iscollectable(o), val_(o).gc)#define pvalue(o)   check_exp(ttislightuserdata(o), val_(o).p)#define tsvalue(o)  check_exp(ttisstring(o), gco2ts(val_(o).gc))#define uvalue(o)   check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))#define clvalue(o)  check_exp(ttisclosure(o), gco2cl(val_(o).gc))#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc))#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc))#define fvalue(o)   check_exp(ttislcf(o), val_(o).f)#define hvalue(o)   check_exp(ttistable(o), gco2t(val_(o).gc))#define bvalue(o)   check_exp(ttisboolean(o), val_(o).b)#define thvalue(o)  check_exp(ttisthread(o), gco2th(val_(o).gc))/* a dead value may get the 'gc' field, but cannot access its contents */#define deadvalue(o)    check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))#define l_isfalse(o)    (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))#define iscollectable(o)    (rttype(o) & BIT_ISCOLLECTABLE)

这组宏 实现了带类型校验的值获取操作, 对于需要GC的类型 利用 下面一组宏,将GCObject 转换后对应的 TString 、TUSERDATA、TFUNCTION、TTABLE、TPROTO、TTHREAD 数据类型。

/*** Union of all collectable objects (only for conversions)*/union GCUnion {  GCObject gc;  /* common header */  struct TString ts;  struct Udata u;  union Closure cl;  struct Table h;  struct Proto p;  struct lua_State th;  /* thread */};#define cast_u(o)   cast(union GCUnion *, (o))/* macros to convert a GCObject into a specific value */#define gco2ts(o)  \    check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))#define gco2u(o)  check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u))#define gco2lcl(o)  check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l))#define gco2ccl(o)  check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))#define gco2cl(o)  \    check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))#define gco2t(o)  check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))#define gco2p(o)  check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))#define gco2th(o)  check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))/* macro to convert a Lua object into a GCObject */#define obj2gco(v) \    check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))/* actual number of total bytes allocated */#define gettotalbytes(g)    ((g)->totalbytes + (g)->GCdebt)

所有的GCObject都有共同的头部,也就是CommonHeader,所以可以把GCObject转为GCUnion之后,再转为具体类型的指针,安全性由check-exp保证。 反之, obj2gco 这个宏 又提供 将具体TString 、TUSERDATA、TFUNCTION、TTABLE、TPROTO、TTHREAD 数据类型转换为 GCObject 的操作

SET VALUE

设置TValue 的值,需要同时设置 Value 和 TAG TYPE。这组宏里面,对GCObject,都要通过obj2gco把具体类型转型后再赋值给val_(io).gc字段。
/* Macros to set values */
#define settt_(o,t) ((o)->tt_=(t))

#define setfltvalue(obj,x) \{ TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }#define setivalue(obj,x) \{ TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }#define setnilvalue(obj) settt_(obj, LUA_TNIL)#define setfvalue(obj,x) \{ TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }#define setpvalue(obj,x) \{ TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }#define setbvalue(obj,x) \{ TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }#define setgcovalue(L,obj,x) \{ TValue *io = (obj); GCObject *i_g=(x); \val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }#define setsvalue(L,obj,x) \{ TValue *io = (obj); TString *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \checkliveness(G(L),io); }#define setuvalue(L,obj,x) \{ TValue *io = (obj); Udata *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \checkliveness(G(L),io); }#define setthvalue(L,obj,x) \{ TValue *io = (obj); lua_State *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \checkliveness(G(L),io); }#define setclLvalue(L,obj,x) \{ TValue *io = (obj); LClosure *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \checkliveness(G(L),io); }#define setclCvalue(L,obj,x) \{ TValue *io = (obj); CClosure *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \checkliveness(G(L),io); }#define sethvalue(L,obj,x) \{ TValue *io = (obj); Table *x_ = (x); \val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \checkliveness(G(L),io); }#define setdeadvalue(obj)   settt_(obj, LUA_TDEADKEY)#define setobj(L,obj1,obj2) \{ TValue *io1=(obj1); *io1 = *(obj2); \(void)L; checkliveness(G(L),io1); }/* ** different types of assignments, according to destination *//* from stack to (same) stack */#define setobjs2s   setobj/* to stack (not from same stack) */#define setobj2s    setobj#define setsvalue2s setsvalue#define sethvalue2s sethvalue#define setptvalue2s    setptvalue/* from table to same table */#define setobjt2t   setobj/* to table */#define setobj2t    setobj/* to new object */#define setobj2n    setobj#define setsvalue2n setsvalue