diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-02-23 10:16:18 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-02-23 10:16:18 -0300 |
commit | 9243c414d92c253edd908f438caa31e2aa16f3f4 (patch) | |
tree | e8959a48f4672037aef061cc6eb82bba21d0766b /lgc.c | |
parent | 477ca2fe8ceaf79038972977915987adbef0e425 (diff) | |
download | lua-9243c414d92c253edd908f438caa31e2aa16f3f4.tar.gz lua-9243c414d92c253edd908f438caa31e2aa16f3f4.tar.bz2 lua-9243c414d92c253edd908f438caa31e2aa16f3f4.zip |
first version of empty entries in tables
(so that, in the future, tables can contain regular nil entries)
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 58 |
1 files changed, 30 insertions, 28 deletions
@@ -145,12 +145,13 @@ static GCObject **getgclist (GCObject *o) { | |||
145 | ** Clear keys for empty entries in tables. If entry is empty | 145 | ** Clear keys for empty entries in tables. If entry is empty |
146 | ** and its key is not marked, mark its entry as dead. This allows the | 146 | ** and its key is not marked, mark its entry as dead. This allows the |
147 | ** collection of the key, but keeps its entry in the table (its removal | 147 | ** collection of the key, but keeps its entry in the table (its removal |
148 | ** could break a chain). Other places never manipulate dead keys, | 148 | ** could break a chain). The main feature of a dead key is that it must |
149 | ** because its associated nil value is enough to signal that the entry | 149 | ** be different from any other value, to do not disturb searches. |
150 | ** is logically empty. | 150 | ** Other places never manipulate dead keys, because its associated empty |
151 | ** value is enough to signal that the entry is logically empty. | ||
151 | */ | 152 | */ |
152 | static void removeentry (Node *n) { | 153 | static void clearkey (Node *n) { |
153 | lua_assert(ttisnil(gval(n))); | 154 | lua_assert(isempty(gval(n))); |
154 | if (keyiswhite(n)) | 155 | if (keyiswhite(n)) |
155 | setdeadkey(n); /* unused and unmarked key; remove it */ | 156 | setdeadkey(n); /* unused and unmarked key; remove it */ |
156 | } | 157 | } |
@@ -386,8 +387,8 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
386 | worth traversing it now just to check) */ | 387 | worth traversing it now just to check) */ |
387 | int hasclears = (h->sizearray > 0); | 388 | int hasclears = (h->sizearray > 0); |
388 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 389 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
389 | if (ttisnil(gval(n))) /* entry is empty? */ | 390 | if (isempty(gval(n))) /* entry is empty? */ |
390 | removeentry(n); /* remove it */ | 391 | clearkey(n); /* clear its key */ |
391 | else { | 392 | else { |
392 | lua_assert(!keyisnil(n)); | 393 | lua_assert(!keyisnil(n)); |
393 | markkey(g, n); | 394 | markkey(g, n); |
@@ -428,8 +429,8 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
428 | } | 429 | } |
429 | /* traverse hash part */ | 430 | /* traverse hash part */ |
430 | for (n = gnode(h, 0); n < limit; n++) { | 431 | for (n = gnode(h, 0); n < limit; n++) { |
431 | if (ttisnil(gval(n))) /* entry is empty? */ | 432 | if (isempty(gval(n))) /* entry is empty? */ |
432 | removeentry(n); /* remove it */ | 433 | clearkey(n); /* clear its key */ |
433 | else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ | 434 | else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */ |
434 | hasclears = 1; /* table must be cleared */ | 435 | hasclears = 1; /* table must be cleared */ |
435 | if (valiswhite(gval(n))) /* value not marked yet? */ | 436 | if (valiswhite(gval(n))) /* value not marked yet? */ |
@@ -461,8 +462,8 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
461 | for (i = 0; i < h->sizearray; i++) /* traverse array part */ | 462 | for (i = 0; i < h->sizearray; i++) /* traverse array part */ |
462 | markvalue(g, &h->array[i]); | 463 | markvalue(g, &h->array[i]); |
463 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ | 464 | for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ |
464 | if (ttisnil(gval(n))) /* entry is empty? */ | 465 | if (isempty(gval(n))) /* entry is empty? */ |
465 | removeentry(n); /* remove it */ | 466 | clearkey(n); /* clear its key */ |
466 | else { | 467 | else { |
467 | lua_assert(!keyisnil(n)); | 468 | lua_assert(!keyisnil(n)); |
468 | markkey(g, n); | 469 | markkey(g, n); |
@@ -681,15 +682,16 @@ static void clearprotolist (global_State *g) { | |||
681 | /* | 682 | /* |
682 | ** clear entries with unmarked keys from all weaktables in list 'l' | 683 | ** clear entries with unmarked keys from all weaktables in list 'l' |
683 | */ | 684 | */ |
684 | static void clearkeys (global_State *g, GCObject *l) { | 685 | static void clearbykeys (global_State *g, GCObject *l) { |
685 | for (; l; l = gco2t(l)->gclist) { | 686 | for (; l; l = gco2t(l)->gclist) { |
686 | Table *h = gco2t(l); | 687 | Table *h = gco2t(l); |
687 | Node *n, *limit = gnodelast(h); | 688 | Node *limit = gnodelast(h); |
689 | Node *n; | ||
688 | for (n = gnode(h, 0); n < limit; n++) { | 690 | for (n = gnode(h, 0); n < limit; n++) { |
689 | if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) /* unmarked key? */ | 691 | if (isempty(gval(n))) /* is entry empty? */ |
690 | setnilvalue(gval(n)); /* clear value */ | 692 | clearkey(n); /* clear its key */ |
691 | if (ttisnil(gval(n))) /* is entry empty? */ | 693 | else if (iscleared(g, gckeyN(n))) /* unmarked key? */ |
692 | removeentry(n); /* remove it from table */ | 694 | setempty(gval(n)); /* remove entry */ |
693 | } | 695 | } |
694 | } | 696 | } |
695 | } | 697 | } |
@@ -699,7 +701,7 @@ static void clearkeys (global_State *g, GCObject *l) { | |||
699 | ** clear entries with unmarked values from all weaktables in list 'l' up | 701 | ** clear entries with unmarked values from all weaktables in list 'l' up |
700 | ** to element 'f' | 702 | ** to element 'f' |
701 | */ | 703 | */ |
702 | static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | 704 | static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { |
703 | for (; l != f; l = gco2t(l)->gclist) { | 705 | for (; l != f; l = gco2t(l)->gclist) { |
704 | Table *h = gco2t(l); | 706 | Table *h = gco2t(l); |
705 | Node *n, *limit = gnodelast(h); | 707 | Node *n, *limit = gnodelast(h); |
@@ -707,13 +709,13 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
707 | for (i = 0; i < h->sizearray; i++) { | 709 | for (i = 0; i < h->sizearray; i++) { |
708 | TValue *o = &h->array[i]; | 710 | TValue *o = &h->array[i]; |
709 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ | 711 | if (iscleared(g, gcvalueN(o))) /* value was collected? */ |
710 | setnilvalue(o); /* remove value */ | 712 | setempty(o); /* remove entry */ |
711 | } | 713 | } |
712 | for (n = gnode(h, 0); n < limit; n++) { | 714 | for (n = gnode(h, 0); n < limit; n++) { |
713 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ | 715 | if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ |
714 | setnilvalue(gval(n)); /* clear value */ | 716 | setempty(gval(n)); /* remove entry */ |
715 | if (ttisnil(gval(n))) /* is entry empty? */ | 717 | if (isempty(gval(n))) /* is entry empty? */ |
716 | removeentry(n); /* remove it from table */ | 718 | clearkey(n); /* clear its key */ |
717 | } | 719 | } |
718 | } | 720 | } |
719 | } | 721 | } |
@@ -1372,8 +1374,8 @@ static lu_mem atomic (lua_State *L) { | |||
1372 | convergeephemerons(g); | 1374 | convergeephemerons(g); |
1373 | /* at this point, all strongly accessible objects are marked. */ | 1375 | /* at this point, all strongly accessible objects are marked. */ |
1374 | /* Clear values from weak tables, before checking finalizers */ | 1376 | /* Clear values from weak tables, before checking finalizers */ |
1375 | clearvalues(g, g->weak, NULL); | 1377 | clearbyvalues(g, g->weak, NULL); |
1376 | clearvalues(g, g->allweak, NULL); | 1378 | clearbyvalues(g, g->allweak, NULL); |
1377 | origweak = g->weak; origall = g->allweak; | 1379 | origweak = g->weak; origall = g->allweak; |
1378 | separatetobefnz(g, 0); /* separate objects to be finalized */ | 1380 | separatetobefnz(g, 0); /* separate objects to be finalized */ |
1379 | work += markbeingfnz(g); /* mark objects that will be finalized */ | 1381 | work += markbeingfnz(g); /* mark objects that will be finalized */ |
@@ -1381,11 +1383,11 @@ static lu_mem atomic (lua_State *L) { | |||
1381 | convergeephemerons(g); | 1383 | convergeephemerons(g); |
1382 | /* at this point, all resurrected objects are marked. */ | 1384 | /* at this point, all resurrected objects are marked. */ |
1383 | /* remove dead objects from weak tables */ | 1385 | /* remove dead objects from weak tables */ |
1384 | clearkeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ | 1386 | clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ |
1385 | clearkeys(g, g->allweak); /* clear keys from all 'allweak' tables */ | 1387 | clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ |
1386 | /* clear values from resurrected weak tables */ | 1388 | /* clear values from resurrected weak tables */ |
1387 | clearvalues(g, g->weak, origweak); | 1389 | clearbyvalues(g, g->weak, origweak); |
1388 | clearvalues(g, g->allweak, origall); | 1390 | clearbyvalues(g, g->allweak, origall); |
1389 | luaS_clearcache(g); | 1391 | luaS_clearcache(g); |
1390 | clearprotolist(g); | 1392 | clearprotolist(g); |
1391 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1393 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |