aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lgc.c39
-rw-r--r--testes/gc.lua5
2 files changed, 31 insertions, 13 deletions
diff --git a/lgc.c b/lgc.c
index f0045dd6..e4cbcf0c 100644
--- a/lgc.c
+++ b/lgc.c
@@ -589,25 +589,38 @@ static void traversestrongtable (global_State *g, Table *h) {
589} 589}
590 590
591 591
592static l_mem traversetable (global_State *g, Table *h) { 592/*
593 const char *weakkey, *weakvalue; 593** (result & 1) iff weak values; (result & 2) iff weak keys.
594*/
595static int getmode (global_State *g, Table *h) {
594 const TValue *mode = gfasttm(g, h->metatable, TM_MODE); 596 const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
595 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
608static l_mem traversetable (global_State *g, Table *h) {
596 markobjectN(g, h->metatable); 609 markobjectN(g, h->metatable);
597 if (mode && ttisshrstring(mode) && /* is there a weak mode? */ 610 switch (getmode(g, h)) {
598 (cast_void(smode = tsvalue(mode)), 611 case 0: /* not weak */
599 cast_void(weakkey = strchr(getshrstr(smode), 'k')), 612 traversestrongtable(g, h);
600 cast_void(weakvalue = strchr(getshrstr(smode), 'v')), 613 break;
601 (weakkey || weakvalue))) { /* is really weak? */ 614 case 1: /* weak values */
602 if (!weakkey) /* strong keys? */
603 traverseweakvalue(g, h); 615 traverseweakvalue(g, h);
604 else if (!weakvalue) /* strong values? */ 616 break;
617 case 2: /* weak keys */
605 traverseephemeron(g, h, 0); 618 traverseephemeron(g, h, 0);
606 else /* all weak */ 619 break;
620 case 3: /* all weak */
607 linkgclist(h, g->allweak); /* nothing to traverse now */ 621 linkgclist(h, g->allweak); /* nothing to traverse now */
622 break;
608 } 623 }
609 else /* not weak */
610 traversestrongtable(g, h);
611 return 1 + 2*sizenode(h) + h->asize; 624 return 1 + 2*sizenode(h) + h->asize;
612} 625}
613 626
diff --git a/testes/gc.lua b/testes/gc.lua
index ca8aa1bc..5d2b3085 100644
--- a/testes/gc.lua
+++ b/testes/gc.lua
@@ -288,6 +288,11 @@ x,y,z=nil
288collectgarbage() 288collectgarbage()
289assert(next(a) == string.rep('$', 11)) 289assert(next(a) == string.rep('$', 11))
290 290
291do -- invalid mode
292 local a = setmetatable({}, {__mode = 34})
293 collectgarbage()
294end
295
291 296
292-- 'bug' in 5.1 297-- 'bug' in 5.1
293a = {} 298a = {}