| /* |
| ** $Id: lref.c,v 1.10 2000/03/27 20:10:21 roberto Exp roberto $ |
| ** reference mechanism |
| ** See Copyright Notice in lua.h |
| */ |
| |
| |
| #define LUA_REENTRANT |
| |
| #include "lapi.h" |
| #include "lmem.h" |
| #include "lref.h" |
| #include "lstate.h" |
| #include "lua.h" |
| |
| |
| int lua_ref (lua_State *L, int lock) { |
| int ref; |
| luaA_checkCargs(L, 1); |
| if (ttype(L->top-1) == TAG_NIL) |
| ref = LUA_REFNIL; |
| else { |
| if (L->refFree != NONEXT) { /* is there a free place? */ |
| ref = L->refFree; |
| L->refFree = L->refArray[ref].st; |
| } |
| else { /* no more free places */ |
| luaM_growvector(L, L->refArray, L->refSize, 1, struct Ref, refEM, MAX_INT); |
| ref = L->refSize++; |
| } |
| L->refArray[ref].o = *(L->top-1); |
| L->refArray[ref].st = lock ? LOCK : HOLD; |
| } |
| L->top--; |
| return ref; |
| } |
| |
| |
| void lua_unref (lua_State *L, int ref) { |
| if (ref >= 0) { |
| if (ref >= L->refSize || L->refArray[ref].st >= 0) |
| lua_error(L, "Lua API error - " |
| "invalid argument for function `lua_unref'"); |
| L->refArray[ref].st = L->refFree; |
| L->refFree = ref; |
| } |
| } |
| |
| |
| lua_Object lua_getref (lua_State *L, int ref) { |
| if (ref == LUA_REFNIL) |
| return luaA_putluaObject(L, &luaO_nilobject); |
| else if (0 <= ref && ref < L->refSize && |
| (L->refArray[ref].st == LOCK || L->refArray[ref].st == HOLD)) |
| return luaA_putluaObject(L, &L->refArray[ref].o); |
| else |
| return LUA_NOOBJECT; |
| } |
| |
| |
| void lua_beginblock (lua_State *L) { |
| luaM_growvector(L, L->Cblocks, L->numCblocks, 1, struct C_Lua_Stack, |
| "too many nested blocks", L->stacksize); |
| L->Cblocks[L->numCblocks] = L->Cstack; |
| L->numCblocks++; |
| } |
| |
| |
| void lua_endblock (lua_State *L) { |
| if (L->numCblocks <= 0) |
| lua_error(L, "Lua API error - no block to end"); |
| --L->numCblocks; |
| L->Cstack = L->Cblocks[L->numCblocks]; |
| L->top = L->Cstack.base; |
| } |
| |
| |
| |
| |
| |
| |
| static int ismarked (const TObject *o) { |
| /* valid only for locked objects */ |
| switch (o->ttype) { |
| case TAG_STRING: case TAG_USERDATA: |
| return o->value.ts->marked; |
| case TAG_TABLE: |
| return o->value.a->marked; |
| case TAG_LCLOSURE: case TAG_CCLOSURE: |
| return o->value.cl->marked; |
| default: /* number */ |
| return 1; |
| } |
| } |
| |
| |
| /* for internal debugging only; check if a link of free refs is valid */ |
| #define VALIDLINK(L, st,n) (NONEXT <= (st) && (st) < (n)) |
| |
| void luaR_invalidaterefs (lua_State *L) { |
| int n = L->refSize; |
| int i; |
| for (i=0; i<n; i++) { |
| struct Ref *r = &L->refArray[i]; |
| if (r->st == HOLD && !ismarked(&r->o)) |
| r->st = COLLECTED; |
| LUA_ASSERT(L, (r->st == LOCK && ismarked(&r->o)) || |
| r->st == COLLECTED || |
| r->st == NONEXT || |
| (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)), |
| "inconsistent ref table"); |
| } |
| LUA_ASSERT(L, VALIDLINK(L, L->refFree, n), "inconsistent ref table"); |
| } |
| |