[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: [Patch] Finalization of function objects
- From: TNHarris <telliamed@...>
- Date: Fri, 31 Jul 2009 16:55:13 -0400
On Fri, 31 Jul 2009 15:23:21 -0400
"Thomas Harning Jr." <harningt@gmail.com> wrote:
> I've narrowed this down to the GC'ed coroutine. Ah hah!
>
> My guess is that the locally defined function somehow got cleaned up
> during the coroutine finalization.... then the op got called and it
> passes due to the fact that the memory hadn't yet been written over.
>
> I don't know how valgrind misses it on your system (from way back)...
> but I can reproducibly cause valgrind errors and 'fix' them. Now to
> see how in the world to fix this in the patch.
>
I don't believe the original patch was marking the coroutines
properly. I redid the GC so finalizers are treated similarly to userdata
__gc methods, the coroutine doesn't get collected until a second
finalize pass is done.
[lua514-finalizers0609.patch]
At the same time I simplified how finalizers are stored, and also
improves the speed. A call with finally is as fast as pcall and 43%
slower than using neither. With the previous patch, finally was 8%
slower than pcall and 59% slower than a regular call.
That said, I'm not even sure if this patch is needed, as I also put
together a rough framework of finalizers in pure lua.
[final.lua]
-- tom
telliamed@whoopdedo.org
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lapi.c lua.mod/src/lapi.c
--- lua.orig/src/lapi.c 2008-07-04 14:41:18.000000000 -0400
+++ lua.mod/src/lapi.c 2009-05-30 15:47:13.396958400 -0400
@@ -1085,3 +1085,64 @@
return name;
}
+
+
+/*
+** finalization functions
+*/
+
+
+LUA_API int lua_getfinalframe (lua_State *L) {
+ int base = L->fin_stack ? L->fin_top - L->fin_stack + 1 : 1;
+ return base;
+}
+
+
+LUA_API int lua_finally (lua_State *L, int nargs, int scope, int when) {
+ int base;
+ StkId fin,o;
+ TValue key;
+ lua_lock(L);
+ api_checknelems(L, nargs + 1);
+ api_check(L, scope <= 0 && L->base_ci <= scope + L->ci);
+ fin = L->top - (nargs+1);
+ if (!ttisfunction(fin)) {
+ setsvalue(L, &key, luaS_new(L, "close"));
+ luaV_gettable(L, fin, &key, L->top);
+ if (!ttisfunction(L->top)) {
+ setobj2s(L, L->top, luaT_gettmbyobj(L, fin, TM_GC));
+ if (!ttisfunction(L->top)) {
+ base = L->fin_stack ? L->fin_top - L->fin_stack + 1 : 1;
+ L->top = fin;
+ lua_unlock(L);
+ return base;
+ }
+ }
+ api_incr_top(L);
+ o = fin;
+ for (o = L->top; o>fin; o--) setobjs2s(L, o, o-1);
+ setobjs2s(L, fin, L->top);
+ nargs++;
+ }
+ base = luaD_finally(L, fin, scope, when);
+ lua_unlock(L);
+ return base;
+}
+
+
+LUA_API void lua_finalize (lua_State *L, int base, int failure) {
+ StkId fin;
+ lua_lock(L);
+ if (base == 0) {
+ if (NULL == (fin = L->ci->fin_base)) {
+ lua_unlock(L);
+ return;
+ }
+ }
+ else
+ fin = L->fin_stack + base - 1;
+ api_check(L, L->fin_stack <= fin && fin <= L->fin_top);
+ luaD_finalize(L, fin, failure);
+ lua_unlock(L);
+}
+
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lbaselib.c lua.mod/src/lbaselib.c
--- lua.orig/src/lbaselib.c 2008-02-14 11:46:22.000000000 -0500
+++ lua.mod/src/lbaselib.c 2009-05-30 15:59:47.561393600 -0400
@@ -393,6 +393,32 @@
}
+static int luaB_finally (lua_State *L) {
+ int base;
+ int when = LUA_FINALWAYS;
+ int nargs = lua_gettop(L) - 1;
+ if (nargs >= 0) {
+ if (lua_isboolean(L, 1)) {
+ nargs--;
+ luaL_checkany(L, 2);
+ when = lua_toboolean(L, 1) ? LUA_FINSUCCESS : LUA_FINERROR;
+ }
+ base = lua_finally(L, nargs, -1, when);
+ }
+ else
+ base = lua_getfinalframe(L);
+ lua_pushinteger(L, base);
+ return 1;
+}
+
+
+static int luaB_finalize (lua_State *L) {
+ int base = luaL_optint(L, 1, 0);
+ lua_finalize(L, base, !lua_isnoneornil(L, 2));
+ return 0;
+}
+
+
static int luaB_tostring (lua_State *L) {
luaL_checkany(L, 1);
if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
@@ -469,6 +495,8 @@
{"type", luaB_type},
{"unpack", luaB_unpack},
{"xpcall", luaB_xpcall},
+ {"finally", luaB_finally},
+ {"finalize", luaB_finalize},
{NULL, NULL}
};
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/ldo.c lua.mod/src/ldo.c
--- lua.orig/src/ldo.c 2008-01-18 17:31:22.000000000 -0500
+++ lua.mod/src/ldo.c 2009-05-30 19:54:16.100960000 -0400
@@ -83,6 +83,8 @@
L->base = L->ci->base;
luaF_close(L, L->base); /* close eventual pending closures */
luaD_seterrorobj(L, status, L->base);
+ L->allowhook = 0;
+ if (L->fin_top) luaD_finalize(L, L->fin_top, 1);
L->nCcalls = L->baseCcalls;
L->allowhook = 1;
restore_stack_limit(L);
@@ -293,6 +295,7 @@
L->savedpc = p->code; /* starting point */
ci->tailcalls = 0;
ci->nresults = nresults;
+ ci->fin_base = NULL;
for (st = L->top; st < ci->top; st++)
setnilvalue(st);
L->top = ci->top;
@@ -313,6 +316,7 @@
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->nresults = nresults;
+ ci->fin_base = NULL;
if (L->hookmask & LUA_MASKCALL)
luaD_callhook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
@@ -345,6 +349,11 @@
CallInfo *ci;
if (L->hookmask & LUA_MASKRET)
firstResult = callrethooks(L, firstResult);
+ if (L->ci->fin_base) {
+ ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
+ luaD_finalize(L, L->ci->fin_base, 0);
+ firstResult = restorestack(L, fr);
+ }
ci = L->ci--;
res = ci->func; /* res == final position of 1st result */
wanted = ci->nresults;
@@ -360,6 +369,94 @@
}
+void luaD_reallocFIN (lua_State *L, int newsize) {
+ CallInfo *ci;
+ TValue *oldfin = L->fin_stack;
+ luaM_reallocvector(L, L->fin_stack, L->fin_size, newsize, TValue);
+ L->fin_size = newsize;
+ L->fin_top = (L->fin_top - oldfin) + L->fin_stack;
+ for (ci = L->base_ci; ci <= L->ci; ci++)
+ if (ci->fin_base) ci->fin_base = (ci->fin_base - oldfin) + L->fin_stack;
+}
+
+
+void luaD_growfinstack (lua_State *L, int n) {
+ if (n <= L->fin_size) /* double size is enough? */
+ luaD_reallocFIN(L, 2*L->fin_size);
+ else
+ luaD_reallocFIN(L, L->fin_size + (n < BASIC_STACK_SIZE ? BASIC_STACK_SIZE : n));
+}
+
+
+int luaD_finally (lua_State *L, StkId func, int scope, int when) {
+ StkId o;
+ TValue *fin;
+ int ncond = when==LUA_FINALWAYS ? 0 :
+ when==LUA_FINERROR ? 2*LUAI_MAXCSTACK :
+ LUAI_MAXCSTACK; /* conditional call */
+ int n = L->top - func + 1;
+ L->fin_top += n;
+ if (L->fin_top - L->fin_stack >= L->fin_size) {
+ luaD_growfinstack(L, n);
+ }
+ fin = L->fin_top - 1;
+ setnvalue(fin, cast_num(ncond + --n));
+ for (o = func; n-- != 0; o++) { /* push objects to finalization stack */
+ setobj2n(L, --fin, o);
+ luaC_barrier(L, obj2gco(L), o);
+ }
+ /* set finalization base of call frame */
+ {
+ CallInfo *ci = L->ci + scope;
+ lua_assert(L->base_ci <= ci);
+ if (!ci->fin_base) ci->fin_base = fin;
+ }
+ return fin - L->fin_stack + 1;
+}
+
+
+void luaD_finalize (lua_State *L, StkId base, int failure) {
+ TValue *fin;
+ int nmax = 0;
+ lua_assert(base && L->fin_stack && L->fin_stack <= base && base <= L->fin_top);
+ while ((fin = L->fin_top-1) > base) {
+ StkId o, func;
+ int call = 1, n;
+ lua_assert(ttisnumber(fin));
+ n = cast_int(nvalue(fin));
+ if (n >= LUAI_MAXCSTACK) { /* call on success */
+ n -= LUAI_MAXCSTACK;
+ if (n >= LUAI_MAXCSTACK) { /* call on failure */
+ n -= LUAI_MAXCSTACK;
+ call = failure;
+ }
+ else
+ call = !failure;
+ }
+ L->fin_top = fin - n;
+ lua_assert(L->fin_stack <= L->fin_top);
+ if (!call) {
+ fin -= n + 1;
+ continue;
+ }
+ if (n > nmax) {
+ nmax = n;
+ luaD_checkstack(L, n + 1); /* with error message */
+ }
+ o = func = L->top;
+ fin--;
+ lua_assert(ttisfunction(fin));
+ while (n-- != 0) /* pop objects from finalization stack */
+ setobj2s(L, o++, fin--);
+ if (failure)
+ setobj2s(L, o++, func - 1); /* push error message */
+ L->top = o;
+ luaD_call(L, func, 0);
+ }
+ if (L->ci->fin_base >= L->fin_top) L->ci->fin_base = NULL;
+}
+
+
/*
** Call a function (C or Lua). The function to be called is at *func.
** The arguments are on the stack, right after the function.
@@ -428,6 +525,7 @@
if (status != 0) { /* error? */
L->status = cast_byte(status); /* mark thread as `dead' */
luaD_seterrorobj(L, status, L->top);
+ if (L->fin_top >= L->fin_stack) luaD_finalize(L, L->fin_top, 1);
L->ci->top = L->top;
}
else {
@@ -459,12 +557,15 @@
ptrdiff_t old_ci = saveci(L, L->ci);
lu_byte old_allowhooks = L->allowhook;
ptrdiff_t old_errfunc = L->errfunc;
+ ptrdiff_t old_fin = savefin(L, L->fin_top);
L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u);
if (status != 0) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
+ StkId fintop = restorefin(L, old_fin);
luaF_close(L, oldtop); /* close eventual pending closures */
luaD_seterrorobj(L, status, oldtop);
+ if (fintop) luaD_finalize(L, fintop, 1);
L->nCcalls = oldnCcalls;
L->ci = restoreci(L, old_ci);
L->base = L->ci->base;
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/ldo.h lua.mod/src/ldo.h
--- lua.orig/src/ldo.h 2007-12-27 08:02:25.000000000 -0500
+++ lua.mod/src/ldo.h 2009-05-30 17:08:26.414012800 -0400
@@ -27,6 +27,9 @@
#define saveci(L,p) ((char *)(p) - (char *)L->base_ci)
#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n)))
+#define savefin(L,p) ((char *)(p) - (char *)L->fin_stack)
+#define restorefin(L,n) ((TValue *)((char *)L->fin_stack + (n)))
+
/* results from luaD_precall */
#define PCRLUA 0 /* initiated a call to a Lua function */
@@ -47,6 +50,10 @@
LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
+LUAI_FUNC void luaD_reallocFIN (lua_State *L, int newsize);
+LUAI_FUNC void luaD_growfinstack (lua_State *L, int n);
+LUAI_FUNC int luaD_finally (lua_State *L, StkId func, int scope, int when);
+LUAI_FUNC void luaD_finalize (lua_State *L, StkId base, int failure);
LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lgc.c lua.mod/src/lgc.c
--- lua.orig/src/lgc.c 2007-12-27 08:02:25.000000000 -0500
+++ lua.mod/src/lgc.c 2009-05-30 16:36:09.388707200 -0400
@@ -40,8 +40,8 @@
#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
-#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
-#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
+#define isfinalized(u) testbit((u)->gch.marked, FINALIZEDBIT)
+#define markfinalized(u) l_setbit((u)->gch.marked, FINALIZEDBIT)
#define KEYWEAK bitmask(KEYWEAKBIT)
@@ -131,15 +131,27 @@
GCObject **p = &g->mainthread->next;
GCObject *curr;
while ((curr = *p) != NULL) {
- if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
+ if (!(iswhite(curr) || all) || isfinalized(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));
+ else {
+ if (curr->gch.tt == LUA_TTHREAD) {
+ lua_State *th = gco2th(curr);
+ if (th->fin_stack == NULL || th->fin_top <= th->fin_stack) {
+ markfinalized(curr); /* don't need finalization */
+ p = &curr->gch.next;
+ continue;
+ }
+ }
+ else {
+ if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
+ markfinalized(curr); /* don't need finalization */
+ p = &curr->gch.next;
+ continue;
+ }
+ /* must call its gc method */
+ deadmem += sizeudata(gco2u(curr));
+ }
+ markfinalized(curr);
*p = curr->gch.next;
/* link `curr' at the end of `tmudata' list */
if (g->tmudata == NULL) /* list is empty? */
@@ -241,6 +253,7 @@
static void checkstacksizes (lua_State *L, StkId max) {
int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */
int s_used = cast_int(max - L->stack); /* part of stack in use */
+ int fin_used = cast_int(L->fin_top - L->fin_stack); /* size of finalizer stack */
if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */
return; /* do not touch the stacks */
if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
@@ -250,6 +263,10 @@
2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
condhardstacktests(luaD_reallocstack(L, s_used));
+ if (4*fin_used < L->fin_size &&
+ 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->fin_size)
+ luaD_reallocFIN(L, L->fin_size/2); /* still big enough... */
+ condhardstacktests(luaD_reallocFIN(L, fin_used));
}
@@ -257,6 +274,10 @@
StkId o, lim;
CallInfo *ci;
markvalue(g, gt(l));
+ if (l->fin_stack) {
+ for (o = l->fin_stack; o < l->fin_top; o++)
+ markvalue(g, o);
+ }
lim = l->top;
for (ci = l->base_ci; ci <= l->ci; ci++) {
lua_assert(ci->top <= l->stack_last);
@@ -302,7 +323,8 @@
black2gray(o);
traversestack(g, th);
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
- sizeof(CallInfo) * th->size_ci;
+ sizeof(CallInfo) * th->size_ci +
+ sizeof(TValue) * th->fin_size;
}
case LUA_TPROTO: {
Proto *p = gco2p(o);
@@ -341,7 +363,8 @@
return 0;
}
return iswhite(gcvalue(o)) ||
- (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
+ (ttisuserdata(o) && (!iskey && isfinalized(obj2gco(o)))) ||
+ (ttisthread(o) && (!iskey && isfinalized(obj2gco(o))));
}
@@ -445,28 +468,42 @@
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->tmudata->gch.next = o->gch.next;
+ o->gch.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 */
+ if (o->gch.tt == LUA_TTHREAD) {
+ lua_State *th = gco2th(o);
+ if (th->fin_stack) {
+ lu_byte oldah = th->allowhook;
+ lu_mem oldt = g->GCthreshold;
+ th->allowhook = 0; /* stop debug hooks during GC tag method */
+ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */
+ luaD_finalize(th, th->fin_stack, 0);
+ th->allowhook = oldah; /* restore hooks */
+ g->GCthreshold = oldt; /* restore threshold */
+ }
+ }
+ else {
+ Udata *udata = rawgco2u(o);
+ const TValue *tm;
+ 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 */
+ }
}
}
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lstate.c lua.mod/src/lstate.c
--- lua.orig/src/lstate.c 2008-01-03 10:20:39.000000000 -0500
+++ lua.mod/src/lstate.c 2009-05-30 16:57:46.664097600 -0400
@@ -55,12 +55,14 @@
setnilvalue(L1->top++); /* `function' entry for this `ci' */
L1->base = L1->ci->base = L1->top;
L1->ci->top = L1->top + LUA_MINSTACK;
+ L1->ci->fin_base = NULL;
}
static void freestack (lua_State *L, lua_State *L1) {
luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
luaM_freearray(L, L1->stack, L1->stacksize, TValue);
+ luaM_freearray(L, L1->fin_stack, L1->fin_size, TValue);
}
@@ -99,6 +101,9 @@
L->savedpc = NULL;
L->errfunc = 0;
setnilvalue(gt(L));
+ L->fin_stack = NULL;
+ L->fin_top = NULL;
+ L->fin_size = 0;
}
@@ -118,7 +123,11 @@
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);
+ /*luaC_link(L, obj2gco(L1), LUA_TTHREAD);*/
+ L1->marked = luaC_white(G(L));
+ L1->tt = LUA_TTHREAD;
+ L1->next = G(L)->mainthread->next;
+ G(L)->mainthread->next = obj2gco(L1);
preinit_state(L1, G(L));
stack_init(L1, L); /* init stack */
setobj2n(L, gt(L1), gt(L)); /* share table of globals */
@@ -133,6 +142,8 @@
void luaE_freethread (lua_State *L, lua_State *L1) {
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
+ /*if (L1->fin_stack) luaD_finalize(L1, L1->fin_stack, 0); thread is finalized by GC */
+ lua_assert(L1->fin_stack == NULL || L1->fin_top <= L1->fin_stack);
lua_assert(L1->openupval == NULL);
luai_userstatefree(L1);
freestack(L, L1);
@@ -200,6 +211,7 @@
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
+ if (L->fin_stack) luaD_finalize(L, L->fin_stack, 0);
luaC_separateudata(L, 1); /* separate udata that have GC metamethods */
L->errfunc = 0; /* no error function during GC metamethods */
do { /* repeat until no more errors */
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lstate.h lua.mod/src/lstate.h
--- lua.orig/src/lstate.h 2008-01-03 10:20:39.000000000 -0500
+++ lua.mod/src/lstate.h 2009-05-30 16:50:27.622787200 -0400
@@ -52,6 +52,7 @@
const Instruction *savedpc;
int nresults; /* expected number of results from this function */
int tailcalls; /* number of tail calls lost under this entry */
+ StkId fin_base; /* start of the finalization stack */
} CallInfo;
@@ -124,6 +125,9 @@
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
+ StkId fin_stack; /* finalization stack */
+ StkId fin_top; /* first free slot in the finalization stack */
+ int fin_size; /* size of finalization stack */
};
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lua.h lua.mod/src/lua.h
--- lua.orig/src/lua.h 2008-08-06 09:30:12.000000000 -0400
+++ lua.mod/src/lua.h 2009-05-30 16:04:14.465182400 -0400
@@ -244,6 +244,19 @@
LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+/*
+** finalization functions
+*/
+
+#define LUA_FINALWAYS 0
+#define LUA_FINSUCCESS 1
+#define LUA_FINERROR 2
+
+LUA_API int lua_getfinalframe (lua_State *L);
+LUA_API int lua_finally (lua_State *L, int nargs, int scope, int when);
+LUA_API void lua_finalize (lua_State *L, int base, int failure);
+
+
/*
** ===============================================================
diff -urN -x '*.exe' -x '*.lua' lua.orig/src/lvm.c lua.mod/src/lvm.c
--- lua.orig/src/lvm.c 2007-12-28 10:32:23.000000000 -0500
+++ lua.mod/src/lvm.c 2009-05-30 16:41:32.262977600 -0400
@@ -613,6 +613,7 @@
StkId func = ci->func;
StkId pfunc = (ci+1)->func; /* previous function index */
if (L->openupval) luaF_close(L, ci->base);
+ if (ci->fin_base) luaD_finalize(L, ci->fin_base, 0);
L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */
setobjs2s(L, func+aux, pfunc+aux);
Attachment:
final.lua
Description: Binary data