diff options
Diffstat (limited to '')
-rw-r--r-- | lgc.c | 52 |
1 files changed, 36 insertions, 16 deletions
@@ -126,7 +126,6 @@ static l_mem objsize (GCObject *o) { | |||
126 | CClosure *cl = gco2ccl(o); | 126 | CClosure *cl = gco2ccl(o); |
127 | res = sizeCclosure(cl->nupvalues); | 127 | res = sizeCclosure(cl->nupvalues); |
128 | break; | 128 | break; |
129 | break; | ||
130 | } | 129 | } |
131 | case LUA_VUSERDATA: { | 130 | case LUA_VUSERDATA: { |
132 | Udata *u = gco2u(o); | 131 | Udata *u = gco2u(o); |
@@ -465,6 +464,8 @@ static void restartcollection (global_State *g) { | |||
465 | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go | 464 | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go |
466 | ** back to a gray list, but then it must become OLD. (That is what | 465 | ** back to a gray list, but then it must become OLD. (That is what |
467 | ** 'correctgraylist' does when it finds a TOUCHED2 object.) | 466 | ** 'correctgraylist' does when it finds a TOUCHED2 object.) |
467 | ** This function is a no-op in incremental mode, as objects cannot be | ||
468 | ** marked as touched in that mode. | ||
468 | */ | 469 | */ |
469 | static void genlink (global_State *g, GCObject *o) { | 470 | static void genlink (global_State *g, GCObject *o) { |
470 | lua_assert(isblack(o)); | 471 | lua_assert(isblack(o)); |
@@ -480,7 +481,8 @@ static void genlink (global_State *g, GCObject *o) { | |||
480 | ** Traverse a table with weak values and link it to proper list. During | 481 | ** Traverse a table with weak values and link it to proper list. During |
481 | ** propagate phase, keep it in 'grayagain' list, to be revisited in the | 482 | ** propagate phase, keep it in 'grayagain' list, to be revisited in the |
482 | ** atomic phase. In the atomic phase, if table has any white value, | 483 | ** atomic phase. In the atomic phase, if table has any white value, |
483 | ** put it in 'weak' list, to be cleared. | 484 | ** put it in 'weak' list, to be cleared; otherwise, call 'genlink' |
485 | ** to check table age in generational mode. | ||
484 | */ | 486 | */ |
485 | static void traverseweakvalue (global_State *g, Table *h) { | 487 | static void traverseweakvalue (global_State *g, Table *h) { |
486 | Node *n, *limit = gnodelast(h); | 488 | Node *n, *limit = gnodelast(h); |
@@ -501,6 +503,8 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
501 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | 503 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ |
502 | else if (hasclears) | 504 | else if (hasclears) |
503 | linkgclist(h, g->weak); /* has to be cleared later */ | 505 | linkgclist(h, g->weak); /* has to be cleared later */ |
506 | else | ||
507 | genlink(g, obj2gco(h)); | ||
504 | } | 508 | } |
505 | 509 | ||
506 | 510 | ||
@@ -585,25 +589,41 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
585 | } | 589 | } |
586 | 590 | ||
587 | 591 | ||
588 | static l_mem traversetable (global_State *g, Table *h) { | 592 | /* |
589 | const char *weakkey, *weakvalue; | 593 | ** (result & 1) iff weak values; (result & 2) iff weak keys. |
594 | */ | ||
595 | static int getmode (global_State *g, Table *h) { | ||
590 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); | 596 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); |
591 | TString *smode; | 597 | if (mode == NULL || !ttisshrstring(mode)) |
598 | return 0; /* ignore non-(short)string modes */ | ||
599 | else { | ||
600 | const char *smode = getshrstr(tsvalue(mode)); | ||
601 | const char *weakkey = strchr(smode, 'k'); | ||
602 | const char *weakvalue = strchr(smode, 'v'); | ||
603 | return ((weakkey != NULL) << 1) | (weakvalue != NULL); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | |||
608 | static l_mem traversetable (global_State *g, Table *h) { | ||
592 | markobjectN(g, h->metatable); | 609 | markobjectN(g, h->metatable); |
593 | if (mode && ttisshrstring(mode) && /* is there a weak mode? */ | 610 | switch (getmode(g, h)) { |
594 | (cast_void(smode = tsvalue(mode)), | 611 | case 0: /* not weak */ |
595 | cast_void(weakkey = strchr(getshrstr(smode), 'k')), | 612 | traversestrongtable(g, h); |
596 | cast_void(weakvalue = strchr(getshrstr(smode), 'v')), | 613 | break; |
597 | (weakkey || weakvalue))) { /* is really weak? */ | 614 | case 1: /* weak values */ |
598 | if (!weakkey) /* strong keys? */ | ||
599 | traverseweakvalue(g, h); | 615 | traverseweakvalue(g, h); |
600 | else if (!weakvalue) /* strong values? */ | 616 | break; |
617 | case 2: /* weak keys */ | ||
601 | traverseephemeron(g, h, 0); | 618 | traverseephemeron(g, h, 0); |
602 | else /* all weak */ | 619 | break; |
603 | linkgclist(h, g->allweak); /* nothing to traverse now */ | 620 | case 3: /* all weak; nothing to traverse */ |
621 | if (g->gcstate == GCSpropagate) | ||
622 | linkgclist(h, g->grayagain); /* must visit again its metatable */ | ||
623 | else | ||
624 | linkgclist(h, g->allweak); /* must clear collected entries */ | ||
625 | break; | ||
604 | } | 626 | } |
605 | else /* not weak */ | ||
606 | traversestrongtable(g, h); | ||
607 | return 1 + 2*sizenode(h) + h->asize; | 627 | return 1 + 2*sizenode(h) + h->asize; |
608 | } | 628 | } |
609 | 629 | ||