From: Felix Fietkau Date: Sat, 24 Oct 2009 22:19:13 +0000 (+0000) Subject: lua: add reference counting for strings - this will need A LOT of testing, but it... X-Git-Tag: reboot~22097 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=8f9821461723848e35487b70711e83bff1eb1dc4;p=openwrt%2Fstaging%2Fpepe2k.git lua: add reference counting for strings - this will need A LOT of testing, but it should finally fix the excessive memory usage problems triggered by luci SVN-Revision: 18136 --- diff --git a/package/lua/patches/040-memory-limits.patch b/package/lua/patches/040-memory-limits.patch deleted file mode 100644 index bc6526b3f7..0000000000 --- a/package/lua/patches/040-memory-limits.patch +++ /dev/null @@ -1,289 +0,0 @@ ---- a/src/lapi.c -+++ b/src/lapi.c -@@ -716,14 +716,14 @@ - - LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { - StkId t; -- TValue key; - lua_lock(L); - api_checknelems(L, 1); - t = index2adr(L, idx); - api_checkvalidindex(L, t); -- setsvalue(L, &key, luaS_new(L, k)); -- luaV_settable(L, t, &key, L->top - 1); -- L->top--; /* pop value */ -+ setsvalue2s(L, L->top, luaS_new(L, k)); -+ api_incr_top(L); -+ luaV_settable(L, t, L->top - 1, L->top - 2); -+ L->top -= 2; /* pop key and value */ - lua_unlock(L); - } - -@@ -971,7 +971,12 @@ - break; - } - case LUA_GCCOLLECT: { -- luaC_fullgc(L); -+ lu_mem old_thres = g->GCthreshold; -+ if(g->GCthreshold != MAX_LUMEM) { -+ g->GCthreshold = MAX_LUMEM; -+ luaC_fullgc(L); -+ g->GCthreshold = old_thres; -+ } - break; - } - case LUA_GCCOUNT: { ---- a/src/ldo.c -+++ b/src/ldo.c -@@ -494,6 +494,7 @@ - struct SParser *p = cast(struct SParser *, ud); - int c = luaZ_lookahead(p->z); - luaC_checkGC(L); -+ lua_gc(L, LUA_GCSTOP, 0); /* stop collector during parsing */ - tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, - &p->buff, p->name); - cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); -@@ -502,6 +503,7 @@ - cl->l.upvals[i] = luaF_newupval(L); - setclvalue(L, L->top, cl); - incr_top(L); -+ lua_gc(L, LUA_GCRESTART, 0); - } - - ---- a/src/lgc.c -+++ b/src/lgc.c -@@ -437,7 +437,10 @@ - /* check size of buffer */ - if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&g->buff) / 2; -- luaZ_resizebuffer(L, &g->buff, newsize); -+ /* make sure newsize is larger then the buffer's in use size. */ -+ newsize = (luaZ_bufflen(&g->buff) > newsize) ? luaZ_bufflen(&g->buff) : newsize; -+ if(newsize < luaZ_sizebuffer(&g->buff)) -+ luaZ_resizebuffer(L, &g->buff, newsize); - } - } - ---- a/src/lstate.c -+++ b/src/lstate.c -@@ -118,7 +118,6 @@ - - lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); -- luaC_link(L, obj2gco(L1), LUA_TTHREAD); - preinit_state(L1, G(L)); - stack_init(L1, L); /* init stack */ - setobj2n(L, gt(L1), gt(L)); /* share table of globals */ -@@ -126,6 +125,7 @@ - L1->basehookcount = L->basehookcount; - L1->hook = L->hook; - resethookcount(L1); -+ luaC_link(L, obj2gco(L1), LUA_TTHREAD); - lua_assert(iswhite(obj2gco(L1))); - return L1; - } ---- a/src/lstring.c -+++ b/src/lstring.c -@@ -53,6 +53,9 @@ - stringtable *tb; - if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) - luaM_toobig(L); -+ tb = &G(L)->strt; -+ if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) -+ luaS_resize(L, tb->size*2); /* too crowded */ - ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); - ts->tsv.len = l; - ts->tsv.hash = h; -@@ -61,13 +64,10 @@ - ts->tsv.reserved = 0; - memcpy(ts+1, str, l*sizeof(char)); - ((char *)(ts+1))[l] = '\0'; /* ending 0 */ -- tb = &G(L)->strt; - h = lmod(h, tb->size); - ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = obj2gco(ts); - tb->nuse++; -- if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) -- luaS_resize(L, tb->size*2); /* too crowded */ - return ts; - } - ---- a/src/ltable.c -+++ b/src/ltable.c -@@ -371,7 +371,6 @@ - - Table *luaH_new (lua_State *L, int narray, int nhash) { - Table *t = luaM_new(L, Table); -- luaC_link(L, obj2gco(t), LUA_TTABLE); - t->metatable = NULL; - t->flags = cast_byte(~0); - /* temporary values (kept only if some malloc fails) */ -@@ -381,6 +380,7 @@ - t->node = cast(Node *, dummynode); - setarrayvector(L, t, narray); - setnodevector(L, t, nhash); -+ luaC_link(L, obj2gco(t), LUA_TTABLE); - return t; - } - ---- a/src/lvm.c -+++ b/src/lvm.c -@@ -375,6 +375,7 @@ - if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); - tl += l; - } -+ G(L)->buff.n = tl; - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - for (i=n; i>0; i--) { /* concat all strings */ -@@ -383,6 +384,7 @@ - tl += l; - } - setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); -+ luaZ_resetbuffer(&G(L)->buff); - } - total -= n-1; /* got `n' strings to create 1 new */ - last -= n-1; ---- a/src/lua.c -+++ b/src/lua.c -@@ -19,6 +19,94 @@ - #include "llimits.h" - - -+typedef struct { -+ char *name; -+ lua_State *L; -+ size_t memused; -+ size_t peak_memused; -+ size_t gc_memused; -+ size_t max_memused; -+ int collecting; -+} script_info_t; -+ -+ -+static void *script_alloc(void *ud, void *ptr, size_t osize, size_t nsize) -+{ -+ script_info_t *info=(script_info_t *)ud; -+ size_t old_size = info->memused; -+ -+ info->memused -= osize; -+ if (nsize == 0) { -+ free(ptr); -+ return NULL; -+ } -+ info->memused += nsize; -+ if(info->max_memused > 0 && nsize > osize && -+ (info->memused >= info->max_memused || info->memused >= info->gc_memused)) { -+#ifdef LOW_MEM_DEBUG -+ printf("LOW MEM: 1 osize=%zd, nsize=%zd, used=%zu, peak=%zu, need=%zd\n", osize, nsize, -+ info->memused, info->peak_memused, (info->memused - info->max_memused)); -+#endif -+ info->memused = old_size; -+ /* don't allow a recursive garbage collection call. */ -+ if(info->collecting != 0) { -+ return NULL; -+ } -+ info->collecting = 1; -+ /* try to free memory by collecting garbage. */ -+ lua_gc(info->L, LUA_GCCOLLECT, 0); -+ info->collecting = 0; -+#ifdef LOW_MEM_DEBUG -+ printf("LOW MEM: 2 used=%zu, peak=%zu\n", info->memused, info->peak_memused); -+#endif -+ /* check memory usage again. */ -+ old_size = info->memused; -+ info->memused -= osize; -+ info->memused += nsize; -+ if(info->memused >= info->max_memused) { -+ info->memused = old_size; -+#ifdef LOW_MEM_DEBUG -+ printf("OUT OF MEMORY: memused=%zd, osize=%zd, nsize=%zd\n", info->memused, osize, nsize); -+#endif -+ return NULL; -+ } -+ } -+ if(info->memused > info->peak_memused) info->peak_memused = info->memused; -+ return realloc(ptr, nsize); -+} -+ -+static int set_memory_limit(lua_State *L) -+{ -+ int hardlimit = luaL_checknumber(L, 1); -+ int softlimit = luaL_optnumber(L, 2, 0); -+ -+ script_info_t *info; -+ lua_getallocf(L, (void *)(&info)); -+ -+ if( hardlimit >= 0 ) -+ { -+ if( softlimit <= 0 ) -+ softlimit = (int)((float)hardlimit * 0.75); -+ -+ info->max_memused = hardlimit; -+ info->gc_memused = softlimit; -+ } -+ -+ lua_pushnumber(L, hardlimit); -+ lua_pushnumber(L, softlimit); -+ return 2; -+} -+ -+static int get_memory_limit(lua_State *L) -+{ -+ script_info_t *info; -+ lua_getallocf(L, (void *)(&info)); -+ lua_pushnumber(L, info->max_memused); -+ lua_pushnumber(L, info->gc_memused); -+ return 2; -+} -+ -+ - static lua_State *globalL = NULL; - - static const char *progname = LUA_PROGNAME; -@@ -377,11 +465,28 @@ - int main (int argc, char **argv) { - int status; - struct Smain s; -- lua_State *L = lua_open(); /* create state */ -+ script_info_t *info; -+ -+ info = (script_info_t *)calloc(1, sizeof(script_info_t)); -+ info->max_memused = 0; -+ info->collecting = 0; -+ info->name = argv[0]; -+ info->memused = 0; -+ info->peak_memused = 0; -+ -+ lua_State *L = lua_newstate(script_alloc, info); -+ - if (L == NULL) { - l_message(argv[0], "cannot create state: not enough memory"); - return EXIT_FAILURE; - } -+ -+ info->L = L; -+ -+ luaL_openlibs(L); -+ lua_register(L, "set_memory_limit", set_memory_limit); -+ lua_register(L, "get_memory_limit", get_memory_limit); -+ - /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers. - */ - #ifdef LNUM_INT16 -@@ -396,6 +501,14 @@ - status = lua_cpcall(L, &pmain, &s); - report(L, status); - lua_close(L); -+ -+#ifdef LOW_MEM_DEBUG -+ printf("%s: memused=%zd, peak_memused=%zd\n", info->name, -+ info->memused, info->peak_memused); -+#endif -+ -+ free(info); -+ - return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; - } - diff --git a/package/lua/patches/300-opcode_performance.patch b/package/lua/patches/300-opcode_performance.patch index fb1f9a1ea7..e870a25f42 100644 --- a/package/lua/patches/300-opcode_performance.patch +++ b/package/lua/patches/300-opcode_performance.patch @@ -10,7 +10,7 @@ /* * If 'obj' is a string, it is tried to be interpreted as a number. -@@ -564,12 +567,63 @@ +@@ -562,12 +565,63 @@ static inline int arith_mode( const TVal ARITH_OP1_END #endif @@ -74,7 +74,7 @@ reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; -@@ -594,33 +648,33 @@ +@@ -592,33 +646,33 @@ void luaV_execute (lua_State *L, int nex lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); @@ -115,7 +115,7 @@ TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); -@@ -628,88 +682,88 @@ +@@ -626,88 +680,88 @@ void luaV_execute (lua_State *L, int nex Protect(luaV_gettable(L, &g, rb, ra)); continue; } @@ -219,7 +219,7 @@ const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { -@@ -729,18 +783,18 @@ +@@ -727,18 +781,18 @@ void luaV_execute (lua_State *L, int nex } continue; } @@ -241,7 +241,7 @@ TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( -@@ -750,7 +804,7 @@ +@@ -748,7 +802,7 @@ void luaV_execute (lua_State *L, int nex pc++; continue; } @@ -250,7 +250,7 @@ Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); -@@ -758,7 +812,7 @@ +@@ -756,7 +810,7 @@ void luaV_execute (lua_State *L, int nex pc++; continue; } @@ -259,7 +259,7 @@ Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); -@@ -766,13 +820,13 @@ +@@ -764,13 +818,13 @@ void luaV_execute (lua_State *L, int nex pc++; continue; } @@ -275,7 +275,7 @@ TValue *rb = RB(i); if (l_isfalse(rb) != GETARG_C(i)) { setobjs2s(L, ra, rb); -@@ -781,7 +835,7 @@ +@@ -779,7 +833,7 @@ void luaV_execute (lua_State *L, int nex pc++; continue; } @@ -284,7 +284,7 @@ int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ -@@ -802,7 +856,7 @@ +@@ -800,7 +854,7 @@ void luaV_execute (lua_State *L, int nex } } } @@ -293,7 +293,7 @@ int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ L->savedpc = pc; -@@ -834,7 +888,7 @@ +@@ -832,7 +886,7 @@ void luaV_execute (lua_State *L, int nex } } } @@ -302,7 +302,7 @@ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); -@@ -849,7 +903,7 @@ +@@ -847,7 +901,7 @@ void luaV_execute (lua_State *L, int nex goto reentry; } } @@ -311,7 +311,7 @@ /* If start,step and limit are all integers, we don't need to check * against overflow in the looping. */ -@@ -877,7 +931,7 @@ +@@ -875,7 +929,7 @@ void luaV_execute (lua_State *L, int nex } continue; } @@ -320,7 +320,7 @@ const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; -@@ -900,7 +954,7 @@ +@@ -898,7 +952,7 @@ void luaV_execute (lua_State *L, int nex dojump(L, pc, GETARG_sBx(i)); continue; } @@ -329,7 +329,7 @@ StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); -@@ -916,7 +970,7 @@ +@@ -914,7 +968,7 @@ void luaV_execute (lua_State *L, int nex pc++; continue; } @@ -338,7 +338,7 @@ int n = GETARG_B(i); int c = GETARG_C(i); int last; -@@ -938,11 +992,11 @@ +@@ -936,11 +990,11 @@ void luaV_execute (lua_State *L, int nex } continue; } @@ -352,7 +352,7 @@ Proto *p; Closure *ncl; int nup, j; -@@ -962,7 +1016,7 @@ +@@ -960,7 +1014,7 @@ void luaV_execute (lua_State *L, int nex Protect(luaC_checkGC(L)); continue; } diff --git a/package/lua/patches/600-refcounting.patch b/package/lua/patches/600-refcounting.patch new file mode 100644 index 0000000000..10fd53375d --- /dev/null +++ b/package/lua/patches/600-refcounting.patch @@ -0,0 +1,1096 @@ +--- a/src/lapi.c ++++ b/src/lapi.c +@@ -27,8 +27,8 @@ + #include "ltable.h" + #include "ltm.h" + #include "lundump.h" +-#include "lvm.h" + #include "lnum.h" ++#include "lvm.h" + + + const char lua_ident[] = +@@ -117,6 +117,7 @@ LUA_API void lua_xmove (lua_State *from, + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, to->top++, from->top + i); ++ setnilvalue(from, from->top + i); + } + lua_unlock(to); + } +@@ -166,12 +167,16 @@ LUA_API void lua_settop (lua_State *L, i + if (idx >= 0) { + api_check(L, idx <= L->stack_last - L->base); + while (L->top < L->base + idx) +- setnilvalue(L->top++); ++ setnilvalue(L, L->top++); + L->top = L->base + idx; ++ setnilvalue(L, L->top); + } + else { ++ int i; + api_check(L, -(idx+1) <= (L->top - L->base)); + L->top += idx+1; /* `subtract' index (index is negative) */ ++ for (i = 0; i < -(idx+1); i++) ++ setnilvalue(L, L->top + i); + } + lua_unlock(L); + } +@@ -184,6 +189,7 @@ LUA_API void lua_remove (lua_State *L, i + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); + L->top--; ++ setnilvalue(L, L->top); + lua_unlock(L); + } + +@@ -196,6 +202,7 @@ LUA_API void lua_insert (lua_State *L, i + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); ++ setnilvalue(L, L->top); + lua_unlock(L); + } + +@@ -221,6 +228,7 @@ LUA_API void lua_replace (lua_State *L, + luaC_barrier(L, curr_func(L), L->top - 1); + } + L->top--; ++ setnilvalue(L, L->top); + lua_unlock(L); + } + +@@ -259,14 +267,14 @@ LUA_API int lua_iscfunction (lua_State * + + + LUA_API int lua_isnumber (lua_State *L, int idx) { +- TValue n; ++ TValue n = tvinit(); + const TValue *o = index2adr(L, idx); + return tonumber(o, &n); + } + + + LUA_API int lua_isinteger (lua_State *L, int idx) { +- TValue tmp; ++ TValue tmp = tvinit(); + lua_Integer dum; + const TValue *o = index2adr(L, idx); + return tonumber(o,&tmp) && (ttisint(o) || tt_integer_valued(o,&dum)); +@@ -319,7 +327,7 @@ LUA_API int lua_lessthan (lua_State *L, + + + LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { +- TValue n; ++ TValue n = tvinit(); + const TValue *o = index2adr(L, idx); + if (tonumber(o, &n)) { + #ifdef LNUM_COMPLEX +@@ -333,7 +341,7 @@ LUA_API lua_Number lua_tonumber (lua_Sta + + + LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { +- TValue n; ++ TValue n = tvinit(); + /* Lua 5.1 documented behaviour is to return nonzero for non-integer: + * "If the number is not an integer, it is truncated in some non-specified way." + * I would suggest to change this, to return 0 for anything that would +@@ -369,7 +377,7 @@ LUA_API lua_Integer lua_tointeger (lua_S + + #ifdef LNUM_COMPLEX + LUA_API lua_Complex lua_tocomplex (lua_State *L, int idx) { +- TValue tmp; ++ TValue tmp = tvinit(); + const TValue *o = index2adr(L, idx); + if (tonumber(o, &tmp)) + return nvalue_complex(o); +@@ -465,7 +473,7 @@ LUA_API const void *lua_topointer (lua_S + + LUA_API void lua_pushnil (lua_State *L) { + lua_lock(L); +- setnilvalue(L->top); ++ setnilvalue(L, L->top); + api_incr_top(L); + lua_unlock(L); + } +@@ -548,8 +556,10 @@ LUA_API void lua_pushcclosure (lua_State + cl = luaF_newCclosure(L, n, getcurrenv(L)); + cl->c.f = fn; + L->top -= n; +- while (n--) ++ while (n--) { + setobj2n(L, &cl->c.upvalue[n], L->top+n); ++ setnilvalue(L, L->top + n); ++ } + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); + api_incr_top(L); +@@ -600,7 +610,7 @@ LUA_API void lua_gettable (lua_State *L, + + LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; +- TValue key; ++ TValue key = tvinit(); + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); +@@ -689,7 +699,7 @@ LUA_API void lua_getfenv (lua_State *L, + setobj2s(L, L->top, gt(thvalue(o))); + break; + default: +- setnilvalue(L->top); ++ setnilvalue(L, L->top); + break; + } + api_incr_top(L); +@@ -710,13 +720,15 @@ LUA_API void lua_settable (lua_State *L, + api_checkvalidindex(L, t); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ ++ setnilvalue(L, L->top); ++ setnilvalue(L, L->top + 1); + lua_unlock(L); + } + + + LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; +- TValue key; ++ TValue key = tvinit(); + lua_lock(L); + api_checknelems(L, 1); + t = index2adr(L, idx); +@@ -724,6 +736,7 @@ LUA_API void lua_setfield (lua_State *L, + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ ++ setnilvalue(L, L->top); + lua_unlock(L); + } + +@@ -737,6 +750,8 @@ LUA_API void lua_rawset (lua_State *L, i + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barriert(L, hvalue(t), L->top-1); + L->top -= 2; ++ setnilvalue(L, L->top); ++ setnilvalue(L, L->top + 1); + lua_unlock(L); + } + +@@ -750,6 +765,7 @@ LUA_API void lua_rawseti (lua_State *L, + setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); + L->top--; ++ setnilvalue(L, L->top); + lua_unlock(L); + } + +@@ -786,6 +802,7 @@ LUA_API int lua_setmetatable (lua_State + } + } + L->top--; ++ setnilvalue(L, L->top); + lua_unlock(L); + return 1; + } +@@ -815,6 +832,7 @@ LUA_API int lua_setfenv (lua_State *L, i + } + if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); + L->top--; ++ setnilvalue(L, L->top); + lua_unlock(L); + return res; + } +@@ -1040,20 +1058,25 @@ LUA_API int lua_next (lua_State *L, int + if (more) { + api_incr_top(L); + } +- else /* no more elements */ ++ else { /* no more elements */ + L->top -= 1; /* remove key */ ++ setnilvalue(L, L->top); ++ } + lua_unlock(L); + return more; + } + + + LUA_API void lua_concat (lua_State *L, int n) { ++ int i; + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaC_checkGC(L); + luaV_concat(L, n, cast_int(L->top - L->base) - 1); + L->top -= (n-1); ++ for (i = 0; i < n - 1; i++) ++ setnilvalue(L, L->top + i); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); +@@ -1139,6 +1162,7 @@ LUA_API const char *lua_setupvalue (lua_ + if (name) { + L->top--; + setobj(L, val, L->top); ++ setnilvalue(L, L->top); + luaC_barrier(L, clvalue(fi), L->top); + } + lua_unlock(L); +@@ -1160,7 +1184,7 @@ LUA_API const char *lua_setupvalue (lua_ + int lua_pushvalue_as_number (lua_State *L, int idx) + { + const TValue *o = index2adr(L, idx); +- TValue tmp; ++ TValue tmp = tvinit(); + lua_Integer i; + if (ttisnumber(o)) { + if ( (!ttisint(o)) && tt_integer_valued(o,&i)) { +--- a/src/lcode.c ++++ b/src/lcode.c +@@ -23,6 +23,7 @@ + #include "lparser.h" + #include "ltable.h" + #include "lnum.h" ++#include "lvm.h" + + + #define hasjumps(e) ((e)->t != (e)->f) +@@ -248,7 +249,7 @@ static int addk (FuncState *fs, TValue * + setivalue(idx, fs->nk); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, + MAXARG_Bx, "constant table overflow"); +- while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); ++ while (oldsize < f->sizek) setnilvalue(L, &f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); + return fs->nk++; +@@ -257,21 +258,24 @@ static int addk (FuncState *fs, TValue * + + + int luaK_stringK (FuncState *fs, TString *s) { +- TValue o; ++ TValue o = tvinit(); + setsvalue(fs->L, &o, s); ++ luaV_unref(fs->L, &o); + return addk(fs, &o, &o); + } + + + int luaK_numberK (FuncState *fs, lua_Number r) { +- TValue o; ++ lua_State *L = fs->L; ++ TValue o = tvinit(); + setnvalue(&o, r); + return addk(fs, &o, &o); + } + + + int luaK_integerK (FuncState *fs, lua_Integer r) { +- TValue o; ++ lua_State *L = fs->L; ++ TValue o = tvinit(); + setivalue(&o, r); + return addk(fs, &o, &o); + } +@@ -279,22 +283,24 @@ int luaK_integerK (FuncState *fs, lua_In + + #ifdef LNUM_COMPLEX + static int luaK_imagK (FuncState *fs, lua_Number r) { +- TValue o; ++ lua_State *L = fs->L; ++ TValue o = tvinit(); + setnvalue_complex(&o, r*I); + return addk(fs, &o, &o); + } + #endif + + static int boolK (FuncState *fs, int b) { +- TValue o; ++ lua_State *L = fs->L; ++ TValue o = tvinit(); + setbvalue(&o, b); + return addk(fs, &o, &o); + } + + + static int nilK (FuncState *fs) { +- TValue k, v; +- setnilvalue(&v); ++ TValue k = tvinit(), v = tvinit(); ++ setnilvalue(fs->L, &v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); + return addk(fs, &k, &v); +--- a/src/ldebug.c ++++ b/src/ldebug.c +@@ -176,7 +176,7 @@ static void info_tailcall (lua_Debug *ar + + static void collectvalidlines (lua_State *L, Closure *f) { + if (f == NULL || f->c.isC) { +- setnilvalue(L->top); ++ setnilvalue(L, L->top); + } + else { + Table *t = luaH_new(L, 0, 0); +@@ -248,7 +248,7 @@ LUA_API int lua_getinfo (lua_State *L, c + } + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f')) { +- if (f == NULL) setnilvalue(L->top); ++ if (f == NULL) setnilvalue(L, L->top); + else setclvalue(L, L->top, f); + incr_top(L); + } +@@ -586,7 +586,7 @@ void luaG_concaterror (lua_State *L, Stk + + + void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { +- TValue temp; ++ TValue temp = tvinit(); + if (luaV_tonumber(p1, &temp) == NULL) + p2 = p1; /* first operand is wrong */ + luaG_typeerror(L, p2, "perform arithmetic on"); +--- a/src/ldo.c ++++ b/src/ldo.c +@@ -211,7 +211,7 @@ static StkId adjust_varargs (lua_State * + Table *htab = NULL; + StkId base, fixed; + for (; actual < nfixargs; ++actual) +- setnilvalue(L->top++); ++ setnilvalue(L, L->top++); + #if defined(LUA_COMPAT_VARARG) + if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ + int nvar = actual - nfixargs; /* number of extra arguments */ +@@ -229,7 +229,6 @@ static StkId adjust_varargs (lua_State * + base = L->top; /* final position of first argument */ + for (i=0; itop++, fixed+i); +- setnilvalue(fixed+i); + } + /* add `arg' parameter */ + if (htab) { +@@ -294,7 +293,7 @@ int luaD_precall (lua_State *L, StkId fu + ci->tailcalls = 0; + ci->nresults = nresults; + for (st = L->top; st < ci->top; st++) +- setnilvalue(st); ++ setnilvalue(L, st); + L->top = ci->top; + if (L->hookmask & LUA_MASKCALL) { + L->savedpc++; /* hooks assume 'pc' is already incremented */ +@@ -354,7 +353,9 @@ int luaD_poscall (lua_State *L, StkId fi + for (i = wanted; i != 0 && firstResult < L->top; i--) + setobjs2s(L, res++, firstResult++); + while (i-- > 0) +- setnilvalue(res++); ++ setnilvalue(L, res++); ++ for (i = (res - L->top); i-- > 0;) ++ setnilvalue(L, L->top + i); + L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ + } +@@ -463,8 +464,12 @@ int luaD_pcall (lua_State *L, Pfunc func + status = luaD_rawrunprotected(L, func, u); + if (status != 0) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); ++ StkId curtop = L->top; ++ int i; + luaF_close(L, oldtop); /* close eventual pending closures */ + luaD_seterrorobj(L, status, oldtop); ++ for (i = (curtop - L->top); i-- > 0;) ++ setnilvalue(L, L->top + i); + L->nCcalls = oldnCcalls; + L->ci = restoreci(L, old_ci); + L->base = L->ci->base; +--- a/src/lfunc.c ++++ b/src/lfunc.c +@@ -17,7 +17,7 @@ + #include "lmem.h" + #include "lobject.h" + #include "lstate.h" +- ++#include "lvm.h" + + + Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { +@@ -45,7 +45,7 @@ UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->u.value; +- setnilvalue(uv->v); ++ setnilvalue(L, uv->v); + return uv; + } + +@@ -69,6 +69,12 @@ UpVal *luaF_findupval (lua_State *L, Stk + uv->marked = luaC_white(g); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ ++ if (uv->next) { ++ uv->prev = uv->next->gch.prev; ++ uv->next->gch.prev = (GCObject *)uv; ++ } else { ++ uv->prev = NULL; ++ } + *pp = obj2gco(uv); + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; +--- a/src/lgc.c ++++ b/src/lgc.c +@@ -21,6 +21,7 @@ + #include "lstring.h" + #include "ltable.h" + #include "ltm.h" ++#include "lvm.h" + + + #define GCSTEPSIZE 1024u +@@ -265,7 +266,7 @@ static void traversestack (global_State + for (o = l->stack; o < l->top; o++) + markvalue(g, o); + for (; o <= lim; o++) +- setnilvalue(o); ++ setnilvalue(l, o); + checkstacksizes(l, lim); + } + +@@ -348,7 +349,7 @@ static int iscleared (const TValue *o, i + /* + ** clear collected entries from weaktables + */ +-static void cleartable (GCObject *l) { ++static void cleartable (lua_State *L, GCObject *l) { + while (l) { + Table *h = gco2h(l); + int i = h->sizearray; +@@ -358,7 +359,7 @@ static void cleartable (GCObject *l) { + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ +- setnilvalue(o); /* remove value */ ++ setnilvalue(L, o); /* remove value */ + } + } + i = sizenode(h); +@@ -366,7 +367,7 @@ static void cleartable (GCObject *l) { + Node *n = gnode(h, i); + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { +- setnilvalue(gval(n)); /* remove value ... */ ++ setnilvalue(L, gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from table */ + } + } +@@ -375,7 +376,7 @@ static void cleartable (GCObject *l) { + } + + +-static void freeobj (lua_State *L, GCObject *o) { ++void luaC_freeobj (lua_State *L, GCObject *o) { + switch (o->gch.tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; +@@ -418,10 +419,14 @@ static GCObject **sweeplist (lua_State * + } + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); ++ if (curr->gch.prev) ++ curr->gch.prev->gch.next = curr->gch.next; ++ if (curr->gch.next) ++ curr->gch.next->gch.prev = (GCObject*)p; + *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ +- freeobj(L, curr); ++ luaC_freeobj(L, curr); + } + } + return p; +@@ -543,7 +548,7 @@ static void atomic (lua_State *L) { + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ + marktmu(g); /* mark `preserved' userdata */ + udsize += propagateall(g); /* remark, to propagate `preserveness' */ +- cleartable(g->weak); /* remove collected objects from weak tables */ ++ cleartable(L, g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = cast_byte(otherwhite(g)); + g->sweepstrgc = 0; +@@ -685,8 +690,11 @@ void luaC_barrierback (lua_State *L, Tab + + void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { + global_State *g = G(L); ++ o->gch.prev = (GCObject*)&g->rootgc; + o->gch.next = g->rootgc; + g->rootgc = o; ++ if (o->gch.next) ++ o->gch.next->gch.prev = o; + o->gch.marked = luaC_white(g); + o->gch.tt = tt; + } +--- a/src/lgc.h ++++ b/src/lgc.h +@@ -105,6 +105,6 @@ LUAI_FUNC void luaC_link (lua_State *L, + LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); + LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); + LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); +- ++LUAI_FUNC void luaC_freeobj (lua_State *L, GCObject *o); + + #endif +--- a/src/lmem.c ++++ b/src/lmem.c +@@ -6,6 +6,7 @@ + + + #include ++#include + + #define lmem_c + #define LUA_CORE +@@ -80,6 +81,8 @@ void *luaM_realloc_ (lua_State *L, void + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); ++ if (nsize > osize) ++ memset((char *)block + osize, 0, nsize - osize); + g->totalbytes = (g->totalbytes - osize) + nsize; + return block; + } +--- a/src/lobject.h ++++ b/src/lobject.h +@@ -44,7 +44,7 @@ typedef union GCObject GCObject; + ** Common Header for all collectable objects (in macro form, to be + ** included in other objects) + */ +-#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked ++#define CommonHeader GCObject *next; GCObject *prev; lu_byte tt; lu_byte marked + + + /* +@@ -83,6 +83,7 @@ typedef struct lua_TValue { + TValuefields; + } TValue; + ++#define tvinit() { .value.b = 0, .tt = 0 } + + /* Macros to test type */ + #define ttisnil(o) (ttype(o) == LUA_TNIL) +@@ -145,15 +146,15 @@ typedef struct lua_TValue { + + + /* Macros to set values */ +-#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) ++#define setnilvalue(L, obj) (luaV_unref(L, (obj))->tt=LUA_TNIL) + + /* Must not have side effects, 'x' may be expression. + */ + #define setivalue(obj,x) \ +- { TValue *i_o=(obj); i_o->value.i=(x); i_o->tt=LUA_TINT; } ++ { TValue *i_o=luaV_unref(L, (obj)); i_o->value.i=(x); i_o->tt=LUA_TINT; } + + # define setnvalue(obj,x) \ +- { TValue *i_o=(obj); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; } ++ { TValue *i_o=luaV_unref(L, (obj)); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; } + + /* Note: Complex always has "inline", both are C99. + */ +@@ -170,45 +171,45 @@ typedef struct lua_TValue { + + + #define setpvalue(obj,x) \ +- { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } ++ { TValue *i_o=luaV_unref(L, (obj)); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + + #define setbvalue(obj,x) \ +- { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } ++ { TValue *i_o=luaV_unref(L, (obj)); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + + #define setsvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ +- i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ ++ { TValue *i_o=(obj); TString *val=(x); luaS_ref(val); luaV_unref(L, obj); \ ++ i_o->value.gc=cast(GCObject *, (val)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } + + #define setuvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ ++ { TValue *i_o=luaV_unref(L, (obj)); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } + + #define setthvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ ++ { TValue *i_o=luaV_unref(L, (obj)); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } + + #define setclvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ ++ { TValue *i_o=luaV_unref(L, (obj)); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } + + #define sethvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ ++ { TValue *i_o=luaV_unref(L, (obj)); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } + + #define setptvalue(L,obj,x) \ +- { TValue *i_o=(obj); \ ++ { TValue *i_o=luaV_unref(L, (obj)); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } + + #define setobj(L,obj1,obj2) \ +- { const TValue *o2=(obj2); TValue *o1=(obj1); \ ++ do { const TValue *o2=luaV_ref((TValue *)(obj2)); TValue *o1=luaV_unref(L, (obj1)); \ + o1->value = o2->value; o1->tt=o2->tt; \ +- checkliveness(G(L),o1); } ++ checkliveness(G(L),o1); } while(0) + + + /* +@@ -253,6 +254,7 @@ typedef union TString { + lu_byte reserved; + unsigned int hash; + size_t len; ++ int refcount; + } tsv; + } TString; + +@@ -409,6 +411,7 @@ typedef struct Table { + #define twoto(x) (1<<(x)) + #define sizenode(t) (twoto((t)->lsizenode)) + ++#include "lstring.h" + + #define luaO_nilobject (&luaO_nilobject_) + +--- a/src/lparser.c ++++ b/src/lparser.c +@@ -24,6 +24,7 @@ + #include "lstate.h" + #include "lstring.h" + #include "ltable.h" ++#include "lvm.h" + + + +@@ -146,7 +147,7 @@ static int registerlocalvar (LexState *l + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, SHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; +- f->locvars[fs->nlocvars].varname = varname; ++ f->locvars[fs->nlocvars].varname = luaS_ref(varname); + luaC_objbarrier(ls->L, f, varname); + return fs->nlocvars++; + } +@@ -194,7 +195,7 @@ static int indexupvalue (FuncState *fs, + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, + TString *, MAX_INT, ""); + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; +- f->upvalues[f->nups] = name; ++ f->upvalues[f->nups] = luaS_ref(name); + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast_byte(v->k); +@@ -341,7 +342,7 @@ static void open_func (LexState *ls, Fun + fs->nlocvars = 0; + fs->nactvar = 0; + fs->bl = NULL; +- f->source = ls->source; ++ f->source = luaS_ref(ls->source); + f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ +--- a/src/lstate.c ++++ b/src/lstate.c +@@ -22,6 +22,7 @@ + #include "lstring.h" + #include "ltable.h" + #include "ltm.h" ++#include "lvm.h" + + + #define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) +@@ -52,7 +53,7 @@ static void stack_init (lua_State *L1, l + L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + /* initialize first ci */ + L1->ci->func = L1->top; +- setnilvalue(L1->top++); /* `function' entry for this `ci' */ ++ setnilvalue(L1, L1->top++); /* `function' entry for this `ci' */ + L1->base = L1->ci->base = L1->top; + L1->ci->top = L1->top + LUA_MINSTACK; + } +@@ -98,7 +99,7 @@ static void preinit_state (lua_State *L, + L->base_ci = L->ci = NULL; + L->savedpc = NULL; + L->errfunc = 0; +- setnilvalue(gt(L)); ++ setnilvalue(L, gt(L)); + } + + +@@ -163,7 +164,7 @@ LUA_API lua_State *lua_newstate (lua_All + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; +- setnilvalue(registry(L)); ++ setnilvalue(L, registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSpause; +--- a/src/lstring.c ++++ b/src/lstring.c +@@ -37,6 +37,9 @@ void luaS_resize (lua_State *L, int news + int h1 = lmod(h, newsize); /* new position */ + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); + p->gch.next = newhash[h1]; /* chain it */ ++ if (p->gch.next) ++ p->gch.next->gch.prev = p; ++ p->gch.prev = NULL; + newhash[h1] = p; + p = next; + } +@@ -59,11 +62,15 @@ static TString *newlstr (lua_State *L, c + ts->tsv.marked = luaC_white(G(L)); + ts->tsv.tt = LUA_TSTRING; + ts->tsv.reserved = 0; ++ ts->tsv.refcount = 0; + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + tb = &G(L)->strt; + h = lmod(h, tb->size); + ts->tsv.next = tb->hash[h]; /* chain new entry */ ++ if (ts->tsv.next) ++ ts->tsv.next->gch.prev = (GCObject *)ts; ++ ts->tsv.prev = NULL; + tb->hash[h] = obj2gco(ts); + tb->nuse++; + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) +@@ -109,3 +116,29 @@ Udata *luaS_newudata (lua_State *L, size + return u; + } + ++void luaS_unref(lua_State *L, TString *ts) { ++ if (!L || !ts) ++ return; ++ if (testbit(ts->tsv.marked, FIXEDBIT)) ++ return; ++ ts->tsv.refcount--; ++ if (ts->tsv.refcount < 0) { ++ fprintf(stderr, "REFCOUNT BUG, COUNT=%d, str=%s, len=%d\n", ts->tsv.refcount, (char *) (ts + 1), (int) ts->tsv.len); ++ } else if (ts->tsv.refcount) ++ return; ++ ++ if (ts->tsv.prev) { ++ ts->tsv.prev->gch.next = ts->tsv.next; ++ } else { ++ unsigned int idx = lmod(ts->tsv.hash, G(L)->strt.size); ++ lua_assert(G(L)->strt.hash[index] == (GCObject*)ts); ++ G(L)->strt.hash[idx] = ts->tsv.next; ++ } ++ ++ if (ts->tsv.next) ++ ts->tsv.next->gch.prev = ts->tsv.prev; ++ ++ luaC_freeobj(L, (GCObject *) ts); ++} ++ ++ +--- a/src/lstring.h ++++ b/src/lstring.h +@@ -7,7 +7,7 @@ + #ifndef lstring_h + #define lstring_h + +- ++#include + #include "lgc.h" + #include "lobject.h" + #include "lstate.h" +@@ -23,6 +23,12 @@ + + #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + ++static inline TString *luaS_ref(TString *ts) { ++ ts->tsv.refcount++; ++ return ts; ++} ++ ++LUA_API void luaS_unref(lua_State *L, TString *ts); + LUAI_FUNC void luaS_resize (lua_State *L, int newsize); + LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); + LUA_API TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +--- a/src/ltable.c ++++ b/src/ltable.c +@@ -34,6 +34,7 @@ + #include "lstate.h" + #include "ltable.h" + #include "lnum.h" ++#include "lvm.h" + + + /* +@@ -278,7 +279,7 @@ static void setarrayvector (lua_State *L + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); + for (i=t->sizearray; iarray[i]); ++ setnilvalue(L, &t->array[i]); + t->sizearray = size; + } + +@@ -299,8 +300,8 @@ static void setnodevector (lua_State *L, + for (i=0; ilsizenode = cast_byte(lsize); +@@ -427,9 +428,11 @@ static TValue *newkey (lua_State *L, Tab + othern = gnext(othern); /* find previous */ + } + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ ++ luaV_ref((TValue *) gkey(mp)); ++ luaV_ref(gval(mp)); + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + gnext(mp) = NULL; /* now `mp' is free */ +- setnilvalue(gval(mp)); ++ setnilvalue(L, gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ +@@ -438,6 +441,7 @@ static TValue *newkey (lua_State *L, Tab + mp = n; + } + } ++ luaV_ref((TValue *) key); + gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + luaC_barriert(L, t, key); + lua_assert(ttisnil(gval(mp))); +@@ -530,7 +534,7 @@ TValue *luaH_setint (lua_State *L, Table + if (p != luaO_nilobject) + return cast(TValue *, p); + else { +- TValue k; ++ TValue k = tvinit(); + setivalue(&k, key); + return newkey(L, t, &k); + } +@@ -542,7 +546,7 @@ TValue *luaH_setstr (lua_State *L, Table + if (p != luaO_nilobject) + return cast(TValue *, p); + else { +- TValue k; ++ TValue k = tvinit(); + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +--- a/src/luac.c ++++ b/src/luac.c +@@ -20,8 +20,9 @@ + #include "lmem.h" + #include "lobject.h" + #include "lopcodes.h" +-#include "lstring.h" + #include "lundump.h" ++#include "lvm.h" ++#include "lstring.h" + + #define PROGNAME "luac" /* default program name */ + #define OUTPUT PROGNAME ".out" /* default output file */ +--- a/src/lundump.c ++++ b/src/lundump.c +@@ -19,6 +19,7 @@ + #include "lstring.h" + #include "lundump.h" + #include "lzio.h" ++#include "lvm.h" + + typedef struct { + lua_State* L; +@@ -133,7 +134,7 @@ static TString* LoadString(LoadState* S) + { + char* s=luaZ_openspace(S->L,S->b,size); + LoadBlock(S,s,size); +- return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ ++ return luaS_ref(luaS_newlstr(S->L,s,size-1)); /* remove trailing '\0' */ + } + } + +@@ -149,11 +150,12 @@ static Proto* LoadFunction(LoadState* S, + + static void LoadConstants(LoadState* S, Proto* f) + { ++ lua_State *L = S->L; + int i,n; + n=LoadInt(S); + f->k=luaM_newvector(S->L,n,TValue); + f->sizek=n; +- for (i=0; ik[i]); ++ for (i=0; ik[i]); + for (i=0; ik[i]; +@@ -161,7 +163,7 @@ static void LoadConstants(LoadState* S, + switch (t) + { + case LUA_TNIL: +- setnilvalue(o); ++ setnilvalue(L, o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadChar(S)!=0); +@@ -229,6 +231,7 @@ static Proto* LoadFunction(LoadState* S, + LoadDebug(S,f); + IF (!luaG_checkcode(f), "bad code"); + S->L->top--; ++ setnilvalue(S->L, S->L->top); + S->L->nCcalls--; + return f; + } +--- a/src/lvm.c ++++ b/src/lvm.c +@@ -39,6 +39,7 @@ + * If 'obj' is a string, it is tried to be interpreted as a number. + */ + const TValue *luaV_tonumber ( const TValue *obj, TValue *n) { ++ lua_State *L = NULL; /* FIXME */ + lua_Number d; + lua_Integer i; + +@@ -384,6 +385,7 @@ void luaV_concat (lua_State *L, int tota + size_t l = tsvalue(top-i)->len; + memcpy(buffer+tl, svalue(top-i), l); + tl += l; ++ setnilvalue(L, top - i); + } + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + } +@@ -420,7 +422,7 @@ void luaV_concat (lua_State *L, int tota + */ + static void Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { +- TValue tempb, tempc; ++ TValue tempb = tvinit(), tempc = tvinit(); + const TValue *b, *c; + lua_Number nb,nc; + +@@ -663,7 +665,7 @@ void luaV_execute (lua_State *L, int nex + OPCODE_TARGET(LOADNIL) { + TValue *rb = RB(i); + do { +- setnilvalue(rb--); ++ setnilvalue(L, rb--); + } while (rb >= ra); + continue; + } +@@ -673,7 +675,7 @@ void luaV_execute (lua_State *L, int nex + continue; + } + OPCODE_TARGET(GETGLOBAL) { +- TValue g; ++ TValue g = tvinit(); + TValue *rb = KBx(i); + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(rb)); +@@ -685,7 +687,7 @@ void luaV_execute (lua_State *L, int nex + continue; + } + OPCODE_TARGET(SETGLOBAL) { +- TValue g; ++ TValue g = tvinit(); + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + Protect(luaV_settable(L, &g, KBx(i), ra)); +@@ -693,7 +695,7 @@ void luaV_execute (lua_State *L, int nex + } + OPCODE_TARGET(SETUPVAL) { + UpVal *uv = cl->upvals[GETARG_B(i)]; +- setobj(L, uv->v, ra); ++ setobj(L, uv->v, luaV_ref(ra)); + luaC_barrier(L, uv, ra); + continue; + } +@@ -1030,7 +1032,7 @@ void luaV_execute (lua_State *L, int nex + setobjs2s(L, ra + j, ci->base - n + j); + } + else { +- setnilvalue(ra + j); ++ setnilvalue(L, ra + j); + } + } + continue; +--- a/src/lvm.h ++++ b/src/lvm.h +@@ -11,6 +11,7 @@ + #include "ldo.h" + #include "lobject.h" + #include "ltm.h" ++#include "lstring.h" + + + #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) +@@ -19,6 +20,19 @@ + + #define equalobj(L,o1,o2) (ttype_ext_same(o1,o2) && luaV_equalval(L, o1, o2)) + ++static inline TValue *luaV_ref(TValue *tv) ++{ ++ if (ttisstring(tv)) ++ luaS_ref(rawtsvalue(tv)); ++ return tv; ++} ++ ++static inline TValue *luaV_unref(lua_State *L, TValue *tv) ++{ ++ if (ttisstring(tv)) ++ luaS_unref(L, rawtsvalue(tv)); ++ return tv; ++} + + LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); + LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +--- a/src/llex.c ++++ b/src/llex.c +@@ -23,6 +23,7 @@ + #include "ltable.h" + #include "lzio.h" + #include "lnum.h" ++#include "lvm.h" + + + +@@ -69,7 +70,7 @@ static void save (LexState *ls, int c) { + void luaX_init (lua_State *L) { + int i; + for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ +@@ -125,7 +126,7 @@ void luaX_syntaxerror (LexState *ls, con + + TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; +- TString *ts = luaS_newlstr(L, str, l); ++ TString *ts = luaS_ref(luaS_newlstr(L, str, l)); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ +@@ -152,7 +153,7 @@ void luaX_setinput (lua_State *L, LexSta + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; +- ls->source = source; ++ ls->source = luaS_ref(source); + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ + }