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 /lgc.c | |
parent | 5023aaee0aa7cb741dc112deec7dc9469d804cd5 (diff) | |
download | lua-ca2ceef659ed013277485acd0b6058a536649730.tar.gz lua-ca2ceef659ed013277485acd0b6058a536649730.tar.bz2 lua-ca2ceef659ed013277485acd0b6058a536649730.zip |
simpler solution for finalizing udata
Diffstat (limited to 'lgc.c')
-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); |