diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-11 15:41:09 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-11 15:41:09 -0300 |
| commit | a3d36fe283c09d4e56474da98f22d13162cc9fec (patch) | |
| tree | 1f6e2ed56d50dc14aa669fa5f31a63755abd4553 /lgc.c | |
| parent | 9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20 (diff) | |
| download | lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.tar.gz lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.tar.bz2 lua-a3d36fe283c09d4e56474da98f22d13162cc9fec.zip | |
Upvalues collected like everything else (with mark-sweep) instead
of reference count (simpler and better for generational mode)
Diffstat (limited to 'lgc.c')
| -rw-r--r-- | lgc.c | 89 |
1 files changed, 32 insertions, 57 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.218 2017/04/06 13:08:56 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.219 2017/04/10 13:33:04 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 | */ |
| @@ -179,25 +179,11 @@ void luaC_barrierback_ (lua_State *L, Table *t) { | |||
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | 181 | ||
| 182 | /* | ||
| 183 | ** barrier for assignments to closed upvalues. Because upvalues are | ||
| 184 | ** shared among closures, it is impossible to know the color of all | ||
| 185 | ** closures pointing to it. So, we assume that the object being assigned | ||
| 186 | ** must be marked. | ||
| 187 | */ | ||
| 188 | void luaC_upvalbarrier_ (lua_State *L, GCObject *o) { | ||
| 189 | global_State *g = G(L); | ||
| 190 | if (keepinvariant(g) && !isold(o)) { | ||
| 191 | markobject(g, o); | ||
| 192 | setage(o, G_OLD0); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | void luaC_fix (lua_State *L, GCObject *o) { | 182 | void luaC_fix (lua_State *L, GCObject *o) { |
| 198 | global_State *g = G(L); | 183 | global_State *g = G(L); |
| 199 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ | 184 | lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ |
| 200 | white2gray(o); /* they will be gray forever */ | 185 | white2gray(o); /* they will be gray forever */ |
| 186 | setage(o, G_OLD); /* and old forever */ | ||
| 201 | g->allgc = o->next; /* remove object from 'allgc' list */ | 187 | g->allgc = o->next; /* remove object from 'allgc' list */ |
| 202 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ | 188 | o->next = g->fixedgc; /* link it to 'fixedgc' list */ |
| 203 | g->fixedgc = o; | 189 | g->fixedgc = o; |
| @@ -230,10 +216,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { | |||
| 230 | 216 | ||
| 231 | 217 | ||
| 232 | /* | 218 | /* |
| 233 | ** mark an object. Userdata, strings, and closed upvalues are visited | 219 | ** Mark an object. Userdata, strings, and closed upvalues are visited |
| 234 | ** and turned black here. Other objects are marked gray and added | 220 | ** and turned black here. Other objects are marked gray and added |
| 235 | ** to appropriate list to be visited (and turned black) later. (Open | 221 | ** to appropriate list to be visited (and turned black) later. (Open |
| 236 | ** upvalues are already linked in 'headuv' list.) | 222 | ** upvalues are already linked in 'headuv' list. They are kept gray |
| 223 | ** to avoid barriers, as their values will be revisited by the thread.) | ||
| 237 | */ | 224 | */ |
| 238 | static void reallymarkobject (global_State *g, GCObject *o) { | 225 | static void reallymarkobject (global_State *g, GCObject *o) { |
| 239 | reentry: | 226 | reentry: |
| @@ -261,6 +248,14 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 261 | } | 248 | } |
| 262 | break; | 249 | break; |
| 263 | } | 250 | } |
| 251 | case LUA_TUPVAL: { | ||
| 252 | UpVal *uv = gco2upv(o); | ||
| 253 | g->GCmemtrav += sizeof(UpVal); | ||
| 254 | if (!upisopen(uv)) /* open upvalues are kept gray */ | ||
| 255 | gray2black(o); | ||
| 256 | markvalue(g, uv->v); /* mark its content */ | ||
| 257 | break; | ||
| 258 | } | ||
| 264 | case LUA_TLCL: { | 259 | case LUA_TLCL: { |
| 265 | linkgclist(gco2lcl(o), g->gray); | 260 | linkgclist(gco2lcl(o), g->gray); |
| 266 | break; | 261 | break; |
| @@ -324,10 +319,8 @@ static void remarkupvals (global_State *g) { | |||
| 324 | *p = thread->twups; /* remove thread from the list */ | 319 | *p = thread->twups; /* remove thread from the list */ |
| 325 | thread->twups = thread; /* mark that it is out of list */ | 320 | thread->twups = thread; /* mark that it is out of list */ |
| 326 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | 321 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { |
| 327 | if (uv->u.open.touched) { | 322 | if (!iswhite(uv)) /* upvalue already visited? */ |
| 328 | markvalue(g, uv->v); /* remark upvalue's value */ | 323 | markvalue(g, uv->v); /* mark its value */ |
| 329 | uv->u.open.touched = 0; | ||
| 330 | } | ||
| 331 | } | 324 | } |
| 332 | } | 325 | } |
| 333 | } | 326 | } |
| @@ -516,22 +509,15 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
| 516 | } | 509 | } |
| 517 | 510 | ||
| 518 | /* | 511 | /* |
| 519 | ** open upvalues point to values in a thread, so those values should | 512 | ** Traverse a Lua closure, marking its prototype and its upvalues. |
| 520 | ** be marked when the thread is traversed except in the atomic phase | 513 | ** (Both can be NULL while closure is being created.) |
| 521 | ** (because then the value cannot be changed by the thread and the | ||
| 522 | ** thread may not be traversed again) | ||
| 523 | */ | 514 | */ |
| 524 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 515 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
| 525 | int i; | 516 | int i; |
| 526 | markobjectN(g, cl->p); /* mark its prototype */ | 517 | markobjectN(g, cl->p); /* mark its prototype */ |
| 527 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ | 518 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
| 528 | UpVal *uv = cl->upvals[i]; | 519 | UpVal *uv = cl->upvals[i]; |
| 529 | if (uv != NULL) { /* can be NULL while closure is being built */ | 520 | markobjectN(g, uv); /* mark upvalue */ |
| 530 | if (upisopen(uv) && g->gcstate != GCSatomic) | ||
| 531 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ | ||
| 532 | else | ||
| 533 | markvalue(g, uv->v); | ||
| 534 | } | ||
| 535 | } | 521 | } |
| 536 | return sizeLclosure(cl->nupvalues); | 522 | return sizeLclosure(cl->nupvalues); |
| 537 | } | 523 | } |
| @@ -569,7 +555,6 @@ static lu_mem traversethread (global_State *g, lua_State *th) { | |||
| 569 | static void propagatemark (global_State *g) { | 555 | static void propagatemark (global_State *g) { |
| 570 | lu_mem size; | 556 | lu_mem size; |
| 571 | GCObject *o = g->gray; | 557 | GCObject *o = g->gray; |
| 572 | lua_assert(ongraylist(o)); | ||
| 573 | gray2black(o); | 558 | gray2black(o); |
| 574 | switch (o->tt) { | 559 | switch (o->tt) { |
| 575 | case LUA_TTABLE: { | 560 | case LUA_TTABLE: { |
| @@ -683,26 +668,10 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
| 683 | } | 668 | } |
| 684 | 669 | ||
| 685 | 670 | ||
| 686 | /* | 671 | static void freeupval (lua_State *L, UpVal *uv) { |
| 687 | ** Decrement the reference count of an upvalue. If it goes to zero and | 672 | if (upisopen(uv)) |
| 688 | ** upvalue is closed, delete it. | 673 | luaF_unlinkupval(uv); |
| 689 | */ | 674 | luaM_free(L, uv); |
| 690 | void luaC_upvdeccount (lua_State *L, UpVal *uv) { | ||
| 691 | lua_assert(uv->refcount > 0); | ||
| 692 | uv->refcount--; | ||
| 693 | if (uv->refcount == 0 && !upisopen(uv)) | ||
| 694 | luaM_free(L, uv); | ||
| 695 | } | ||
| 696 | |||
| 697 | |||
| 698 | static void freeLclosure (lua_State *L, LClosure *cl) { | ||
| 699 | int i; | ||
| 700 | for (i = 0; i < cl->nupvalues; i++) { | ||
| 701 | UpVal *uv = cl->upvals[i]; | ||
| 702 | if (uv) | ||
| 703 | luaC_upvdeccount(L, uv); | ||
| 704 | } | ||
| 705 | luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); | ||
| 706 | } | 675 | } |
| 707 | 676 | ||
| 708 | 677 | ||
| @@ -711,8 +680,11 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 711 | case LUA_TPROTO: | 680 | case LUA_TPROTO: |
| 712 | luaF_freeproto(L, gco2p(o)); | 681 | luaF_freeproto(L, gco2p(o)); |
| 713 | break; | 682 | break; |
| 683 | case LUA_TUPVAL: | ||
| 684 | freeupval(L, gco2upv(o)); | ||
| 685 | break; | ||
| 714 | case LUA_TLCL: | 686 | case LUA_TLCL: |
| 715 | freeLclosure(L, gco2lcl(o)); | 687 | luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); |
| 716 | break; | 688 | break; |
| 717 | case LUA_TCCL: | 689 | case LUA_TCCL: |
| 718 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); | 690 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); |
| @@ -1144,14 +1116,14 @@ static void correctgraylists (global_State *g) { | |||
| 1144 | 1116 | ||
| 1145 | 1117 | ||
| 1146 | /* | 1118 | /* |
| 1147 | ** Mark 'old1' objects when starting a new young collection. ('old1' | 1119 | ** Mark 'old1' objects when starting a new young collection. (Threads |
| 1148 | ** tables are always black, threads are always gray.) | 1120 | ** and open upvalues are always gray, and do not need to be marked. |
| 1121 | ** All other old objects are black.) | ||
| 1149 | */ | 1122 | */ |
| 1150 | static void markold (global_State *g, GCObject *from, GCObject *to) { | 1123 | static void markold (global_State *g, GCObject *from, GCObject *to) { |
| 1151 | GCObject *p; | 1124 | GCObject *p; |
| 1152 | for (p = from; p != to; p = p->next) { | 1125 | for (p = from; p != to; p = p->next) { |
| 1153 | if (getage(p) == G_OLD1) { | 1126 | if (getage(p) == G_OLD1) { |
| 1154 | lua_assert((p->tt == LUA_TTHREAD) ? isgray(p) : isblack(p)); | ||
| 1155 | if (isblack(p)) { | 1127 | if (isblack(p)) { |
| 1156 | black2gray(p); /* should be '2white', but gray works too */ | 1128 | black2gray(p); /* should be '2white', but gray works too */ |
| 1157 | reallymarkobject(g, p); | 1129 | reallymarkobject(g, p); |
| @@ -1228,6 +1200,8 @@ static void entergen (lua_State *L, global_State *g) { | |||
| 1228 | 1200 | ||
| 1229 | sweep2old(L, &g->tobefnz); | 1201 | sweep2old(L, &g->tobefnz); |
| 1230 | 1202 | ||
| 1203 | setage(g->mainthread, G_OLD); | ||
| 1204 | |||
| 1231 | finishgencycle(L, g); | 1205 | finishgencycle(L, g); |
| 1232 | g->gckind = KGC_GEN; | 1206 | g->gckind = KGC_GEN; |
| 1233 | } | 1207 | } |
| @@ -1282,6 +1256,7 @@ static void genstep (lua_State *L, global_State *g) { | |||
| 1282 | youngcollection(L, g); | 1256 | youngcollection(L, g); |
| 1283 | mem = gettotalbytes(g); | 1257 | mem = gettotalbytes(g); |
| 1284 | luaE_setdebt(g, -((mem / 100) * 20)); | 1258 | luaE_setdebt(g, -((mem / 100) * 20)); |
| 1259 | lua_checkmemory(L); | ||
| 1285 | } | 1260 | } |
| 1286 | 1261 | ||
| 1287 | 1262 | ||
