diff options
| -rw-r--r-- | lgc.c | 359 | ||||
| -rw-r--r-- | lgc.h | 54 | ||||
| -rw-r--r-- | lstate.c | 5 | ||||
| -rw-r--r-- | lstate.h | 8 |
4 files changed, 324 insertions, 102 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.216 2017/02/23 21:07:34 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "lprefix.h" | 10 | #include "lprefix.h" |
| 11 | 11 | ||
| 12 | 12 | #include <stdio.h> | |
| 13 | #include <string.h> | 13 | #include <string.h> |
| 14 | 14 | ||
| 15 | #include "lua.h" | 15 | #include "lua.h" |
| @@ -27,12 +27,6 @@ | |||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | /* | 29 | /* |
| 30 | ** internal state for collector while inside the atomic phase. The | ||
| 31 | ** collector should never be in this state while running regular code. | ||
| 32 | */ | ||
| 33 | #define GCSinsideatomic (GCSpause + 1) | ||
| 34 | |||
| 35 | /* | ||
| 36 | ** cost of sweeping one element (the size of a small object divided | 30 | ** cost of sweeping one element (the size of a small object divided |
| 37 | ** by some adjust for the sweep speed) | 31 | ** by some adjust for the sweep speed) |
| 38 | */ | 32 | */ |
| @@ -59,8 +53,9 @@ | |||
| 59 | #define PAUSEADJ 100 | 53 | #define PAUSEADJ 100 |
| 60 | 54 | ||
| 61 | 55 | ||
| 62 | /* mask to erase all color bits */ | 56 | /* mask to erase all color bits (plus gen. related stuff) */ |
| 63 | #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) | 57 | #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS)) |
| 58 | |||
| 64 | 59 | ||
| 65 | /* macro to erase all color bits then sets only the current white bit */ | 60 | /* macro to erase all color bits then sets only the current white bit */ |
| 66 | #define makewhite(g,x) \ | 61 | #define makewhite(g,x) \ |
| @@ -157,8 +152,10 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
| 157 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 152 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
| 158 | if (keepinvariant(g)) { /* must keep invariant? */ | 153 | if (keepinvariant(g)) { /* must keep invariant? */ |
| 159 | reallymarkobject(g, v); /* restore invariant */ | 154 | reallymarkobject(g, v); /* restore invariant */ |
| 160 | if (isold(o)) | 155 | if (isold(o)) { |
| 161 | l_setbit((v)->marked, OLDBIT); | 156 | lua_assert(!isold(v)); |
| 157 | setage(v, G_OLD0); | ||
| 158 | } | ||
| 162 | } | 159 | } |
| 163 | else { /* sweep phase */ | 160 | else { /* sweep phase */ |
| 164 | lua_assert(issweepphase(g)); | 161 | lua_assert(issweepphase(g)); |
| @@ -174,8 +171,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
| 174 | void luaC_barrierback_ (lua_State *L, Table *t) { | 171 | void luaC_barrierback_ (lua_State *L, Table *t) { |
| 175 | global_State *g = G(L); | 172 | global_State *g = G(L); |
| 176 | lua_assert(isblack(t) && !isdead(g, t)); | 173 | lua_assert(isblack(t) && !isdead(g, t)); |
| 174 | lua_assert(issweepphase(g) || getage(t) != G_TOUCHED1); | ||
| 175 | lua_assert(g->gckind != KGC_GEN || isold(t)); | ||
| 176 | if (getage(t) != G_TOUCHED2) /* not already in gray list? */ | ||
| 177 | linkgclist(t, g->grayagain); /* link it in 'grayagain' */ | ||
| 177 | black2gray(t); /* make table gray (again) */ | 178 | black2gray(t); /* make table gray (again) */ |
| 178 | linkgclist(t, g->grayagain); | 179 | setage(t, G_TOUCHED1); /* touched in current cycle */ |
| 179 | } | 180 | } |
| 180 | 181 | ||
| 181 | 182 | ||
| @@ -188,10 +189,10 @@ void luaC_barrierback_ (lua_State *L, Table *t) { | |||
| 188 | void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { | 189 | void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { |
| 189 | global_State *g = G(L); | 190 | global_State *g = G(L); |
| 190 | GCObject *o = gcvalue(uv->v); | 191 | GCObject *o = gcvalue(uv->v); |
| 191 | lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ | ||
| 192 | if (keepinvariant(g)) { | 192 | if (keepinvariant(g)) { |
| 193 | markobject(g, o); | 193 | markobject(g, o); |
| 194 | l_setbit((o)->marked, OLDBIT); | 194 | if (!isold(o)) |
| 195 | setage(o, G_OLD0); | ||
| 195 | } | 196 | } |
| 196 | } | 197 | } |
| 197 | 198 | ||
| @@ -379,10 +380,10 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
| 379 | hasclears = 1; /* table will have to be cleared */ | 380 | hasclears = 1; /* table will have to be cleared */ |
| 380 | } | 381 | } |
| 381 | } | 382 | } |
| 382 | if (g->gcstate == GCSpropagate) | 383 | if (g->gcstate == GCSatomic && hasclears) |
| 383 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | ||
| 384 | else if (hasclears) | ||
| 385 | linkgclist(h, g->weak); /* has to be cleared later */ | 384 | linkgclist(h, g->weak); /* has to be cleared later */ |
| 385 | else | ||
| 386 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | ||
| 386 | } | 387 | } |
| 387 | 388 | ||
| 388 | 389 | ||
| @@ -431,6 +432,8 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
| 431 | linkgclist(h, g->ephemeron); /* have to propagate again */ | 432 | linkgclist(h, g->ephemeron); /* have to propagate again */ |
| 432 | else if (hasclears) /* table has white keys? */ | 433 | else if (hasclears) /* table has white keys? */ |
| 433 | linkgclist(h, g->allweak); /* may have to clean white keys */ | 434 | linkgclist(h, g->allweak); /* may have to clean white keys */ |
| 435 | else if (g->gckind == KGC_GEN) | ||
| 436 | linkgclist(h, g->grayagain); /* keep it in some list */ | ||
| 434 | return marked; | 437 | return marked; |
| 435 | } | 438 | } |
| 436 | 439 | ||
| @@ -450,6 +453,10 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
| 450 | markvalue(g, gval(n)); /* mark value */ | 453 | markvalue(g, gval(n)); /* mark value */ |
| 451 | } | 454 | } |
| 452 | } | 455 | } |
| 456 | if (g->gckind == KGC_GEN) { | ||
| 457 | linkgclist(h, g->grayagain); /* keep it in some gray list */ | ||
| 458 | black2gray(h); | ||
| 459 | } | ||
| 453 | } | 460 | } |
| 454 | 461 | ||
| 455 | 462 | ||
| @@ -522,7 +529,7 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | |||
| 522 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ | 529 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ |
| 523 | UpVal *uv = cl->upvals[i]; | 530 | UpVal *uv = cl->upvals[i]; |
| 524 | if (uv != NULL) { | 531 | if (uv != NULL) { |
| 525 | if (upisopen(uv) && g->gcstate != GCSinsideatomic) | 532 | if (upisopen(uv) && g->gcstate != GCSatomic) |
| 526 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ | 533 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ |
| 527 | else | 534 | else |
| 528 | markvalue(g, uv->v); | 535 | markvalue(g, uv->v); |
| @@ -536,11 +543,11 @@ static lu_mem traversethread (global_State *g, lua_State *th) { | |||
| 536 | StkId o = th->stack; | 543 | StkId o = th->stack; |
| 537 | if (o == NULL) | 544 | if (o == NULL) |
| 538 | return 1; /* stack not completely built yet */ | 545 | return 1; /* stack not completely built yet */ |
| 539 | lua_assert(g->gcstate == GCSinsideatomic || | 546 | lua_assert(g->gcstate == GCSatomic || |
| 540 | th->openupval == NULL || isintwups(th)); | 547 | th->openupval == NULL || isintwups(th)); |
| 541 | for (; o < th->top; o++) /* mark live elements in the stack */ | 548 | for (; o < th->top; o++) /* mark live elements in the stack */ |
| 542 | markvalue(g, o); | 549 | markvalue(g, o); |
| 543 | if (g->gcstate == GCSinsideatomic) { /* final traversal? */ | 550 | if (g->gcstate == GCSatomic) { /* final traversal? */ |
| 544 | StkId lim = th->stack + th->stacksize; /* real end of stack */ | 551 | StkId lim = th->stack + th->stacksize; /* real end of stack */ |
| 545 | for (; o < lim; o++) /* clear not-marked stack slice */ | 552 | for (; o < lim; o++) /* clear not-marked stack slice */ |
| 546 | setnilvalue(o); | 553 | setnilvalue(o); |
| @@ -564,7 +571,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) { | |||
| 564 | static void propagatemark (global_State *g) { | 571 | static void propagatemark (global_State *g) { |
| 565 | lu_mem size; | 572 | lu_mem size; |
| 566 | GCObject *o = g->gray; | 573 | GCObject *o = g->gray; |
| 567 | lua_assert(isgray(o)); | 574 | lua_assert(ongraylist(o)); |
| 568 | gray2black(o); | 575 | gray2black(o); |
| 569 | switch (o->tt) { | 576 | switch (o->tt) { |
| 570 | case LUA_TTABLE: { | 577 | case LUA_TTABLE: { |
| @@ -638,11 +645,10 @@ static void convergeephemerons (global_State *g) { | |||
| 638 | 645 | ||
| 639 | 646 | ||
| 640 | /* | 647 | /* |
| 641 | ** clear entries with unmarked keys from all weaktables in list 'l' up | 648 | ** clear entries with unmarked keys from all weaktables in list 'l' |
| 642 | ** to element 'f' | ||
| 643 | */ | 649 | */ |
| 644 | static void clearkeys (global_State *g, GCObject *l, GCObject *f) { | 650 | static void clearkeys (global_State *g, GCObject *l) { |
| 645 | for (; l != f; l = gco2t(l)->gclist) { | 651 | for (; l; l = gco2t(l)->gclist) { |
| 646 | Table *h = gco2t(l); | 652 | Table *h = gco2t(l); |
| 647 | Node *n, *limit = gnodelast(h); | 653 | Node *n, *limit = gnodelast(h); |
| 648 | for (n = gnode(h, 0); n < limit; n++) { | 654 | for (n = gnode(h, 0); n < limit; n++) { |
| @@ -885,11 +891,13 @@ static void separatetobefnz (global_State *g, int all) { | |||
| 885 | GCObject *curr; | 891 | GCObject *curr; |
| 886 | GCObject **p = &g->finobj; | 892 | GCObject **p = &g->finobj; |
| 887 | GCObject **lastnext = findlast(&g->tobefnz); | 893 | GCObject **lastnext = findlast(&g->tobefnz); |
| 888 | while ((curr = *p) != NULL) { /* traverse all finalizable objects */ | 894 | while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */ |
| 889 | lua_assert(tofinalize(curr)); | 895 | lua_assert(tofinalize(curr)); |
| 890 | if (!(iswhite(curr) || all)) /* not being collected? */ | 896 | if (!(iswhite(curr) || all)) /* not being collected? */ |
| 891 | p = &curr->next; /* don't bother with it */ | 897 | p = &curr->next; /* don't bother with it */ |
| 892 | else { | 898 | else { |
| 899 | if (curr == g->finobjsur) | ||
| 900 | g->finobjsur = curr->next; | ||
| 893 | *p = curr->next; /* remove 'curr' from 'finobj' list */ | 901 | *p = curr->next; /* remove 'curr' from 'finobj' list */ |
| 894 | curr->next = *lastnext; /* link at the end of 'tobefnz' list */ | 902 | curr->next = *lastnext; /* link at the end of 'tobefnz' list */ |
| 895 | *lastnext = curr; | 903 | *lastnext = curr; |
| @@ -915,6 +923,14 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
| 915 | if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ | 923 | if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ |
| 916 | g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ | 924 | g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ |
| 917 | } | 925 | } |
| 926 | else { | ||
| 927 | if (o == g->survival) | ||
| 928 | g->survival = o->next; | ||
| 929 | if (o == g->old) | ||
| 930 | g->old = o->next; | ||
| 931 | if (o == g->reallyold) | ||
| 932 | g->reallyold = o->next; | ||
| 933 | } | ||
| 918 | /* search for pointer pointing to 'o' */ | 934 | /* search for pointer pointing to 'o' */ |
| 919 | for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } | 935 | for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } |
| 920 | *p = o->next; /* remove 'o' from 'allgc' list */ | 936 | *p = o->next; /* remove 'o' from 'allgc' list */ |
| @@ -934,31 +950,65 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
| 934 | */ | 950 | */ |
| 935 | 951 | ||
| 936 | 952 | ||
| 953 | /* mask to erase all color bits (not changing gen-related stuff) */ | ||
| 954 | #define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS)) | ||
| 955 | |||
| 937 | #if 0 | 956 | #if 0 |
| 938 | static int count (GCObject *p, GCObject *limit) { | 957 | static int count (GCObject *p, GCObject *limit) { |
| 939 | int res = 0; | 958 | int res = 0; |
| 940 | for (; p != NULL && p != limit; p = p->next) | 959 | for (; p != NULL && p != limit; p = p->next) { |
| 941 | res++; | 960 | res++; |
| 961 | } | ||
| 942 | return res; | 962 | return res; |
| 943 | } | 963 | } |
| 944 | #endif | 964 | #endif |
| 945 | 965 | ||
| 946 | 966 | ||
| 947 | static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, | 967 | static void sweep2old (lua_State *L, GCObject **p) { |
| 948 | int zeromask, int onemask) { | 968 | GCObject *curr; |
| 949 | global_State *g = G(L); | 969 | while ((curr = *p) != NULL) { |
| 950 | int ow = otherwhite(g); | 970 | if (iswhite(curr)) { /* is 'curr' dead? */ |
| 971 | lua_assert(isdead(G(L), curr)); | ||
| 972 | *p = curr->next; /* remove 'curr' from list */ | ||
| 973 | freeobj(L, curr); /* erase 'curr' */ | ||
| 974 | } | ||
| 975 | else { /* all surviving objects become old */ | ||
| 976 | setage(curr, G_OLD); | ||
| 977 | p = &curr->next; /* go to next element */ | ||
| 978 | } | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | |||
| 983 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | ||
| 984 | GCObject *limit) { | ||
| 985 | int white = luaC_white(g); | ||
| 951 | GCObject *curr; | 986 | GCObject *curr; |
| 952 | while ((curr = *p) != limit) { | 987 | while ((curr = *p) != limit) { |
| 953 | int marked = curr->marked; | 988 | int marked = curr->marked; |
| 954 | if (isdeadm(ow, marked)) { /* is 'curr' dead? */ | 989 | if (iswhite(curr)) { /* is 'curr' dead? */ |
| 955 | lua_assert(!isold(curr)); | 990 | lua_assert(!isold(curr) && !testbits(curr->marked, white)); |
| 956 | *p = curr->next; /* remove 'curr' from list */ | 991 | *p = curr->next; /* remove 'curr' from list */ |
| 957 | freeobj(L, curr); /* erase 'curr' */ | 992 | freeobj(L, curr); /* erase 'curr' */ |
| 958 | } | 993 | } |
| 959 | else { /* correct mark */ | 994 | else { /* correct mark and age */ |
| 960 | if (!isold(curr)) /* don't change old objects */ | 995 | switch (getage(curr)) { |
| 961 | curr->marked = cast_byte((marked & zeromask) | onemask); | 996 | case G_NEW: /* make white and go to next age */ |
| 997 | curr->marked = cast_byte((marked & maskgencolors) | white); | ||
| 998 | changeage(curr, G_NEW, G_SURVIVAL); | ||
| 999 | break; | ||
| 1000 | case G_SURVIVAL: /* go to next age */ | ||
| 1001 | changeage(curr, G_SURVIVAL, G_OLD1); | ||
| 1002 | break; | ||
| 1003 | case G_OLD0: /* go to next age */ | ||
| 1004 | changeage(curr, G_OLD0, G_OLD1); | ||
| 1005 | break; | ||
| 1006 | case G_OLD1: /* go to next age */ | ||
| 1007 | changeage(curr, G_OLD1, G_OLD); | ||
| 1008 | break; | ||
| 1009 | default: /* don't change 'old', 'touched1', and 'touched2' */ | ||
| 1010 | break; | ||
| 1011 | } | ||
| 962 | p = &curr->next; /* go to next element */ | 1012 | p = &curr->next; /* go to next element */ |
| 963 | } | 1013 | } |
| 964 | } | 1014 | } |
| @@ -966,51 +1016,184 @@ static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, | |||
| 966 | } | 1016 | } |
| 967 | 1017 | ||
| 968 | 1018 | ||
| 969 | static void startgencycle (lua_State *L, global_State *g) { | 1019 | static void whitelist (global_State *g, GCObject *p) { |
| 970 | propagateall(g); | 1020 | int white = luaC_white(g); |
| 971 | atomic(L); | 1021 | for (; p != NULL; p = p->next) |
| 1022 | p->marked = cast_byte((p->marked & maskcolors) | white); | ||
| 972 | } | 1023 | } |
| 973 | 1024 | ||
| 974 | 1025 | ||
| 975 | static void finishgencycle (lua_State *L, global_State *g, int mask) { | 1026 | static void finishgencycle (lua_State *L, global_State *g) { |
| 976 | sweepgen(L, &g->finobj, NULL, ~0, mask); | 1027 | // sweepgen(L, &g->tobefnz, ~0, mask); |
| 977 | sweepgen(L, &g->tobefnz, NULL, ~0, mask); | ||
| 978 | checkSizes(L, g); | 1028 | checkSizes(L, g); |
| 979 | g->gcstate = GCSpropagate; /* skip restart */ | 1029 | g->gcstate = GCSpropagate; /* skip restart */ |
| 980 | callallpendingfinalizers(L); | 1030 | callallpendingfinalizers(L); |
| 981 | } | 1031 | } |
| 982 | 1032 | ||
| 1033 | static void printgray (GCObject *o) { | ||
| 1034 | printf("gray: "); | ||
| 1035 | while (o) { | ||
| 1036 | printf("%p %d %02x ", (void*)o, o->tt, o->marked); | ||
| 1037 | switch (o->tt) { | ||
| 1038 | case LUA_TTABLE: { | ||
| 1039 | Table *h = gco2t(o); | ||
| 1040 | o = h->gclist; | ||
| 1041 | break; | ||
| 1042 | } | ||
| 1043 | case LUA_TLCL: { | ||
| 1044 | LClosure *cl = gco2lcl(o); | ||
| 1045 | o = cl->gclist; | ||
| 1046 | break; | ||
| 1047 | } | ||
| 1048 | case LUA_TCCL: { | ||
| 1049 | CClosure *cl = gco2ccl(o); | ||
| 1050 | o = cl->gclist; | ||
| 1051 | break; | ||
| 1052 | } | ||
| 1053 | case LUA_TTHREAD: { | ||
| 1054 | lua_State *th = gco2th(o); | ||
| 1055 | o = th->gclist; | ||
| 1056 | break; | ||
| 1057 | } | ||
| 1058 | case LUA_TPROTO: { | ||
| 1059 | Proto *p = gco2p(o); | ||
| 1060 | o = p->gclist; | ||
| 1061 | break; | ||
| 1062 | } | ||
| 1063 | default: lua_assert(0); return; | ||
| 1064 | } | ||
| 1065 | } | ||
| 1066 | printf("\n"); | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | |||
| 1070 | |||
| 1071 | static GCObject **correctgraylist (GCObject **p) { | ||
| 1072 | GCObject *curr; | ||
| 1073 | while ((curr = *p) != NULL) { | ||
| 1074 | switch (curr->tt) { | ||
| 1075 | case LUA_TTABLE: { | ||
| 1076 | Table *h = gco2t(curr); | ||
| 1077 | if (getage(h) == G_TOUCHED1) { /* touched in this cycle? */ | ||
| 1078 | lua_assert(isgray(h)); | ||
| 1079 | gray2black(h); /* make it black, for next barrier */ | ||
| 1080 | changeage(h, G_TOUCHED1, G_TOUCHED2); | ||
| 1081 | p = &h->gclist; /* go to next element */ | ||
| 1082 | } | ||
| 1083 | else { | ||
| 1084 | if (!iswhite(h)) { | ||
| 1085 | lua_assert(isold(h)); | ||
| 1086 | if (getage(h) == G_TOUCHED2) | ||
| 1087 | changeage(h, G_TOUCHED2, G_OLD); | ||
| 1088 | gray2black(h); /* make it black */ | ||
| 1089 | } | ||
| 1090 | *p = h->gclist; /* remove 'curr' from gray list */ | ||
| 1091 | } | ||
| 1092 | break; | ||
| 1093 | } | ||
| 1094 | case LUA_TTHREAD: { | ||
| 1095 | lua_State *th = gco2th(curr); | ||
| 1096 | lua_assert(!isblack(th)); | ||
| 1097 | if (iswhite(th)) /* new object? */ | ||
| 1098 | *p = th->gclist; /* remove from gray list */ | ||
| 1099 | else /* old threads remain gray */ | ||
| 1100 | p = &th->gclist; /* go to next element */ | ||
| 1101 | break; | ||
| 1102 | } | ||
| 1103 | default: lua_assert(0); /* nothing more could be gray here */ | ||
| 1104 | } | ||
| 1105 | } | ||
| 1106 | return p; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | |||
| 1110 | static void correctgraylists (global_State *g) { | ||
| 1111 | GCObject **list = correctgraylist(&g->grayagain); | ||
| 1112 | *list = g->weak; g->weak = NULL; | ||
| 1113 | list = correctgraylist(list); | ||
| 1114 | *list = g->allweak; g->allweak = NULL; | ||
| 1115 | list = correctgraylist(list); | ||
| 1116 | *list = g->ephemeron; g->ephemeron = NULL; | ||
| 1117 | correctgraylist(list); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | |||
| 1121 | static void markold (global_State *g, GCObject *from, GCObject *to) { | ||
| 1122 | GCObject *p; | ||
| 1123 | for (p = from; p != to; p = p->next) { | ||
| 1124 | if (getage(p) == G_OLD1) { | ||
| 1125 | lua_assert(!iswhite(p)); | ||
| 1126 | if (isblack(p)) { | ||
| 1127 | black2gray(p); /* should be '2white', but gray works too */ | ||
| 1128 | reallymarkobject(g, p); | ||
| 1129 | } | ||
| 1130 | else | ||
| 1131 | lua_assert(p->tt == LUA_TTHREAD); /* threads are always gray */ | ||
| 1132 | } | ||
| 1133 | } | ||
| 1134 | } | ||
| 1135 | |||
| 983 | 1136 | ||
| 984 | static void youngcollection (lua_State *L, global_State *g) { | 1137 | static void youngcollection (lua_State *L, global_State *g) { |
| 985 | GCObject **psurvival; | 1138 | GCObject **psurvival; |
| 986 | lua_assert(g->gcstate == GCSpropagate); | 1139 | lua_assert(g->gcstate == GCSpropagate); |
| 987 | startgencycle(L, g); | 1140 | markold(g, g->survival, g->reallyold); |
| 1141 | markold(g, g->finobj, g->finobjrold); /* ??? */ | ||
| 1142 | atomic(L); | ||
| 1143 | |||
| 988 | /* sweep nursery */ | 1144 | /* sweep nursery */ |
| 989 | psurvival = sweepgen(L, &g->allgc, g->survival, maskcolors, luaC_white(g)); | 1145 | psurvival = sweepgen(L, g, &g->allgc, g->survival); |
| 990 | lua_assert(*psurvival == g->survival); | 1146 | /* sweep 'survival' and 'old' */ |
| 991 | /* sweep 'survival' list, making elements old */ | 1147 | sweepgen(L, g, psurvival, g->reallyold); |
| 992 | sweepgen(L, psurvival, g->old, ~0, bitmask(OLDBIT)); | 1148 | g->reallyold = g->old; |
| 993 | /* incorporate 'survival' list into old list */ | 1149 | g->old = *psurvival; /* 'survival' survivals are old now */ |
| 994 | g->old = *psurvival; | 1150 | g->survival = g->allgc; /* all news are survivals */ |
| 995 | /* surviving young objects go to 'survival' list */ | 1151 | |
| 996 | g->survival = g->allgc; | 1152 | /* repeat for 'finobj' lists */ |
| 997 | finishgencycle(L, g, 0); | 1153 | psurvival = sweepgen(L, g, &g->finobj, g->finobjsur); |
| 998 | lua_checkmemory(L); | 1154 | /* sweep 'survival' and 'old' */ |
| 1155 | sweepgen(L, g, psurvival, g->finobjrold); | ||
| 1156 | g->finobjrold = g->finobjold; | ||
| 1157 | g->finobjold = *psurvival; /* 'survival' survivals are old now */ | ||
| 1158 | g->finobjsur = g->finobj; /* all news are survivals */ | ||
| 1159 | |||
| 1160 | sweepgen(L, g, &g->tobefnz, NULL); | ||
| 1161 | |||
| 1162 | finishgencycle(L, g); | ||
| 1163 | correctgraylists(g); | ||
| 1164 | //printf("check: \n");lua_checkmemory(L); | ||
| 999 | } | 1165 | } |
| 1000 | 1166 | ||
| 1001 | 1167 | ||
| 1002 | static void entergen (lua_State *L, global_State *g) { | 1168 | static void entergen (lua_State *L, global_State *g) { |
| 1003 | lua_checkmemory(L); | 1169 | lua_assert(g->reallyold == NULL && g->old == NULL && g->survival == NULL); |
| 1004 | lua_assert(g->old == NULL && g->survival == NULL); | ||
| 1005 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ | 1170 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ |
| 1006 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1171 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
| 1007 | startgencycle(L, g); | 1172 | atomic(L); |
| 1008 | /* sweep all ellements making them old */ | 1173 | /* sweep all ellements making them old */ |
| 1009 | sweepgen(L, &g->allgc, g->survival, ~0, bitmask(OLDBIT)); | 1174 | sweep2old(L, &g->allgc); |
| 1010 | /* everything alive now is old; 'survival' is empty */ | 1175 | /* everything alive now is old */ |
| 1011 | g->old = g->survival = g->allgc; | 1176 | g->reallyold = g->old = g->survival = g->allgc; |
| 1012 | finishgencycle(L, g, bitmask(OLDBIT)); | 1177 | |
| 1013 | lua_checkmemory(L); | 1178 | /* repeat for 'finobj' lists */ |
| 1179 | sweep2old(L, &g->finobj); | ||
| 1180 | g->finobjrold = g->finobjold = g->finobjsur = g->finobj; | ||
| 1181 | |||
| 1182 | finishgencycle(L, g); | ||
| 1183 | correctgraylists(g); | ||
| 1184 | g->gckind = KGC_GEN; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | |||
| 1188 | static void enterinc (global_State *g) { | ||
| 1189 | makewhite(g, g->mainthread); | ||
| 1190 | whitelist(g, g->allgc); | ||
| 1191 | g->reallyold = g->old = g->survival = NULL; | ||
| 1192 | whitelist(g, g->finobj); | ||
| 1193 | g->finobjrold = g->finobjold = g->finobjsur = NULL; | ||
| 1194 | lua_assert(g->tobefnz == NULL); /* no need to sweep */ | ||
| 1195 | g->gcstate = GCSpause; | ||
| 1196 | g->gckind = KGC_NORMAL; | ||
| 1014 | } | 1197 | } |
| 1015 | 1198 | ||
| 1016 | 1199 | ||
| @@ -1019,17 +1202,18 @@ void luaC_changemode (lua_State *L, int newmode) { | |||
| 1019 | if (newmode != g->gckind) { /* otherwise, nothing to be done */ | 1202 | if (newmode != g->gckind) { /* otherwise, nothing to be done */ |
| 1020 | if (newmode == KGC_GEN) /* entering generational mode? */ | 1203 | if (newmode == KGC_GEN) /* entering generational mode? */ |
| 1021 | entergen(L, g); | 1204 | entergen(L, g); |
| 1022 | else { /* entering incremental mode */ | 1205 | else |
| 1023 | lua_checkmemory(L); | 1206 | enterinc(g); /* entering incremental mode */ |
| 1024 | youngcollection(L, g); | ||
| 1025 | g->old = g->survival = NULL; | ||
| 1026 | lua_checkmemory(L); | ||
| 1027 | } | ||
| 1028 | g->gckind = newmode; | ||
| 1029 | } | 1207 | } |
| 1030 | } | 1208 | } |
| 1031 | 1209 | ||
| 1032 | 1210 | ||
| 1211 | static void fullgen (lua_State *L, global_State *g) { | ||
| 1212 | enterinc(g); | ||
| 1213 | entergen(L, g); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | |||
| 1033 | static void genstep (lua_State *L, global_State *g) { | 1217 | static void genstep (lua_State *L, global_State *g) { |
| 1034 | lu_mem mem; | 1218 | lu_mem mem; |
| 1035 | youngcollection(L, g); | 1219 | youngcollection(L, g); |
| @@ -1094,10 +1278,10 @@ static void deletealllist (lua_State *L, GCObject *p) { | |||
| 1094 | 1278 | ||
| 1095 | void luaC_freeallobjects (lua_State *L) { | 1279 | void luaC_freeallobjects (lua_State *L) { |
| 1096 | global_State *g = G(L); | 1280 | global_State *g = G(L); |
| 1281 | luaC_changemode(L, KGC_NORMAL); | ||
| 1097 | separatetobefnz(g, 1); /* separate all objects with finalizers */ | 1282 | separatetobefnz(g, 1); /* separate all objects with finalizers */ |
| 1098 | lua_assert(g->finobj == NULL); | 1283 | lua_assert(g->finobj == NULL); |
| 1099 | callallpendingfinalizers(L); | 1284 | callallpendingfinalizers(L); |
| 1100 | lua_assert(g->tobefnz == NULL); | ||
| 1101 | deletealllist(L, g->finobj); | 1285 | deletealllist(L, g->finobj); |
| 1102 | deletealllist(L, g->allgc); | 1286 | deletealllist(L, g->allgc); |
| 1103 | deletealllist(L, g->fixedgc); /* collect fixed objects */ | 1287 | deletealllist(L, g->fixedgc); /* collect fixed objects */ |
| @@ -1110,9 +1294,10 @@ static l_mem atomic (lua_State *L) { | |||
| 1110 | l_mem work; | 1294 | l_mem work; |
| 1111 | GCObject *origweak, *origall; | 1295 | GCObject *origweak, *origall; |
| 1112 | GCObject *grayagain = g->grayagain; /* save original list */ | 1296 | GCObject *grayagain = g->grayagain; /* save original list */ |
| 1297 | g->grayagain = NULL; | ||
| 1113 | lua_assert(g->ephemeron == NULL && g->weak == NULL); | 1298 | lua_assert(g->ephemeron == NULL && g->weak == NULL); |
| 1114 | lua_assert(!iswhite(g->mainthread)); | 1299 | lua_assert(!iswhite(g->mainthread)); |
| 1115 | g->gcstate = GCSinsideatomic; | 1300 | g->gcstate = GCSatomic; |
| 1116 | g->GCmemtrav = 0; /* start counting work */ | 1301 | g->GCmemtrav = 0; /* start counting work */ |
| 1117 | markobject(g, L); /* mark running thread */ | 1302 | markobject(g, L); /* mark running thread */ |
| 1118 | /* registry and global metatables may be changed by API */ | 1303 | /* registry and global metatables may be changed by API */ |
| @@ -1123,7 +1308,6 @@ static l_mem atomic (lua_State *L) { | |||
| 1123 | propagateall(g); /* propagate changes */ | 1308 | propagateall(g); /* propagate changes */ |
| 1124 | work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ | 1309 | work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ |
| 1125 | g->gray = grayagain; | 1310 | g->gray = grayagain; |
| 1126 | g->grayagain = NULL; | ||
| 1127 | propagateall(g); /* traverse 'grayagain' list */ | 1311 | propagateall(g); /* traverse 'grayagain' list */ |
| 1128 | g->GCmemtrav = 0; /* restart counting */ | 1312 | g->GCmemtrav = 0; /* restart counting */ |
| 1129 | convergeephemerons(g); | 1313 | convergeephemerons(g); |
| @@ -1141,13 +1325,14 @@ static l_mem atomic (lua_State *L) { | |||
| 1141 | convergeephemerons(g); | 1325 | convergeephemerons(g); |
| 1142 | /* at this point, all resurrected objects are marked. */ | 1326 | /* at this point, all resurrected objects are marked. */ |
| 1143 | /* remove dead objects from weak tables */ | 1327 | /* remove dead objects from weak tables */ |
| 1144 | clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ | 1328 | clearkeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ |
| 1145 | clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ | 1329 | clearkeys(g, g->allweak); /* clear keys from all 'allweak' tables */ |
| 1146 | /* clear values from resurrected weak tables */ | 1330 | /* clear values from resurrected weak tables */ |
| 1147 | clearvalues(g, g->weak, origweak); | 1331 | clearvalues(g, g->weak, origweak); |
| 1148 | clearvalues(g, g->allweak, origall); | 1332 | clearvalues(g, g->allweak, origall); |
| 1149 | luaS_clearcache(g); | 1333 | luaS_clearcache(g); |
| 1150 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1334 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
| 1335 | lua_assert(g->gray == NULL); | ||
| 1151 | work += g->GCmemtrav; /* complete counting */ | 1336 | work += g->GCmemtrav; /* complete counting */ |
| 1152 | return work; /* estimate of memory marked by 'atomic' */ | 1337 | return work; /* estimate of memory marked by 'atomic' */ |
| 1153 | } | 1338 | } |
| @@ -1181,12 +1366,12 @@ static lu_mem singlestep (lua_State *L) { | |||
| 1181 | case GCSpropagate: { | 1366 | case GCSpropagate: { |
| 1182 | g->GCmemtrav = 0; | 1367 | g->GCmemtrav = 0; |
| 1183 | if (g->gray == NULL) /* no more gray objects? */ | 1368 | if (g->gray == NULL) /* no more gray objects? */ |
| 1184 | g->gcstate = GCSatomic; /* finish propagate phase */ | 1369 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
| 1185 | else | 1370 | else |
| 1186 | propagatemark(g); /* traverse one gray object */ | 1371 | propagatemark(g); /* traverse one gray object */ |
| 1187 | return g->GCmemtrav; /* memory traversed in this step */ | 1372 | return g->GCmemtrav; /* memory traversed in this step */ |
| 1188 | } | 1373 | } |
| 1189 | case GCSatomic: { | 1374 | case GCSenteratomic: { |
| 1190 | lu_mem work; | 1375 | lu_mem work; |
| 1191 | propagateall(g); /* make sure gray list is empty */ | 1376 | propagateall(g); /* make sure gray list is empty */ |
| 1192 | work = atomic(L); /* work is what was traversed by 'atomic' */ | 1377 | work = atomic(L); /* work is what was traversed by 'atomic' */ |
| @@ -1291,23 +1476,31 @@ void luaC_step (lua_State *L) { | |||
| 1291 | ** to sweep all objects to turn them back to white (as white has not | 1476 | ** to sweep all objects to turn them back to white (as white has not |
| 1292 | ** changed, nothing will be collected). | 1477 | ** changed, nothing will be collected). |
| 1293 | */ | 1478 | */ |
| 1294 | void luaC_fullgc (lua_State *L, int isemergency) { | 1479 | static void fullinc (lua_State *L, global_State *g) { |
| 1295 | global_State *g = G(L); | 1480 | if (keepinvariant(g)) /* black objects? */ |
| 1296 | lua_assert(g->gckind == KGC_NORMAL); | ||
| 1297 | if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ | ||
| 1298 | if (keepinvariant(g)) { /* black objects? */ | ||
| 1299 | entersweep(L); /* sweep everything to turn them back to white */ | 1481 | entersweep(L); /* sweep everything to turn them back to white */ |
| 1300 | } | ||
| 1301 | /* finish any pending sweep phase to start a new cycle */ | 1482 | /* finish any pending sweep phase to start a new cycle */ |
| 1302 | luaC_runtilstate(L, bitmask(GCSpause)); | 1483 | luaC_runtilstate(L, bitmask(GCSpause)); |
| 1303 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | 1484 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
| 1304 | /* estimate must be correct after a full GC cycle */ | 1485 | /* estimate must be correct after a full GC cycle */ |
| 1305 | lua_assert(g->GCestimate == gettotalbytes(g)); | 1486 | lua_assert(g->GCestimate == gettotalbytes(g)); |
| 1306 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1487 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
| 1307 | g->gckind = KGC_NORMAL; | ||
| 1308 | setpause(g); | 1488 | setpause(g); |
| 1309 | } | 1489 | } |
| 1310 | 1490 | ||
| 1491 | |||
| 1492 | void luaC_fullgc (lua_State *L, int isemergency) { | ||
| 1493 | global_State *g = G(L); | ||
| 1494 | int gckind = g->gckind; | ||
| 1495 | if (isemergency) | ||
| 1496 | g->gckind = KGC_EMERGENCY; /* set flag */ | ||
| 1497 | if (gckind == KGC_NORMAL) | ||
| 1498 | fullinc(L, g); | ||
| 1499 | else | ||
| 1500 | fullgen(L, g); | ||
| 1501 | g->gckind = gckind; | ||
| 1502 | } | ||
| 1503 | |||
| 1311 | /* }====================================================== */ | 1504 | /* }====================================================== */ |
| 1312 | 1505 | ||
| 1313 | 1506 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.92 2017/02/23 21:07:34 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -37,13 +37,14 @@ | |||
| 37 | ** Possible states of the Garbage Collector | 37 | ** Possible states of the Garbage Collector |
| 38 | */ | 38 | */ |
| 39 | #define GCSpropagate 0 | 39 | #define GCSpropagate 0 |
| 40 | #define GCSatomic 1 | 40 | #define GCSenteratomic 1 |
| 41 | #define GCSswpallgc 2 | 41 | #define GCSatomic 2 |
| 42 | #define GCSswpfinobj 3 | 42 | #define GCSswpallgc 3 |
| 43 | #define GCSswptobefnz 4 | 43 | #define GCSswpfinobj 4 |
| 44 | #define GCSswpend 5 | 44 | #define GCSswptobefnz 5 |
| 45 | #define GCScallfin 6 | 45 | #define GCSswpend 6 |
| 46 | #define GCSpause 7 | 46 | #define GCScallfin 7 |
| 47 | #define GCSpause 8 | ||
| 47 | 48 | ||
| 48 | 49 | ||
| 49 | #define issweepphase(g) \ | 50 | #define issweepphase(g) \ |
| @@ -74,14 +75,17 @@ | |||
| 74 | #define testbit(x,b) testbits(x, bitmask(b)) | 75 | #define testbit(x,b) testbits(x, bitmask(b)) |
| 75 | 76 | ||
| 76 | 77 | ||
| 77 | /* Layout for bit use in 'marked' field: */ | 78 | /* |
| 78 | #define WHITE0BIT 0 /* object is white (type 0) */ | 79 | ** Layout for bit use in 'marked' field. First three bits are |
| 79 | #define WHITE1BIT 1 /* object is white (type 1) */ | 80 | ** used for object "age" in generational mode. |
| 80 | #define BLACKBIT 2 /* object is black */ | 81 | */ |
| 81 | #define FINALIZEDBIT 3 /* object has been marked for finalization */ | 82 | #define WHITE0BIT 3 /* object is white (type 0) */ |
| 82 | #define OLDBIT 4 /* object is old (gen. mode) */ | 83 | #define WHITE1BIT 4 /* object is white (type 1) */ |
| 84 | #define BLACKBIT 5 /* object is black */ | ||
| 85 | #define FINALIZEDBIT 6 /* object has been marked for finalization */ | ||
| 83 | #define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */ | 86 | #define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */ |
| 84 | 87 | ||
| 88 | |||
| 85 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | 89 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) |
| 86 | 90 | ||
| 87 | 91 | ||
| @@ -89,7 +93,6 @@ | |||
| 89 | #define isblack(x) testbit((x)->marked, BLACKBIT) | 93 | #define isblack(x) testbit((x)->marked, BLACKBIT) |
| 90 | #define isgray(x) /* neither white nor black */ \ | 94 | #define isgray(x) /* neither white nor black */ \ |
| 91 | (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) | 95 | (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) |
| 92 | #define isold(x) testbit((x)->marked, OLDBIT) | ||
| 93 | 96 | ||
| 94 | #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) | 97 | #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) |
| 95 | 98 | ||
| @@ -103,6 +106,27 @@ | |||
| 103 | #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) | 106 | #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) |
| 104 | 107 | ||
| 105 | 108 | ||
| 109 | /* object age in generational mode */ | ||
| 110 | #define G_NEW 0 /* created in current cycle */ | ||
| 111 | #define G_SURVIVAL 1 /* created in previous cycle */ | ||
| 112 | #define G_OLD1 2 /* first full cycle as old */ | ||
| 113 | #define G_OLD0 3 /* marked old by frw. barrier in this cycle */ | ||
| 114 | #define G_OLD 4 /* really old object (not to be visited) */ | ||
| 115 | #define G_TOUCHED1 5 /* old object touched this cycle */ | ||
| 116 | #define G_TOUCHED2 6 /* old object touched in previous cycle */ | ||
| 117 | |||
| 118 | #define AGEBITS 7 /* all age bits (111) */ | ||
| 119 | |||
| 120 | #define getage(o) ((o)->marked & AGEBITS) | ||
| 121 | #define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) | ||
| 122 | #define isold(o) (getage(o) > G_SURVIVAL) | ||
| 123 | |||
| 124 | #define changeage(o,f,t) \ | ||
| 125 | check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) | ||
| 126 | |||
| 127 | #define ongraylist(o) (isgray(o) || getage(o) == G_TOUCHED2) | ||
| 128 | |||
| 129 | |||
| 106 | /* | 130 | /* |
| 107 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' | 131 | ** Does one step of collection when debt becomes positive. 'pre'/'pos' |
| 108 | ** allows some adjustments to be done only when needed. macro | 132 | ** allows some adjustments to be done only when needed. macro |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.134 2017/02/23 21:07:34 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -319,7 +319,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 319 | g->gcstate = GCSpause; | 319 | g->gcstate = GCSpause; |
| 320 | g->gckind = KGC_NORMAL; | 320 | g->gckind = KGC_NORMAL; |
| 321 | g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; | 321 | g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; |
| 322 | g->survival = g->old = NULL; | 322 | g->survival = g->old = g->reallyold = NULL; |
| 323 | g->finobjsur = g->finobjold = g->finobjrold = NULL; | ||
| 323 | g->sweepgc = NULL; | 324 | g->sweepgc = NULL; |
| 324 | g->gray = g->grayagain = NULL; | 325 | g->gray = g->grayagain = NULL; |
| 325 | g->weak = g->ephemeron = g->allweak = NULL; | 326 | g->weak = g->ephemeron = g->allweak = NULL; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.134 2017/02/15 18:52:13 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.135 2017/02/23 21:07:34 roberto Exp $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -160,8 +160,12 @@ typedef struct global_State { | |||
| 160 | GCObject *tobefnz; /* list of userdata to be GC */ | 160 | GCObject *tobefnz; /* list of userdata to be GC */ |
| 161 | GCObject *fixedgc; /* list of objects not to be collected */ | 161 | GCObject *fixedgc; /* list of objects not to be collected */ |
| 162 | /* fields for generational collector */ | 162 | /* fields for generational collector */ |
| 163 | GCObject *old; /* start of old objects */ | ||
| 164 | GCObject *survival; /* start of objects that survived one GC cycle */ | 163 | GCObject *survival; /* start of objects that survived one GC cycle */ |
| 164 | GCObject *old; /* start of old objects */ | ||
| 165 | GCObject *reallyold; /* old objects with more than one cycle */ | ||
| 166 | GCObject *finobjsur; /* list of survival objects with finalizers */ | ||
| 167 | GCObject *finobjold; /* list of old objects with finalizers */ | ||
| 168 | GCObject *finobjrold; /* list of really old objects with finalizers */ | ||
| 165 | struct lua_State *twups; /* list of threads with open upvalues */ | 169 | struct lua_State *twups; /* list of threads with open upvalues */ |
| 166 | unsigned int gcfinnum; /* number of finalizers to call in each GC step */ | 170 | unsigned int gcfinnum; /* number of finalizers to call in each GC step */ |
| 167 | int gcpause; /* size of pause between successive GCs */ | 171 | int gcpause; /* size of pause between successive GCs */ |
