Lua 5.3 源碼分析(二)值 TValue

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_TNUMINT
define 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
發佈了198 篇原創文章 · 獲贊 36 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章