diff options
-rw-r--r-- | lgc.c | 39 | ||||
-rw-r--r-- | testes/gc.lua | 5 |
2 files changed, 31 insertions, 13 deletions
@@ -589,25 +589,38 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
589 | } | 589 | } |
590 | 590 | ||
591 | 591 | ||
592 | static 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 | */ | ||
595 | static 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 | |||
608 | static 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 | |||
288 | collectgarbage() | 288 | collectgarbage() |
289 | assert(next(a) == string.rep('$', 11)) | 289 | assert(next(a) == string.rep('$', 11)) |
290 | 290 | ||
291 | do -- invalid mode | ||
292 | local a = setmetatable({}, {__mode = 34}) | ||
293 | collectgarbage() | ||
294 | end | ||
295 | |||
291 | 296 | ||
292 | -- 'bug' in 5.1 | 297 | -- 'bug' in 5.1 |
293 | a = {} | 298 | a = {} |