lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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