diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-09-03 13:54:41 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-09-03 13:54:41 -0300 |
| commit | 0a6b58c3aac2741cf1c84c44d168c73e3e478c4d (patch) | |
| tree | 31e96d3c94b2c01c75820463298580b2f05a8f79 | |
| parent | 979a663d2a8200591e263c9a7643b7379b2d7ac9 (diff) | |
| download | lua-0a6b58c3aac2741cf1c84c44d168c73e3e478c4d.tar.gz lua-0a6b58c3aac2741cf1c84c44d168c73e3e478c4d.tar.bz2 lua-0a6b58c3aac2741cf1c84c44d168c73e3e478c4d.zip | |
weak tables that must be retraversed are kept in 'grayagain' list
until atomic phase (instead of going to their special lists) +
more comments
| -rw-r--r-- | lgc.c | 80 |
1 files changed, 38 insertions, 42 deletions
| @@ -335,12 +335,18 @@ static void restartcollection (global_State *g) { | |||
| 335 | ** ======================================================= | 335 | ** ======================================================= |
| 336 | */ | 336 | */ |
| 337 | 337 | ||
| 338 | /* | ||
| 339 | ** Traverse a table with weak values and link it to proper list. During | ||
| 340 | ** propagate phase, keep it in 'grayagain' list, to be revisited in the | ||
| 341 | ** atomic phase. In the atomic phase, if table has any white value, | ||
| 342 | ** put it in 'weak' list, to be cleared. | ||
| 343 | */ | ||
| 338 | static void traverseweakvalue (global_State *g, Table *h) { | 344 | static void traverseweakvalue (global_State *g, Table *h) { |
| 339 | Node *n, *limit = gnodelast(h); | 345 | Node *n, *limit = gnodelast(h); |
| 340 | /* if there is array part, assume it may have white values (do not | 346 | /* if there is array part, assume it may have white values (it is not |
| 341 | traverse it just to check) */ | 347 | worth traversing it now just to check) */ |
| 342 | int hasclears = (h->sizearray > 0); | 348 | int hasclears = (h->sizearray > 0); |
| 343 | for (n = gnode(h, 0); n < limit; n++) { | 349 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
| 344 | checkdeadkey(n); | 350 | checkdeadkey(n); |
| 345 | if (ttisnil(gval(n))) /* entry is empty? */ | 351 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 346 | removeentry(n); /* remove it */ | 352 | removeentry(n); /* remove it */ |
| @@ -351,20 +357,30 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
| 351 | hasclears = 1; /* table will have to be cleared */ | 357 | hasclears = 1; /* table will have to be cleared */ |
| 352 | } | 358 | } |
| 353 | } | 359 | } |
| 354 | if (hasclears) | 360 | if (g->gcstate == GCSpropagate) |
| 361 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | ||
| 362 | else if (hasclears) | ||
| 355 | linkgclist(h, g->weak); /* has to be cleared later */ | 363 | linkgclist(h, g->weak); /* has to be cleared later */ |
| 356 | else /* no white values */ | ||
| 357 | linkgclist(h, g->grayagain); /* no need to clean */ | ||
| 358 | } | 364 | } |
| 359 | 365 | ||
| 360 | 366 | ||
| 367 | /* | ||
| 368 | ** Traverse an ephemeron table and link it to proper list. Returns true | ||
| 369 | ** iff any object was marked during this traversal (which implies that | ||
| 370 | ** convergence has to continue). During propagation phase, keep table | ||
| 371 | ** in 'grayagain' list, to be visited again in the atomic phase. In | ||
| 372 | ** the atomic phase, if table has any white->white entry, it has to | ||
| 373 | ** be revisited during ephemeron convergence (as that key may turn | ||
| 374 | ** black). Otherwise, if it has any white key, table has to be cleared | ||
| 375 | ** (in the atomic phase). | ||
| 376 | */ | ||
| 361 | static int traverseephemeron (global_State *g, Table *h) { | 377 | static int traverseephemeron (global_State *g, Table *h) { |
| 362 | int marked = 0; /* true if an object is marked in this traversal */ | 378 | int marked = 0; /* true if an object is marked in this traversal */ |
| 363 | int hasclears = 0; /* true if table has white keys */ | 379 | int hasclears = 0; /* true if table has white keys */ |
| 364 | int prop = 0; /* true if table has entry "white-key -> white-value" */ | 380 | int hasww = 0; /* true if table has entry "white-key -> white-value" */ |
| 365 | Node *n, *limit = gnodelast(h); | 381 | Node *n, *limit = gnodelast(h); |
| 366 | int i; | 382 | int i; |
| 367 | /* traverse array part (numeric keys are 'strong') */ | 383 | /* traverse array part */ |
| 368 | for (i = 0; i < h->sizearray; i++) { | 384 | for (i = 0; i < h->sizearray; i++) { |
| 369 | if (valiswhite(&h->array[i])) { | 385 | if (valiswhite(&h->array[i])) { |
| 370 | marked = 1; | 386 | marked = 1; |
| @@ -379,19 +395,20 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
| 379 | else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ | 395 | else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ |
| 380 | hasclears = 1; /* table must be cleared */ | 396 | hasclears = 1; /* table must be cleared */ |
| 381 | if (valiswhite(gval(n))) /* value not marked yet? */ | 397 | if (valiswhite(gval(n))) /* value not marked yet? */ |
| 382 | prop = 1; /* must propagate again */ | 398 | hasww = 1; /* white-white entry */ |
| 383 | } | 399 | } |
| 384 | else if (valiswhite(gval(n))) { /* value not marked yet? */ | 400 | else if (valiswhite(gval(n))) { /* value not marked yet? */ |
| 385 | marked = 1; | 401 | marked = 1; |
| 386 | reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ | 402 | reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ |
| 387 | } | 403 | } |
| 388 | } | 404 | } |
| 389 | if (prop) | 405 | /* link table into proper list */ |
| 406 | if (g->gcstate == GCSpropagate) | ||
| 407 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | ||
| 408 | else if (hasww) /* table has white->white entries? */ | ||
| 390 | linkgclist(h, g->ephemeron); /* have to propagate again */ | 409 | linkgclist(h, g->ephemeron); /* have to propagate again */ |
| 391 | else if (hasclears) /* does table have white keys? */ | 410 | else if (hasclears) /* table has white keys? */ |
| 392 | linkgclist(h, g->allweak); /* may have to clean white keys */ | 411 | linkgclist(h, g->allweak); /* may have to clean white keys */ |
| 393 | else /* no white keys */ | ||
| 394 | linkgclist(h, g->grayagain); /* no need to clean */ | ||
| 395 | return marked; | 412 | return marked; |
| 396 | } | 413 | } |
| 397 | 414 | ||
| @@ -565,35 +582,12 @@ static void propagateall (global_State *g) { | |||
| 565 | } | 582 | } |
| 566 | 583 | ||
| 567 | 584 | ||
| 568 | static void propagatelist (global_State *g, GCObject *l) { | ||
| 569 | lua_assert(g->gray == NULL); /* no grays left */ | ||
| 570 | g->gray = l; | ||
| 571 | propagateall(g); /* traverse all elements from 'l' */ | ||
| 572 | } | ||
| 573 | |||
| 574 | /* | ||
| 575 | ** retraverse all gray lists. Because tables may be reinserted in other | ||
| 576 | ** lists when traversed, traverse the original lists to avoid traversing | ||
| 577 | ** twice the same table (which is not wrong, but inefficient) | ||
| 578 | */ | ||
| 579 | static void retraversegrays (global_State *g) { | ||
| 580 | GCObject *weak = g->weak; /* save original lists */ | ||
| 581 | GCObject *grayagain = g->grayagain; | ||
| 582 | GCObject *ephemeron = g->ephemeron; | ||
| 583 | g->weak = g->grayagain = g->ephemeron = NULL; | ||
| 584 | propagateall(g); /* traverse main gray list */ | ||
| 585 | propagatelist(g, grayagain); | ||
| 586 | propagatelist(g, weak); | ||
| 587 | propagatelist(g, ephemeron); | ||
| 588 | } | ||
| 589 | |||
| 590 | |||
| 591 | static void convergeephemerons (global_State *g) { | 585 | static void convergeephemerons (global_State *g) { |
| 592 | int changed; | 586 | int changed; |
| 593 | do { | 587 | do { |
| 594 | GCObject *w; | 588 | GCObject *w; |
| 595 | GCObject *next = g->ephemeron; /* get ephemeron list */ | 589 | GCObject *next = g->ephemeron; /* get ephemeron list */ |
| 596 | g->ephemeron = NULL; /* tables will return to this list when traversed */ | 590 | g->ephemeron = NULL; /* tables may return to this list when traversed */ |
| 597 | changed = 0; | 591 | changed = 0; |
| 598 | while ((w = next) != NULL) { | 592 | while ((w = next) != NULL) { |
| 599 | next = gco2t(w)->gclist; | 593 | next = gco2t(w)->gclist; |
| @@ -966,19 +960,21 @@ static l_mem atomic (lua_State *L) { | |||
| 966 | global_State *g = G(L); | 960 | global_State *g = G(L); |
| 967 | l_mem work; | 961 | l_mem work; |
| 968 | GCObject *origweak, *origall; | 962 | GCObject *origweak, *origall; |
| 969 | g->GCmemtrav = 0; /* start counting work */ | 963 | GCObject *grayagain = g->grayagain; /* save original list */ |
| 964 | lua_assert(g->ephemeron == NULL && g->weak == NULL); | ||
| 970 | lua_assert(!iswhite(g->mainthread)); | 965 | lua_assert(!iswhite(g->mainthread)); |
| 971 | g->gcstate = GCSinsideatomic; | 966 | g->gcstate = GCSinsideatomic; |
| 967 | g->GCmemtrav = 0; /* start counting work */ | ||
| 972 | markobject(g, L); /* mark running thread */ | 968 | markobject(g, L); /* mark running thread */ |
| 973 | /* registry and global metatables may be changed by API */ | 969 | /* registry and global metatables may be changed by API */ |
| 974 | markvalue(g, &g->l_registry); | 970 | markvalue(g, &g->l_registry); |
| 975 | markmt(g); /* mark basic metatables */ | 971 | markmt(g); /* mark global metatables */ |
| 976 | /* remark occasional upvalues of (maybe) dead threads */ | 972 | /* remark occasional upvalues of (maybe) dead threads */ |
| 977 | remarkupvals(g); | 973 | remarkupvals(g); |
| 978 | propagateall(g); /* propagate changes */ | 974 | propagateall(g); /* propagate changes */ |
| 979 | work = g->GCmemtrav; /* stop counting (do not (re)count grays) */ | 975 | work = g->GCmemtrav; /* stop counting (do not recount gray-agains) */ |
| 980 | /* traverse objects caught by write barrier and by 'remarkupvals' */ | 976 | g->gray = grayagain; |
| 981 | retraversegrays(g); | 977 | propagateall(g); /* traverse 'grayagain' list */ |
| 982 | g->GCmemtrav = 0; /* restart counting */ | 978 | g->GCmemtrav = 0; /* restart counting */ |
| 983 | convergeephemerons(g); | 979 | convergeephemerons(g); |
| 984 | /* at this point, all strongly accessible objects are marked. */ | 980 | /* at this point, all strongly accessible objects are marked. */ |
