diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-10-03 13:22:05 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-10-03 13:22:05 -0300 |
commit | bc90cf4b8313d88adc0c6e45961e3b4881a9566a (patch) | |
tree | c9756e135aad46b17ca4a7a30293bb2e144a1a69 | |
parent | d79190e27f6b43a61e490800ccae1ea4e874e7cd (diff) | |
download | lua-bc90cf4b8313d88adc0c6e45961e3b4881a9566a.tar.gz lua-bc90cf4b8313d88adc0c6e45961e3b4881a9566a.tar.bz2 lua-bc90cf4b8313d88adc0c6e45961e3b4881a9566a.zip |
retraverse all gray lists together to avoid traversing some weak
tables twice (as they may change lists when traversed)
-rw-r--r-- | lgc.c | 48 |
1 files changed, 34 insertions, 14 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.110 2011/09/19 17:03:38 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.112 2011/09/24 21:12:01 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 | */ |
@@ -153,7 +153,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
153 | */ | 153 | */ |
154 | void luaC_barrierback_ (lua_State *L, GCObject *o) { | 154 | void luaC_barrierback_ (lua_State *L, GCObject *o) { |
155 | global_State *g = G(L); | 155 | global_State *g = G(L); |
156 | lua_assert(isblack(o) && !isdead(g, o)); | 156 | lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE); |
157 | black2gray(o); /* make object gray (again) */ | 157 | black2gray(o); /* make object gray (again) */ |
158 | gco2t(o)->gclist = g->grayagain; | 158 | gco2t(o)->gclist = g->grayagain; |
159 | g->grayagain = o; | 159 | g->grayagain = o; |
@@ -343,6 +343,9 @@ static void markroot (global_State *g) { | |||
343 | 343 | ||
344 | static void traverseweakvalue (global_State *g, Table *h) { | 344 | static void traverseweakvalue (global_State *g, Table *h) { |
345 | Node *n, *limit = gnode(h, sizenode(h)); | 345 | Node *n, *limit = gnode(h, sizenode(h)); |
346 | /* if there is array part, assume it may have white values (do not | ||
347 | traverse it just to check) */ | ||
348 | int hasclears = (h->sizearray > 0); | ||
346 | for (n = gnode(h, 0); n < limit; n++) { | 349 | for (n = gnode(h, 0); n < limit; n++) { |
347 | checkdeadkey(n); | 350 | checkdeadkey(n); |
348 | if (ttisnil(gval(n))) /* entry is empty? */ | 351 | if (ttisnil(gval(n))) /* entry is empty? */ |
@@ -350,9 +353,14 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
350 | else { | 353 | else { |
351 | lua_assert(!ttisnil(gkey(n))); | 354 | lua_assert(!ttisnil(gkey(n))); |
352 | markvalue(g, gkey(n)); /* mark key */ | 355 | markvalue(g, gkey(n)); /* mark key */ |
356 | if (!hasclears && iscleared(gval(n))) /* is there a white value? */ | ||
357 | hasclears = 1; /* table will have to be cleared */ | ||
353 | } | 358 | } |
354 | } | 359 | } |
355 | linktable(h, &g->weak); /* link into appropriate list */ | 360 | if (hasclears) |
361 | linktable(h, &g->weak); /* has to be cleared later */ | ||
362 | else /* no white values */ | ||
363 | linktable(h, &g->grayagain); /* no need to clean */ | ||
356 | } | 364 | } |
357 | 365 | ||
358 | 366 | ||
@@ -531,11 +539,26 @@ static void propagateall (global_State *g) { | |||
531 | } | 539 | } |
532 | 540 | ||
533 | 541 | ||
534 | static void traverselistofgrays (global_State *g, GCObject **l) { | 542 | static void propagatelist (global_State *g, GCObject *l) { |
535 | lua_assert(g->gray == NULL); /* no grays left */ | 543 | lua_assert(g->gray == NULL); /* no grays left */ |
536 | g->gray = *l; /* now 'l' is new gray list */ | 544 | g->gray = l; |
537 | *l = NULL; | 545 | propagateall(g); /* traverse all elements from 'l' */ |
538 | propagateall(g); | 546 | } |
547 | |||
548 | /* | ||
549 | ** retraverse all gray lists. Because tables may be reinserted in other | ||
550 | ** lists when traversed, traverse the original lists to avoid traversing | ||
551 | ** twice the same table (which is not wrong, but inefficient) | ||
552 | */ | ||
553 | static void retraversegrays (global_State *g) { | ||
554 | GCObject *weak = g->weak; /* save original lists */ | ||
555 | GCObject *grayagain = g->grayagain; | ||
556 | GCObject *ephemeron = g->ephemeron; | ||
557 | g->weak = g->grayagain = g->ephemeron = NULL; | ||
558 | propagateall(g); /* traverse main gray list */ | ||
559 | propagatelist(g, grayagain); | ||
560 | propagatelist(g, weak); | ||
561 | propagatelist(g, ephemeron); | ||
539 | } | 562 | } |
540 | 563 | ||
541 | 564 | ||
@@ -890,10 +913,7 @@ static void atomic (lua_State *L) { | |||
890 | /* remark occasional upvalues of (maybe) dead threads */ | 913 | /* remark occasional upvalues of (maybe) dead threads */ |
891 | remarkupvals(g); | 914 | remarkupvals(g); |
892 | /* traverse objects caught by write barrier and by 'remarkupvals' */ | 915 | /* traverse objects caught by write barrier and by 'remarkupvals' */ |
893 | propagateall(g); | 916 | retraversegrays(g); |
894 | traverselistofgrays(g, &g->weak); /* remark weak tables */ | ||
895 | traverselistofgrays(g, &g->grayagain); /* remark gray again */ | ||
896 | traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ | ||
897 | convergeephemerons(g); | 917 | convergeephemerons(g); |
898 | /* at this point, all strongly accessible objects are marked. */ | 918 | /* at this point, all strongly accessible objects are marked. */ |
899 | /* clear values from weak tables, before checking finalizers */ | 919 | /* clear values from weak tables, before checking finalizers */ |
@@ -904,11 +924,11 @@ static void atomic (lua_State *L) { | |||
904 | markbeingfnz(g); /* mark userdata that will be finalized */ | 924 | markbeingfnz(g); /* mark userdata that will be finalized */ |
905 | propagateall(g); /* remark, to propagate `preserveness' */ | 925 | propagateall(g); /* remark, to propagate `preserveness' */ |
906 | convergeephemerons(g); | 926 | convergeephemerons(g); |
907 | /* at this point, all accessible objects are marked. */ | 927 | /* at this point, all resurrected objects are marked. */ |
908 | /* remove collected objects from weak tables */ | 928 | /* remove dead objects from weak tables */ |
909 | clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ | 929 | clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ |
910 | clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ | 930 | clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ |
911 | /* clear values from weak tables accessible from separated objects */ | 931 | /* clear values from resurrected weak tables */ |
912 | clearvalues(g->weak, origweak); | 932 | clearvalues(g->weak, origweak); |
913 | clearvalues(g->allweak, origall); | 933 | clearvalues(g->allweak, origall); |
914 | g->sweepstrgc = 0; /* prepare to sweep strings */ | 934 | g->sweepstrgc = 0; /* prepare to sweep strings */ |