diff options
Diffstat (limited to 'lgc.c')
| -rw-r--r-- | lgc.c | 112 |
1 files changed, 50 insertions, 62 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.245 2018/01/28 15:13:26 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.248 2018/02/19 16:02:25 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 | */ |
| @@ -110,13 +110,32 @@ static lu_mem atomic (lua_State *L); | |||
| 110 | #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) | 110 | #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) |
| 111 | 111 | ||
| 112 | 112 | ||
| 113 | static GCObject **getgclist (GCObject *o) { | ||
| 114 | switch (o->tt) { | ||
| 115 | case LUA_TTABLE: return &gco2t(o)->gclist; | ||
| 116 | case LUA_TLCL: return &gco2lcl(o)->gclist; | ||
| 117 | case LUA_TCCL: return &gco2ccl(o)->gclist; | ||
| 118 | case LUA_TTHREAD: return &gco2th(o)->gclist; | ||
| 119 | case LUA_TPROTO: return &gco2p(o)->gclist; | ||
| 120 | default: lua_assert(0); return 0; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 113 | /* | 125 | /* |
| 114 | ** link collectable object 'o' into list pointed by 'p' | 126 | ** Link a collectable object 'o' with a known type into list pointed by 'p'. |
| 115 | */ | 127 | */ |
| 116 | #define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) | 128 | #define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) |
| 117 | 129 | ||
| 118 | 130 | ||
| 119 | /* | 131 | /* |
| 132 | ** Link a generic collectable object 'o' into list pointed by 'p'. | ||
| 133 | */ | ||
| 134 | #define linkobjgclist(o,p) (*getgclist(o) = (p), (p) = obj2gco(o)) | ||
| 135 | |||
| 136 | |||
| 137 | |||
| 138 | /* | ||
| 120 | ** Clear keys for empty entries in tables. If entry is empty | 139 | ** Clear keys for empty entries in tables. If entry is empty |
| 121 | ** and its key is not marked, mark its entry as dead. This allows the | 140 | ** and its key is not marked, mark its entry as dead. This allows the |
| 122 | ** collection of the key, but keeps its entry in the table (its removal | 141 | ** collection of the key, but keeps its entry in the table (its removal |
| @@ -175,14 +194,14 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
| 175 | ** barrier that moves collector backward, that is, mark the black object | 194 | ** barrier that moves collector backward, that is, mark the black object |
| 176 | ** pointing to a white object as gray again. | 195 | ** pointing to a white object as gray again. |
| 177 | */ | 196 | */ |
| 178 | void luaC_barrierback_ (lua_State *L, Table *t) { | 197 | void luaC_barrierback_ (lua_State *L, GCObject *o) { |
| 179 | global_State *g = G(L); | 198 | global_State *g = G(L); |
| 180 | lua_assert(isblack(t) && !isdead(g, t)); | 199 | lua_assert(isblack(o) && !isdead(g, o)); |
| 181 | lua_assert(g->gckind != KGC_GEN || (isold(t) && getage(t) != G_TOUCHED1)); | 200 | lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1)); |
| 182 | if (getage(t) != G_TOUCHED2) /* not already in gray list? */ | 201 | if (getage(o) != G_TOUCHED2) /* not already in gray list? */ |
| 183 | linkgclist(t, g->grayagain); /* link it in 'grayagain' */ | 202 | linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */ |
| 184 | black2gray(t); /* make table gray (again) */ | 203 | black2gray(o); /* make table gray (again) */ |
| 185 | setage(t, G_TOUCHED1); /* touched in current cycle */ | 204 | setage(o, G_TOUCHED1); /* touched in current cycle */ |
| 186 | } | 205 | } |
| 187 | 206 | ||
| 188 | 207 | ||
| @@ -276,24 +295,9 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 276 | markvalue(g, uv->v); /* mark its content */ | 295 | markvalue(g, uv->v); /* mark its content */ |
| 277 | break; | 296 | break; |
| 278 | } | 297 | } |
| 279 | case LUA_TLCL: { | 298 | case LUA_TLCL: case LUA_TCCL: case LUA_TTABLE: |
| 280 | linkgclist(gco2lcl(o), g->gray); | 299 | case LUA_TTHREAD: case LUA_TPROTO: { |
| 281 | break; | 300 | linkobjgclist(o, g->gray); |
| 282 | } | ||
| 283 | case LUA_TCCL: { | ||
| 284 | linkgclist(gco2ccl(o), g->gray); | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | case LUA_TTABLE: { | ||
| 288 | linkgclist(gco2t(o), g->gray); | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | case LUA_TTHREAD: { | ||
| 292 | linkgclist(gco2th(o), g->gray); | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | case LUA_TPROTO: { | ||
| 296 | linkgclist(gco2p(o), g->gray); | ||
| 297 | break; | 301 | break; |
| 298 | } | 302 | } |
| 299 | default: lua_assert(0); break; | 303 | default: lua_assert(0); break; |
| @@ -605,34 +609,18 @@ static int traversethread (global_State *g, lua_State *th) { | |||
| 605 | static lu_mem propagatemark (global_State *g) { | 609 | static lu_mem propagatemark (global_State *g) { |
| 606 | GCObject *o = g->gray; | 610 | GCObject *o = g->gray; |
| 607 | gray2black(o); | 611 | gray2black(o); |
| 612 | g->gray = *getgclist(o); /* remove from 'gray' list */ | ||
| 608 | switch (o->tt) { | 613 | switch (o->tt) { |
| 609 | case LUA_TTABLE: { | 614 | case LUA_TTABLE: return traversetable(g, gco2t(o)); |
| 610 | Table *h = gco2t(o); | 615 | case LUA_TLCL: return traverseLclosure(g, gco2lcl(o)); |
| 611 | g->gray = h->gclist; /* remove from 'gray' list */ | 616 | case LUA_TCCL: return traverseCclosure(g, gco2ccl(o)); |
| 612 | return traversetable(g, h); | 617 | case LUA_TPROTO: return traverseproto(g, gco2p(o)); |
| 613 | } | ||
| 614 | case LUA_TLCL: { | ||
| 615 | LClosure *cl = gco2lcl(o); | ||
| 616 | g->gray = cl->gclist; /* remove from 'gray' list */ | ||
| 617 | return traverseLclosure(g, cl); | ||
| 618 | } | ||
| 619 | case LUA_TCCL: { | ||
| 620 | CClosure *cl = gco2ccl(o); | ||
| 621 | g->gray = cl->gclist; /* remove from 'gray' list */ | ||
| 622 | return traverseCclosure(g, cl); | ||
| 623 | } | ||
| 624 | case LUA_TTHREAD: { | 618 | case LUA_TTHREAD: { |
| 625 | lua_State *th = gco2th(o); | 619 | lua_State *th = gco2th(o); |
| 626 | g->gray = th->gclist; /* remove from 'gray' list */ | ||
| 627 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 620 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
| 628 | black2gray(o); | 621 | black2gray(o); |
| 629 | return traversethread(g, th); | 622 | return traversethread(g, th); |
| 630 | } | 623 | } |
| 631 | case LUA_TPROTO: { | ||
| 632 | Proto *p = gco2p(o); | ||
| 633 | g->gray = p->gclist; /* remove from 'gray' list */ | ||
| 634 | return traverseproto(g, p); | ||
| 635 | } | ||
| 636 | default: lua_assert(0); return 0; | 624 | default: lua_assert(0); return 0; |
| 637 | } | 625 | } |
| 638 | } | 626 | } |
| @@ -1069,8 +1057,8 @@ static void whitelist (global_State *g, GCObject *p) { | |||
| 1069 | ** Correct a list of gray objects. Because this correction is | 1057 | ** Correct a list of gray objects. Because this correction is |
| 1070 | ** done after sweeping, young objects can be white and still | 1058 | ** done after sweeping, young objects can be white and still |
| 1071 | ** be in the list. They are only removed. | 1059 | ** be in the list. They are only removed. |
| 1072 | ** For tables, advance 'touched1' to 'touched2'; 'touched2' objects | 1060 | ** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2' |
| 1073 | ** become regular old and are removed from the list. | 1061 | ** objects become regular old and are removed from the list. |
| 1074 | ** For threads, just remove white ones from the list. | 1062 | ** For threads, just remove white ones from the list. |
| 1075 | */ | 1063 | */ |
| 1076 | static GCObject **correctgraylist (GCObject **p) { | 1064 | static GCObject **correctgraylist (GCObject **p) { |
| @@ -1078,21 +1066,21 @@ static GCObject **correctgraylist (GCObject **p) { | |||
| 1078 | while ((curr = *p) != NULL) { | 1066 | while ((curr = *p) != NULL) { |
| 1079 | switch (curr->tt) { | 1067 | switch (curr->tt) { |
| 1080 | case LUA_TTABLE: { | 1068 | case LUA_TTABLE: { |
| 1081 | Table *h = gco2t(curr); | 1069 | GCObject **next = getgclist(curr); |
| 1082 | if (getage(h) == G_TOUCHED1) { /* touched in this cycle? */ | 1070 | if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ |
| 1083 | lua_assert(isgray(h)); | 1071 | lua_assert(isgray(curr)); |
| 1084 | gray2black(h); /* make it black, for next barrier */ | 1072 | gray2black(curr); /* make it black, for next barrier */ |
| 1085 | changeage(h, G_TOUCHED1, G_TOUCHED2); | 1073 | changeage(curr, G_TOUCHED1, G_TOUCHED2); |
| 1086 | p = &h->gclist; /* go to next element */ | 1074 | p = next; /* go to next element */ |
| 1087 | } | 1075 | } |
| 1088 | else { | 1076 | else { |
| 1089 | if (!iswhite(h)) { | 1077 | if (!iswhite(curr)) { |
| 1090 | lua_assert(isold(h)); | 1078 | lua_assert(isold(curr)); |
| 1091 | if (getage(h) == G_TOUCHED2) | 1079 | if (getage(curr) == G_TOUCHED2) |
| 1092 | changeage(h, G_TOUCHED2, G_OLD); | 1080 | changeage(curr, G_TOUCHED2, G_OLD); |
| 1093 | gray2black(h); /* make it black */ | 1081 | gray2black(curr); /* make it black */ |
| 1094 | } | 1082 | } |
| 1095 | *p = h->gclist; /* remove 'curr' from gray list */ | 1083 | *p = *next; /* remove 'curr' from gray list */ |
| 1096 | } | 1084 | } |
| 1097 | break; | 1085 | break; |
| 1098 | } | 1086 | } |
