diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-20 15:37:28 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-20 15:37:28 -0300 |
| commit | ca2ceef659ed013277485acd0b6058a536649730 (patch) | |
| tree | 1ff31ece632f1d6da84bc90c96255c3377b5d28f | |
| parent | 5023aaee0aa7cb741dc112deec7dc9469d804cd5 (diff) | |
| download | lua-ca2ceef659ed013277485acd0b6058a536649730.tar.gz lua-ca2ceef659ed013277485acd0b6058a536649730.tar.bz2 lua-ca2ceef659ed013277485acd0b6058a536649730.zip | |
simpler solution for finalizing udata
| -rw-r--r-- | lgc.c | 101 |
1 files changed, 54 insertions, 47 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 1.129 2002/03/05 16:22:54 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.130 2002/03/07 18:14:29 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -27,7 +27,6 @@ typedef struct GCState { | |||
| 27 | } GCState; | 27 | } GCState; |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | |||
| 31 | /* mark a string; marks larger than 1 cannot be changed */ | 30 | /* mark a string; marks larger than 1 cannot be changed */ |
| 32 | #define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} | 31 | #define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} |
| 33 | 32 | ||
| @@ -37,6 +36,9 @@ typedef struct GCState { | |||
| 37 | #define markud(u) (u->uv.len |= 1) | 36 | #define markud(u) (u->uv.len |= 1) |
| 38 | #define unmarkud(u) (u->uv.len &= (~(size_t)1)) | 37 | #define unmarkud(u) (u->uv.len &= (~(size_t)1)) |
| 39 | 38 | ||
| 39 | #define isfinalized(u) (u->uv.len & 2) | ||
| 40 | #define markfinalized(u) (u->uv.len |= 2) | ||
| 41 | |||
| 40 | 42 | ||
| 41 | /* mark tricks for upvalues (assume that open upvalues are always marked) */ | 43 | /* mark tricks for upvalues (assume that open upvalues are always marked) */ |
| 42 | #define isupvalmarked(uv) ((uv)->v != &(uv)->value) | 44 | #define isupvalmarked(uv) ((uv)->v != &(uv)->value) |
| @@ -97,10 +99,17 @@ static void marktable (GCState *st, Table *h) { | |||
| 97 | if (!ismarked(h)) { | 99 | if (!ismarked(h)) { |
| 98 | h->mark = st->tmark; /* chain it for later traversal */ | 100 | h->mark = st->tmark; /* chain it for later traversal */ |
| 99 | st->tmark = h; | 101 | st->tmark = h; |
| 102 | marktable(st, h->metatable); | ||
| 100 | } | 103 | } |
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | 106 | ||
| 107 | static void markudata (GCState *st, Udata *u) { | ||
| 108 | markud(u); | ||
| 109 | marktable(st, u->uv.metatable); | ||
| 110 | } | ||
| 111 | |||
| 112 | |||
| 104 | static void reallymarkobject (GCState *st, TObject *o) { | 113 | static void reallymarkobject (GCState *st, TObject *o) { |
| 105 | switch (ttype(o)) { | 114 | switch (ttype(o)) { |
| 106 | case LUA_TSTRING: | 115 | case LUA_TSTRING: |
| @@ -108,7 +117,7 @@ static void reallymarkobject (GCState *st, TObject *o) { | |||
| 108 | break; | 117 | break; |
| 109 | case LUA_TUSERDATA: | 118 | case LUA_TUSERDATA: |
| 110 | if (!isudmarked(uvalue(o))) | 119 | if (!isudmarked(uvalue(o))) |
| 111 | markud(uvalue(o)); | 120 | markudata(st, uvalue(o)); |
| 112 | break; | 121 | break; |
| 113 | case LUA_TFUNCTION: | 122 | case LUA_TFUNCTION: |
| 114 | markclosure(st, clvalue(o)); | 123 | markclosure(st, clvalue(o)); |
| @@ -156,12 +165,33 @@ static void markstacks (GCState *st) { | |||
| 156 | } | 165 | } |
| 157 | 166 | ||
| 158 | 167 | ||
| 159 | static void markudet (GCState *st) { | 168 | static void marktmu (GCState *st) { |
| 160 | Udata *u; | 169 | Udata *u; |
| 161 | for (u = G(st->L)->rootudata; u; u = u->uv.next) | ||
| 162 | marktable(st, u->uv.metatable); | ||
| 163 | for (u = G(st->L)->tmudata; u; u = u->uv.next) | 170 | for (u = G(st->L)->tmudata; u; u = u->uv.next) |
| 164 | marktable(st, u->uv.metatable); | 171 | markudata(st, u); |
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | /* move `dead' udata that need finalization to list `tmudata' */ | ||
| 176 | static void separateudata (lua_State *L) { | ||
| 177 | Udata **p = &G(L)->rootudata; | ||
| 178 | Udata *curr; | ||
| 179 | Udata *collected = NULL; /* to collect udata with gc event */ | ||
| 180 | Udata **lastcollected = &collected; | ||
| 181 | while ((curr = *p) != NULL) { | ||
| 182 | if (isudmarked(curr) || isfinalized(curr) || | ||
| 183 | (fasttm(L, curr->uv.metatable, TM_GC) == NULL)) | ||
| 184 | p = &curr->uv.next; | ||
| 185 | else { /* must call its gc method */ | ||
| 186 | *p = curr->uv.next; | ||
| 187 | curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ | ||
| 188 | *lastcollected = curr; | ||
| 189 | lastcollected = &curr->uv.next; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | /* insert collected udata with gc event into `tmudata' list */ | ||
| 193 | *lastcollected = G(L)->tmudata; | ||
| 194 | G(L)->tmudata = collected; | ||
| 165 | } | 195 | } |
| 166 | 196 | ||
| 167 | 197 | ||
| @@ -208,7 +238,6 @@ static void markall (GCState *st) { | |||
| 208 | lua_assert(hvalue(defaultmeta(st->L))->flags == cast(unsigned short, ~0)); | 238 | lua_assert(hvalue(defaultmeta(st->L))->flags == cast(unsigned short, ~0)); |
| 209 | /* table is unchanged */ | 239 | /* table is unchanged */ |
| 210 | markstacks(st); /* mark all stacks */ | 240 | markstacks(st); /* mark all stacks */ |
| 211 | markudet(st); /* mark userdata's meta tables */ | ||
| 212 | while (st->tmark) { /* traverse marked tables */ | 241 | while (st->tmark) { /* traverse marked tables */ |
| 213 | Table *h = st->tmark; /* get first table from list */ | 242 | Table *h = st->tmark; /* get first table from list */ |
| 214 | st->tmark = h->mark; /* remove it from list */ | 243 | st->tmark = h->mark; /* remove it from list */ |
| @@ -322,11 +351,10 @@ static void collecttable (lua_State *L) { | |||
| 322 | } | 351 | } |
| 323 | 352 | ||
| 324 | 353 | ||
| 354 | |||
| 325 | static void collectudata (lua_State *L) { | 355 | static void collectudata (lua_State *L) { |
| 326 | Udata **p = &G(L)->rootudata; | 356 | Udata **p = &G(L)->rootudata; |
| 327 | Udata *curr; | 357 | Udata *curr; |
| 328 | Udata *collected = NULL; /* to collect udata with gc event */ | ||
| 329 | Udata **lastcollected = &collected; | ||
| 330 | while ((curr = *p) != NULL) { | 358 | while ((curr = *p) != NULL) { |
| 331 | if (isudmarked(curr)) { | 359 | if (isudmarked(curr)) { |
| 332 | unmarkud(curr); | 360 | unmarkud(curr); |
| @@ -334,18 +362,11 @@ static void collectudata (lua_State *L) { | |||
| 334 | } | 362 | } |
| 335 | else { | 363 | else { |
| 336 | *p = curr->uv.next; | 364 | *p = curr->uv.next; |
| 337 | if (fasttm(L, curr->uv.metatable, TM_GC) != NULL) { /* gc event? */ | 365 | lua_assert(isfinalized(curr) || |
| 338 | curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ | 366 | fasttm(L, curr->uv.metatable, TM_GC) == NULL); |
| 339 | *lastcollected = curr; | 367 | luaM_free(L, curr, sizeudata(curr->uv.len & (~(size_t)3))); |
| 340 | lastcollected = &curr->uv.next; | ||
| 341 | } | ||
| 342 | else /* no gc event; delete udata */ | ||
| 343 | luaM_free(L, curr, sizeudata(curr->uv.len)); | ||
| 344 | } | 368 | } |
| 345 | } | 369 | } |
| 346 | /* insert collected udata with gc event into `tmudata' list */ | ||
| 347 | *lastcollected = G(L)->tmudata; | ||
| 348 | G(L)->tmudata = collected; | ||
| 349 | } | 370 | } |
| 350 | 371 | ||
| 351 | 372 | ||
| @@ -395,44 +416,27 @@ static void do1gcTM (lua_State *L, Udata *udata) { | |||
| 395 | } | 416 | } |
| 396 | 417 | ||
| 397 | 418 | ||
| 398 | static void unprotectedcallGCTM (lua_State *L, void *pu) { | 419 | static void callGCTM (lua_State *L) { |
| 399 | luaD_checkstack(L, 3); | 420 | int oldah = L->allowhooks; |
| 421 | L->allowhooks = 0; /* stop debug hooks during GC tag methods */ | ||
| 400 | L->top++; /* reserve space to keep udata while runs its gc method */ | 422 | L->top++; /* reserve space to keep udata while runs its gc method */ |
| 401 | while (G(L)->tmudata != NULL) { | 423 | while (G(L)->tmudata != NULL) { |
| 402 | Udata *udata = G(L)->tmudata; | 424 | Udata *udata = G(L)->tmudata; |
| 403 | G(L)->tmudata = udata->uv.next; /* remove udata from list */ | 425 | G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ |
| 404 | *(Udata **)pu = udata; /* keep a reference to it (in case of errors) */ | 426 | udata->uv.next = G(L)->rootudata; /* return it to `root' list */ |
| 405 | setuvalue(L->top - 1, udata); /* and on stack (in case of recursive GC) */ | ||
| 406 | udata->uv.next = G(L)->rootudata; /* resurect it */ | ||
| 407 | G(L)->rootudata = udata; | 427 | G(L)->rootudata = udata; |
| 428 | setuvalue(L->top - 1, udata); /* keep a reference to it */ | ||
| 429 | unmarkud(udata); | ||
| 430 | markfinalized(udata); | ||
| 408 | do1gcTM(L, udata); | 431 | do1gcTM(L, udata); |
| 409 | /* mark udata as finalized (default meta table) */ | ||
| 410 | uvalue(L->top-1)->uv.metatable = hvalue(defaultmeta(L)); | ||
| 411 | unmarkud(uvalue(L->top-1)); | ||
| 412 | } | 432 | } |
| 413 | L->top--; | 433 | L->top--; |
| 414 | } | ||
| 415 | |||
| 416 | |||
| 417 | static void callGCTM (lua_State *L) { | ||
| 418 | int oldah = L->allowhooks; | ||
| 419 | L->allowhooks = 0; /* stop debug hooks during GC tag methods */ | ||
| 420 | while (G(L)->tmudata != NULL) { | ||
| 421 | Udata *udata; | ||
| 422 | if (luaD_runprotected(L, unprotectedcallGCTM, &udata) != 0) { | ||
| 423 | /* `udata' generated an error during its gc */ | ||
| 424 | /* mark it as finalized (default meta table) */ | ||
| 425 | udata->uv.metatable = hvalue(defaultmeta(L)); | ||
| 426 | } | ||
| 427 | } | ||
| 428 | L->allowhooks = oldah; /* restore hooks */ | 434 | L->allowhooks = oldah; /* restore hooks */ |
| 429 | } | 435 | } |
| 430 | 436 | ||
| 431 | 437 | ||
| 432 | void luaC_callallgcTM (lua_State *L) { | 438 | void luaC_callallgcTM (lua_State *L) { |
| 433 | lua_assert(G(L)->tmudata == NULL); | 439 | separateudata(L); |
| 434 | G(L)->tmudata = G(L)->rootudata; /* all udata must be collected */ | ||
| 435 | G(L)->rootudata = NULL; | ||
| 436 | callGCTM(L); /* call their GC tag methods */ | 440 | callGCTM(L); /* call their GC tag methods */ |
| 437 | } | 441 | } |
| 438 | 442 | ||
| @@ -452,7 +456,10 @@ void luaC_collectgarbage (lua_State *L) { | |||
| 452 | st.L = L; | 456 | st.L = L; |
| 453 | st.tmark = NULL; | 457 | st.tmark = NULL; |
| 454 | st.toclear = NULL; | 458 | st.toclear = NULL; |
| 455 | markall(&st); | 459 | markall(&st); /* mark all reachable objects */ |
| 460 | separateudata(L); /* separate userdata to be preserved */ | ||
| 461 | marktmu(&st); /* mark `preserved' userdata */ | ||
| 462 | markall(&st); /* remark */ | ||
| 456 | cleartables(st.toclear); | 463 | cleartables(st.toclear); |
| 457 | luaC_collect(L, 0); | 464 | luaC_collect(L, 0); |
| 458 | checkMbuffer(L); | 465 | checkMbuffer(L); |
