void luaV_settable (lua_State *L, TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ /* oldval is nil=> look for newindex, oldval is not nil => look for usedindex */ if (!((ttisnil(oldval) && ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) != NULL)) || ((!ttisnil(oldval)) && ((tm = fasttm(L, h->metatable, TM_USEDINDEX)) != NULL)))) { setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); }
static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); if (tm2 == NULL) return NULL; /* no metamethod */ if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ return tm1; return NULL; }
/* ** Main operation for equality of Lua values; return 't1 == t2'. ** L == NULL means raw equality (no metamethods) */ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; if (ttype(t1) != ttype(t2)) { /* not the same variant? */ #ifndef _KERNEL if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) return 0; /* only numbers can be equal with different variants */ else { /* two numbers with different variants */ lua_Integer i1, i2; /* compare them as integers */ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); } #else /* _KERNEL */ return 0; /* numbers have only the integer variant */ #endif /* _KERNEL */ } /* values have same type and same variant */ switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); #ifndef _KERNEL case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); #endif /* _KERNEL */ case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) /* no TM? */ return 0; /* objects are different */ luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); const TValue *res = ttistable(t) ? luaH_get((Table*)h, key) : luaH_get_ro(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { callTMres(L, val, tm, t, key); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; } luaG_runerror(L, "loop in gettable"); }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */ if ((oldval && !ttisnil(oldval)) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */ if(oldval) { setobj2t(L, oldval, val); luaC_barriert(L, (Table*)h, val); } return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); }
/* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); size_t deadmem = 0; GCObject **p = &g->mainthread->next; GCObject *curr; while ((curr = *p) != NULL) { if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; /* link `curr' at the end of `tmudata' list */ if (g->tmudata == NULL) /* list is empty? */ g->tmudata = curr->gch.next = curr; /* creates a circular list */ else { curr->gch.next = g->tmudata->gch.next; g->tmudata->gch.next = curr; g->tmudata = curr; } } } return deadmem; }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) /* `t' is a table? */ { Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) /* or no TM? */ { setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }
static void GCTM (lua_State *L) { global_State *g = G(L); GCObject *o = g->tmudata->gch.next; /* get first element */ Udata *udata = rawgco2u(o); const TValue *tm; /* remove udata from `tmudata' */ if (o == g->tmudata) /* last element? */ g->tmudata = NULL; else g->tmudata->gch.next = udata->uv.next; udata->uv.next = g->mainthread->next; /* return it to `root' list */ g->mainthread->next = o; makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ } }
/* ** Main operation 'ra' = #rb'. */ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ setivalue(ra, luaH_getn(h)); /* else primitive len */ return; } case LUA_TSHRSTR: { setivalue(ra, tsvalue(rb)->shrlen); return; } case LUA_TLNGSTR: { setivalue(ra, tsvalue(rb)->u.lnglen); return; } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisnil(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } } luaT_callTM(L, tm, rb, rb, ra, 1); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); TValue *oldval = cast(TValue *, luaH_get(h, key)); /* if previous value is not nil, there must be a previous entry in the table; a metamethod has no relevance */ if (!ttisnil(oldval) || /* previous value is nil; must check the metamethod */ ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1)))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, oldval, val); /* assign new value to that entry */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ }
/* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L) { size_t deadmem = 0; GCObject **p = &G(L)->rootudata; GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ GCObject **lastcollected = &collected; while ((curr = *p) != NULL) { lua_assert(curr->gch.tt == LUA_TUSERDATA); if (ismarked(curr) || isfinalized(gcotou(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { markfinalized(gcotou(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gcotou(curr)->uv.len); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; } } /* insert collected udata with gc event into `tmudata' list */ *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; return deadmem; }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; } luaG_runerror(L, "loop in settable"); }
/* ** Finish the table access 'val = t[key]'. ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to ** t[k] entry (which must be nil). */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ const TValue *tm; /* metamethod */ for (loop = 0; loop < MAXTAGLOOP; loop++) { if (slot == NULL) { /* 't' is not a table? */ lua_assert(!ttistable(t)); tm = luaT_gettmbyobj(L, t, TM_INDEX); if (ttisnil(tm)) luaG_typeerror(L, t, "index"); /* no metamethod */ /* else will try the metamethod */ } else { /* 't' is a table */ lua_assert(ttisnil(slot)); tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ if (tm == NULL) { /* no metamethod? */ setnilvalue(val); /* result is nil */ return; } /* else will try the metamethod */ } if (ttisfunction(tm)) { /* is metamethod a function? */ luaT_callTM(L, tm, t, key, val, 1); /* call it */ return; } t = tm; /* else try to access 'tm[key]' */ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ setobj2s(L, val, slot); /* done */ return; } /* else repeat (tail call 'luaV_finishget') */ } luaG_runerror(L, "'__index' chain too long; possible loop"); }
/* * 获取哈希表 * L 虚拟机状态 * t 哈希表的指针 * key 哈希表的键 * val 哈希表的值在栈中的索引 */ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* 遍历 */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; /* 如果t是哈希表类型 */ if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); /* 获取哈希表值 */ /* 从键中取出值 */ const TValue *res = luaH_get(h, key); /* do a primitive get */ /* 如果不是空值或者其表的元运算为空 */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ /* 设置哈希值到指定的栈索引位置 */ setobj2s(L, val, res); return; } /* else will try the tag method */ } /* 如果t不是哈希表则判断其元运算是否为空值 */ else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* 如果元运算是函数则进行调用 */ if (ttisfunction(tm)) { callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat with 'tm' */ } luaG_runerror(L, "loop in gettable"); }
static void do1gcTM (lua_State *L, Udata *udata) { const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { setobj2s(L->top, tm); setuvalue(L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); } }
static const TObject *luaV_index (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); if (tm == NULL) return &luaO_nilobject; /* no TM */ if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } else return luaV_gettable(L, tm, key, loop); }
void GCTM (lua_State *L) { #else static void GCTM (lua_State *L) { #endif /* LUA_REFCOUNT */ global_State *g = G(L); GCObject *o = g->tmudata->gch.next; /* get first element */ Udata *udata = rawgco2u(o); const TValue *tm; /* remove udata from `tmudata' */ if (o == g->tmudata) /* last element? */ g->tmudata = NULL; else g->tmudata->gch.next = udata->uv.next; #if LUA_REFCOUNT udata->uv.prev = (GCObject*)&G(L)->mainthread->next; #endif /* LUA_REFCOUNT */ udata->uv.next = g->mainthread->next; /* return it to `root' list */ #if LUA_REFCOUNT if (udata->uv.next) udata->uv.next->uv.prev = obj2gco(udata); #endif /* LUA_REFCOUNT */ g->mainthread->next = o; makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ #if LUA_REFCOUNT /* We could be in the middle of a stack set, so call the __gc metamethod on one stack level past the current one. */ L->top++; /* we're freeing this object, but fake ref count it, because GCTM actually uses it */ udata->uv.ref++; L->top += 2; setobj2s(L, L->top - 2, tm); setuvalue(L, L->top - 1, udata); luaD_call(L, L->top - 2, 0); udata->uv.ref--; L->top--; setnilvalue2n(L, L->top - 1); #else setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); #endif /* LUA_REFCOUNT */ L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ } }
static void freeobj (lua_State *L, GCObject *o) { global_State *g = G(L); lua_assert(is_robj(o)); switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { const Udata *udata = rawgco2u(o); const TValue *tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ } luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); } }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { TValue tmp; int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); #if LUA_REFCOUNT if (ttisnil(val)) { Node* keyNode = luaH_getkey(h, key); if (keyNode) { luaH_removekey(L, h, keyNode); } } #endif /* LUA_REFCOUNT */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); #if LUA_REFCOUNT { TValue *newval; if (ttistable(t)) { newval = luaH_set(L, hvalue(t), key); if (ttisnil(newval)) { Node* keyNode = luaH_getkey(hvalue(t), key); if (keyNode) luaH_removekey(L, hvalue(t), keyNode); } } } #endif /* LUA_REFCOUNT */ return; } setobj(L, &tmp, tm); t = &tmp; /* else repeat with copy of `tm' */ } luaG_runerror(L, "loop in settable"); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *oldval) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (oldval != NULL) { Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(oldval)); /* must check the metamethod */ if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, oldval), val); invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, oldval, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "settable chain too long; possible loop"); }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; setnilvalue(L->top); L->top++; fixedstack(L); for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */ if ((oldval && !ttisnil(oldval)) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */ if(oldval) { L->top--; unfixedstack(L); setobj2t(L, oldval, val); ((Table *)h)->flags = 0; luaC_barriert(L, (Table*)h, val); } return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { L->top--; unfixedstack(L); callTM(L, tm, t, key, val); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; setobj2s(L, L->top-1, t); /* need to protect value from EGC. */ } luaG_runerror(L, "loop in settable"); }
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ return; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); return; } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisnil(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } } callTMres(L, ra, tm, rb, luaO_nilobject); }
/* ** Finish a table assignment 't[key] = val'. ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' ** would have done the job.) */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; /* '__newindex' metamethod */ if (slot != NULL) { /* is 't' a table? */ Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(slot)); /* old value must be nil */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ if (slot == luaO_nilobject) /* no previous entry? */ slot = luaH_newkey(L, h, key); /* create one */ /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, slot), val); /* set its new value */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, slot, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "'__newindex' chain too long; possible loop"); }
/* ** Main function for table access (invoking metamethods if needed). ** Compute 'val = t[key]' */ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); /* result is the raw get */ return; } /* else will try metamethod */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat access over 'tm' */ } luaG_runerror(L, "gettable chain too long; possible loop"); }
/* ** Receives table at `t', key at `key' and value at `val'. */ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { const TObject *tm; int loop = 0; do { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(oldval, val); /* write barrier */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } while (++loop <= MAXTAGLOOP); luaG_runerror(L, "loop in settable"); }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm = 0; /* LUA-VEC -- compiler gives a warning of uninitialized value on this so we set it to 0 */ if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisvec(t)) { /* LUA-VEC -- vec[idx] operator */ /* issue: "index" may not be the correct arg for luaG_typeerror in here */ if (ttisnumber(key) && /* acessing vec by a number? */ (nvalue(key) >= 1 && nvalue(key) <= 4)) { /* index is between 1-4? */ TValue res; setnvalue(&res, vecvalue(t)[(int)nvalue(key)-1]); setobj2s(L, val, &res); return; } else if (ttisstring(key)) { /* acessing vec by a string? */ if (tsvalue(key)->len == 1) { /* accessing by a single component, such as vec.x */ TValue res; switch (*getstr(tsvalue(key))) { case 'x': setnvalue(&res, vecvalue(t)[0]); break; case 'y': setnvalue(&res, vecvalue(t)[1]); break; case 'z': setnvalue(&res, vecvalue(t)[2]); break; case 'w': setnvalue(&res, vecvalue(t)[3]); break; default: luaG_typeerror(L, t, "index"); } setobj2s(L, val, &res); return; } else if (tsvalue(key)->len <= 4) { /* accessing by swizzling, such as vec.xy, vec.xxyz etc. */ TValue res; float v[4] = {0.0f,0.0f,0.0f,0.0f}; int i; for (i = 0; i < (int)tsvalue(key)->len; ++i) { switch (getstr(tsvalue(key))[i]) { case 'x': v[i] = vecvalue(t)[0]; break; case 'y': v[i] = vecvalue(t)[1]; break; case 'z': v[i] = vecvalue(t)[2]; break; case 'w': v[i] = vecvalue(t)[3]; break; default: luaG_typeerror(L, t, "index"); } } setvecvalue(&res, v[0], v[1], v[2], v[3]); setobj2s(L, val, &res); return; } } luaG_typeerror(L, t, "index"); } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }
static void marktmu (GCState *st) { GCObject *u; #if LUA_REFCOUNT for (u = st->g->tmudata_head.next; u != (GCObject*)&st->g->tmudata_tail; u = u->gch.next) { #else !LUA_REFCOUNT for (u = st->g->tmudata; u; u = u->gch.next) { #endif LUA_REFCOUNT unmark(u); /* may be marked, if left from previous GC */ reallymarkobject(st, u); } } /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L) { size_t deadmem = 0; #if LUA_REFCOUNT GCObject **p = &G(L)->rootudata_head.next; #else !LUA_REFCOUNT GCObject **p = &G(L)->rootudata; #endif LUA_REFCOUNT GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ #if !LUA_REFCOUNT GCObject **lastcollected = &collected; while ((curr = *p) != NULL) { lua_assert(curr->gch.tt == LUA_TUSERDATA); #else LUA_REFCOUNT while ((curr = *p) != (GCObject*)&G(L)->rootudata_tail) { #endif LUA_REFCOUNT if (ismarked(curr) || isfinalized(gcotou(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { markfinalized(gcotou(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gcotou(curr)->uv.len); *p = curr->gch.next; #if LUA_REFCOUNT Unlink(curr); curr->gch.next = (GCObject*)&G(L)->tmudata_tail; /* link `curr' at the end of `collected' list */ curr->gch.prev = G(L)->tmudata_tail.prev; G(L)->tmudata_tail.prev->gch.next = curr; G(L)->tmudata_tail.prev = curr; #else !LUA_REFCOUNT curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; #endif LUA_REFCOUNT } } /* insert collected udata with gc event into `tmudata' list */ #if LUA_REFCOUNT // *lastcollected = G(L)->tmudata_head.next; // G(L)->tmudata_head.next = collected; #else !LUA_REFCOUNT *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; #endif LUA_REFCOUNT return deadmem; } static void removekey (lua_State *L, Node *n) { (void)L; setnilvalue(gval(n)); /* remove corresponding value ... */ if (iscollectable(gkey(n))) setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ }