Forráskód Böngészése

simpler solution for finalizing udata

Roberto Ierusalimschy 23 éve
szülő
commit
ca2ceef659
1 módosított fájl, 54 hozzáadás és 47 törlés
  1. 54 47
      lgc.c

+ 54 - 47
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.129 2002/03/05 16:22:54 roberto Exp roberto $
+** $Id: lgc.c,v 1.130 2002/03/07 18:14:29 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -27,7 +27,6 @@ typedef struct GCState {
 } GCState;
 
 
-
 /* mark a string; marks larger than 1 cannot be changed */
 #define strmark(s)    {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
 
@@ -37,6 +36,9 @@ typedef struct GCState {
 #define markud(u)	(u->uv.len |= 1)
 #define unmarkud(u)	(u->uv.len &= (~(size_t)1))
 
+#define isfinalized(u)		(u->uv.len & 2)
+#define markfinalized(u)	(u->uv.len |= 2)
+
 
 /* mark tricks for upvalues (assume that open upvalues are always marked) */
 #define isupvalmarked(uv)	((uv)->v != &(uv)->value)
@@ -97,10 +99,17 @@ static void marktable (GCState *st, Table *h) {
   if (!ismarked(h)) {
     h->mark = st->tmark;  /* chain it for later traversal */
     st->tmark = h;
+    marktable(st, h->metatable);
   }
 }
 
 
+static void markudata (GCState *st, Udata *u) {
+  markud(u);
+  marktable(st, u->uv.metatable);
+}
+
+
 static void reallymarkobject (GCState *st, TObject *o) {
   switch (ttype(o)) {
     case LUA_TSTRING:
@@ -108,7 +117,7 @@ static void reallymarkobject (GCState *st, TObject *o) {
       break;
     case LUA_TUSERDATA:
       if (!isudmarked(uvalue(o)))
-        markud(uvalue(o));
+        markudata(st, uvalue(o));
       break;
     case LUA_TFUNCTION:
       markclosure(st, clvalue(o));
@@ -156,12 +165,33 @@ static void markstacks (GCState *st) {
 }
 
 
-static void markudet (GCState *st) {
+static void marktmu (GCState *st) {
   Udata *u;
-  for (u = G(st->L)->rootudata; u; u = u->uv.next)
-    marktable(st, u->uv.metatable);
   for (u = G(st->L)->tmudata; u; u = u->uv.next)
-    marktable(st, u->uv.metatable);
+    markudata(st, u);
+}
+
+
+/* move `dead' udata that need finalization to list `tmudata' */
+static void separateudata (lua_State *L) {
+  Udata **p = &G(L)->rootudata;
+  Udata *curr;
+  Udata *collected = NULL;  /* to collect udata with gc event */
+  Udata **lastcollected = &collected;
+  while ((curr = *p) != NULL) {
+    if (isudmarked(curr) || isfinalized(curr) ||
+        (fasttm(L, curr->uv.metatable, TM_GC) == NULL))
+      p = &curr->uv.next;
+    else {  /* must call its gc method */
+      *p = curr->uv.next;
+      curr->uv.next = NULL;  /* link `curr' at the end of `collected' list */
+      *lastcollected = curr;
+      lastcollected = &curr->uv.next;
+    }
+  }
+  /* insert collected udata with gc event into `tmudata' list */
+  *lastcollected = G(L)->tmudata;
+  G(L)->tmudata = collected;
 }
 
 
@@ -208,7 +238,6 @@ static void markall (GCState *st) {
   lua_assert(hvalue(defaultmeta(st->L))->flags == cast(unsigned short, ~0));
                                                       /* table is unchanged */
   markstacks(st); /* mark all stacks */
-  markudet(st);  /* mark userdata's meta tables */
   while (st->tmark) {  /* traverse marked tables */
     Table *h = st->tmark;  /* get first table from list */
     st->tmark = h->mark;  /* remove it from list */
@@ -322,11 +351,10 @@ static void collecttable (lua_State *L) {
 }
 
 
+
 static void collectudata (lua_State *L) {
   Udata **p = &G(L)->rootudata;
   Udata *curr;
-  Udata *collected = NULL;  /* to collect udata with gc event */
-  Udata **lastcollected = &collected;
   while ((curr = *p) != NULL) {
     if (isudmarked(curr)) {
       unmarkud(curr);
@@ -334,18 +362,11 @@ static void collectudata (lua_State *L) {
     }
     else {
       *p = curr->uv.next;
-      if (fasttm(L, curr->uv.metatable, TM_GC) != NULL) {  /* gc event? */
-        curr->uv.next = NULL;  /* link `curr' at the end of `collected' list */
-        *lastcollected = curr;
-        lastcollected = &curr->uv.next;
-      }
-      else  /* no gc event; delete udata */
-        luaM_free(L, curr, sizeudata(curr->uv.len));
+      lua_assert(isfinalized(curr) ||
+                 fasttm(L, curr->uv.metatable, TM_GC) == NULL);
+      luaM_free(L, curr, sizeudata(curr->uv.len & (~(size_t)3)));
     }
   }
-  /* insert collected udata with gc event into `tmudata' list */
-  *lastcollected = G(L)->tmudata;
-  G(L)->tmudata = collected;
 }
 
 
@@ -395,44 +416,27 @@ static void do1gcTM (lua_State *L, Udata *udata) {
 }
 
 
-static void unprotectedcallGCTM (lua_State *L, void *pu) {
-  luaD_checkstack(L, 3);
+static void callGCTM (lua_State *L) {
+  int oldah = L->allowhooks;
+  L->allowhooks = 0;  /* stop debug hooks during GC tag methods */
   L->top++;  /* reserve space to keep udata while runs its gc method */
   while (G(L)->tmudata != NULL) {
     Udata *udata = G(L)->tmudata;
-    G(L)->tmudata = udata->uv.next;  /* remove udata from list */
-    *(Udata **)pu = udata;  /* keep a reference to it (in case of errors) */
-    setuvalue(L->top - 1, udata);  /* and on stack (in case of recursive GC) */
-    udata->uv.next = G(L)->rootudata;  /* resurect it */
+    G(L)->tmudata = udata->uv.next;  /* remove udata from `tmudata' */
+    udata->uv.next = G(L)->rootudata;  /* return it to `root' list */
     G(L)->rootudata = udata;
+    setuvalue(L->top - 1, udata);  /* keep a reference to it */
+    unmarkud(udata);
+    markfinalized(udata);
     do1gcTM(L, udata);
-    /* mark udata as finalized (default meta table) */
-    uvalue(L->top-1)->uv.metatable = hvalue(defaultmeta(L));
-    unmarkud(uvalue(L->top-1));
   }
   L->top--;
-}
-
-
-static void callGCTM (lua_State *L) {
-  int oldah = L->allowhooks;
-  L->allowhooks = 0;  /* stop debug hooks during GC tag methods */
-  while (G(L)->tmudata != NULL) {
-    Udata *udata;
-    if (luaD_runprotected(L, unprotectedcallGCTM, &udata) != 0) {
-      /* `udata' generated an error during its gc */
-      /* mark it as finalized (default meta table) */
-      udata->uv.metatable = hvalue(defaultmeta(L));
-    }
-  }
   L->allowhooks = oldah;  /* restore hooks */
 }
 
 
 void luaC_callallgcTM (lua_State *L) {
-  lua_assert(G(L)->tmudata == NULL);
-  G(L)->tmudata = G(L)->rootudata;  /* all udata must be collected */
-  G(L)->rootudata = NULL;
+  separateudata(L);
   callGCTM(L);  /* call their GC tag methods */
 }
 
@@ -452,7 +456,10 @@ void luaC_collectgarbage (lua_State *L) {
   st.L = L;
   st.tmark = NULL;
   st.toclear = NULL;
-  markall(&st);
+  markall(&st);  /* mark all reachable objects */
+  separateudata(L);  /* separate userdata to be preserved */
+  marktmu(&st);  /* mark `preserved' userdata */
+  markall(&st);  /* remark */
   cleartables(st.toclear);
   luaC_collect(L, 0);
   checkMbuffer(L);