lua-users home
lua-l archive

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


On Mon, 3 Aug 2009 12:05:26 -0400
"Thomas Harning Jr." <harningt@gmail.com> wrote:

> The following patch to TNHarris's code makes the code pass the current
> test-set.  I think it is correct  and may have been a little typo in
> the original code:
> -    if (L->fin_top >= L->fin_stack) luaD_finalize(L, L->fin_top, 1);
> +    if (L->fin_top >= L->fin_stack) luaD_finalize(L, L->fin_stack,
> 1);
> 
> Basically... the code to handle coroutine errors was originally doing
> nothing because it was finalizing from  L->fin_top  to  L->fin_top ...
> quite an empty set.  Since this is freeing everything in that thread,
> it needs to free from L->fin_top to L->fin_stack (the base)
> 

Yes, that was the problem. And also in resetstack, the same thing:
diff -urN -x '*.o' -x '*.a' -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-08-02 06:57:33.526611200 -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_stack, 1);
   L->nCcalls = L->baseCcalls;
   L->allowhook = 1;
   restore_stack_limit(L);

> Comparing from 'original' finalizer patch (Nodir) to the newer one
> provided by  TNHarris... I'm not sure which is 'correct' or not,
> especially ones that alter the Lua internal stack/etc.

Mostly, this is because of the change from a base+offset stack to stack
pointers. But when it comes to calling finalizers after an error, I'm
not too sure how the Lua state and call info should be massaged to avoid
"Bad Things". I guessed on a lot of it and, if it appeared to work, let
it be. I think the order should be to clean up from the callee, invoke
finalizers, restore the caller state.

-- tom
telliamed@whoopdedo.org
diff -urN -x '*.o' -x '*.a' -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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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-08-02 06:57:33.526611200 -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_stack, 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_stack, 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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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 '*.o' -x '*.a' -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);