diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-27 15:53:35 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2013-08-27 15:53:35 -0300 |
commit | af35c7f398e8149b5f2481b63b399674e4ecdf7e (patch) | |
tree | 7d74f5c81bb0e2555cab4bce00a94a12a6d78604 /lgc.c | |
parent | 742b7377d38e43224ee5dda4bb83a42763c20af8 (diff) | |
download | lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.tar.gz lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.tar.bz2 lua-af35c7f398e8149b5f2481b63b399674e4ecdf7e.zip |
upvalues collected by reference count
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 142 |
1 files changed, 58 insertions, 84 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.151 2013/08/23 13:34:54 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.152 2013/08/26 12:41:10 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 | */ |
@@ -85,12 +85,9 @@ | |||
85 | lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ | 85 | lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \ |
86 | marklocalvalue(g,o); } | 86 | marklocalvalue(g,o); } |
87 | 87 | ||
88 | #define marklocalobject(g,t) { \ | ||
89 | if ((t) && iswhite(obj2gco(t))) \ | ||
90 | reallymarkobject(g, obj2gco(t)); } | ||
91 | |||
92 | #define markobject(g,t) \ | 88 | #define markobject(g,t) \ |
93 | { lua_assert((t) == NULL || !islocal(obj2gco(t))); marklocalobject(g,t); } | 89 | { lua_assert((t) == NULL || !islocal(obj2gco(t))); \ |
90 | if ((t) && iswhite(obj2gco(t))) reallymarkobject(g, obj2gco(t)); } | ||
94 | 91 | ||
95 | static void reallymarkobject (global_State *g, GCObject *o); | 92 | static void reallymarkobject (global_State *g, GCObject *o); |
96 | 93 | ||
@@ -176,22 +173,18 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) { | |||
176 | 173 | ||
177 | 174 | ||
178 | /* | 175 | /* |
179 | ** check color (and invariants) for an upvalue that is being closed, | 176 | ** barrier for assignments to closed upvalues. Because upvalues are |
180 | ** i.e., moved into the 'allgc' list | 177 | ** shared among closures, it is impossible to know the color of all |
178 | ** closured pointing to it. So, we assume that the object being assigned | ||
179 | ** must be marked. | ||
181 | */ | 180 | */ |
182 | void luaC_checkupvalcolor (global_State *g, UpVal *uv) { | 181 | LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { |
183 | GCObject *o = obj2gco(uv); | 182 | global_State *g = G(L); |
184 | lua_assert(!isblack(o)); /* open upvalues are never black */ | 183 | GCObject *o = gcvalue(uv->v); |
185 | if (isgray(o)) { | 184 | lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ |
186 | if (keepinvariant(g)) { | 185 | nolocal(o); |
187 | gray2black(o); /* it is being visited now */ | 186 | if (keepinvariant(g)) |
188 | markvalue(g, uv->v); | 187 | markobject(g, o); |
189 | } | ||
190 | else { | ||
191 | lua_assert(issweepphase(g)); | ||
192 | makewhite(g, o); | ||
193 | } | ||
194 | } | ||
195 | } | 188 | } |
196 | 189 | ||
197 | 190 | ||
@@ -257,14 +250,6 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
257 | size = sizeudata(gco2u(o)); | 250 | size = sizeudata(gco2u(o)); |
258 | break; | 251 | break; |
259 | } | 252 | } |
260 | case LUA_TUPVAL: { | ||
261 | UpVal *uv = gco2uv(o); | ||
262 | marklocalvalue(g, uv->v); | ||
263 | if (uv->v != &uv->value) /* open? */ | ||
264 | return; /* open upvalues remain gray */ | ||
265 | size = sizeof(UpVal); | ||
266 | break; | ||
267 | } | ||
268 | case LUA_TLCL: { | 253 | case LUA_TLCL: { |
269 | gco2lcl(o)->gclist = g->gray; | 254 | gco2lcl(o)->gclist = g->gray; |
270 | g->gray = o; | 255 | g->gray = o; |
@@ -328,10 +313,12 @@ static void remarkupvals (global_State *g) { | |||
328 | for (; thread != NULL; thread = gch(thread)->next) { | 313 | for (; thread != NULL; thread = gch(thread)->next) { |
329 | lua_assert(!isblack(thread)); /* threads are never black */ | 314 | lua_assert(!isblack(thread)); /* threads are never black */ |
330 | if (!isgray(thread)) { /* dead thread? */ | 315 | if (!isgray(thread)) { /* dead thread? */ |
331 | GCObject *uv = gco2th(thread)->openupval; | 316 | UpVal *uv = gco2th(thread)->openupval; |
332 | for (; uv != NULL; uv = gch(uv)->next) { | 317 | for (; uv != NULL; uv = uv->u.op.next) { |
333 | if (isgray(uv)) /* marked? */ | 318 | if (uv->u.op.touched) { |
334 | marklocalvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ | 319 | marklocalvalue(g, uv->v); /* remark upvalue's value */ |
320 | uv->u.op.touched = 0; | ||
321 | } | ||
335 | } | 322 | } |
336 | } | 323 | } |
337 | } | 324 | } |
@@ -493,8 +480,15 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
493 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 480 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
494 | int i; | 481 | int i; |
495 | markobject(g, cl->p); /* mark its prototype */ | 482 | markobject(g, cl->p); /* mark its prototype */ |
496 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ | 483 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ |
497 | marklocalobject(g, cl->upvals[i]); | 484 | UpVal *uv = cl->upvals[i]; |
485 | if (uv != NULL) { | ||
486 | if (upisopen(uv)) | ||
487 | uv->u.op.touched = 1; /* can be marked in 'remarkupvals' */ | ||
488 | else | ||
489 | markvalue(g, uv->v); | ||
490 | } | ||
491 | } | ||
498 | return sizeLclosure(cl->nupvalues); | 492 | return sizeLclosure(cl->nupvalues); |
499 | } | 493 | } |
500 | 494 | ||
@@ -511,10 +505,14 @@ static lu_mem traversestack (global_State *g, lua_State *th) { | |||
511 | for (; o < lim; o++) /* clear not-marked stack slice */ | 505 | for (; o < lim; o++) /* clear not-marked stack slice */ |
512 | setnilvalue(o); | 506 | setnilvalue(o); |
513 | } | 507 | } |
514 | else { /* count call infos to compute size */ | 508 | else { |
515 | CallInfo *ci; | 509 | CallInfo *ci; |
510 | luaE_freeCI(th); /* free extra CallInfo slots */ | ||
516 | for (ci = &th->base_ci; ci != th->ci; ci = ci->next) | 511 | for (ci = &th->base_ci; ci != th->ci; ci = ci->next) |
517 | n++; | 512 | n++; /* count call infos to compute size */ |
513 | /* should not change the stack during an emergency gc cycle */ | ||
514 | if (g->gckind != KGC_EMERGENCY) | ||
515 | luaD_shrinkstack(th); | ||
518 | } | 516 | } |
519 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | 517 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + |
520 | sizeof(CallInfo) * n; | 518 | sizeof(CallInfo) * n; |
@@ -667,18 +665,36 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { | |||
667 | } | 665 | } |
668 | 666 | ||
669 | 667 | ||
668 | void luaC_upvdeccount (lua_State *L, UpVal *uv) { | ||
669 | lua_assert(uv->refcount > 0); | ||
670 | uv->refcount--; | ||
671 | if (uv->refcount == 0 && !upisopen(uv)) | ||
672 | luaM_free(L, uv); | ||
673 | } | ||
674 | |||
675 | |||
676 | static void freeLclosure (lua_State *L, LClosure *cl) { | ||
677 | int i; | ||
678 | for (i = 0; i < cl->nupvalues; i++) { | ||
679 | UpVal *uv = cl->upvals[i]; | ||
680 | if (uv) | ||
681 | luaC_upvdeccount(L, uv); | ||
682 | } | ||
683 | luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); | ||
684 | } | ||
685 | |||
686 | |||
670 | static void freeobj (lua_State *L, GCObject *o) { | 687 | static void freeobj (lua_State *L, GCObject *o) { |
671 | switch (gch(o)->tt) { | 688 | switch (gch(o)->tt) { |
672 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; | 689 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; |
673 | case LUA_TLCL: { | 690 | case LUA_TLCL: { |
674 | luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); | 691 | freeLclosure(L, gco2lcl(o)); |
675 | break; | 692 | break; |
676 | } | 693 | } |
677 | case LUA_TCCL: { | 694 | case LUA_TCCL: { |
678 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); | 695 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); |
679 | break; | 696 | break; |
680 | } | 697 | } |
681 | case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; | ||
682 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; | 698 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; |
683 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; | 699 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; |
684 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; | 700 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; |
@@ -699,20 +715,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); | |||
699 | 715 | ||
700 | 716 | ||
701 | /* | 717 | /* |
702 | ** sweep the (open) upvalues of a thread and resize its stack and | ||
703 | ** list of call-info structures. | ||
704 | */ | ||
705 | static void sweepthread (lua_State *L, lua_State *L1) { | ||
706 | if (L1->stack == NULL) return; /* stack not completely built yet */ | ||
707 | sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ | ||
708 | luaE_freeCI(L1); /* free extra CallInfo slots */ | ||
709 | /* should not change the stack during an emergency gc cycle */ | ||
710 | if (G(L)->gckind != KGC_EMERGENCY) | ||
711 | luaD_shrinkstack(L1); | ||
712 | } | ||
713 | |||
714 | |||
715 | /* | ||
716 | ** sweep at most 'count' elements from a list of GCObjects erasing dead | 718 | ** sweep at most 'count' elements from a list of GCObjects erasing dead |
717 | ** objects, where a dead (not alive) object is one marked with the "old" | 719 | ** objects, where a dead (not alive) object is one marked with the "old" |
718 | ** (non current) white and not fixed; change all non-dead objects back | 720 | ** (non current) white and not fixed; change all non-dead objects back |
@@ -730,10 +732,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
730 | *p = gch(curr)->next; /* remove 'curr' from list */ | 732 | *p = gch(curr)->next; /* remove 'curr' from list */ |
731 | freeobj(L, curr); /* erase 'curr' */ | 733 | freeobj(L, curr); /* erase 'curr' */ |
732 | } | 734 | } |
733 | else { | 735 | else { /* update marks */ |
734 | if (gch(curr)->tt == LUA_TTHREAD) | ||
735 | sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ | ||
736 | /* update marks */ | ||
737 | gch(curr)->marked = cast_byte((marked & maskcolors) | white); | 736 | gch(curr)->marked = cast_byte((marked & maskcolors) | white); |
738 | p = &gch(curr)->next; /* go to next element */ | 737 | p = &gch(curr)->next; /* go to next element */ |
739 | } | 738 | } |
@@ -886,16 +885,6 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
886 | */ | 885 | */ |
887 | 886 | ||
888 | 887 | ||
889 | static void localmarkclosure (LClosure *cl, int bit) { | ||
890 | int i; | ||
891 | for (i = 0; i < cl->nupvalues; i++) { | ||
892 | if (cl->upvals[i]) { | ||
893 | l_setbit(cl->upvals[i]->marked, bit); | ||
894 | } | ||
895 | } | ||
896 | } | ||
897 | |||
898 | |||
899 | /* | 888 | /* |
900 | ** Traverse a thread, local marking all its collectable objects | 889 | ** Traverse a thread, local marking all its collectable objects |
901 | */ | 890 | */ |
@@ -904,16 +893,8 @@ static void localmarkthread (lua_State *l) { | |||
904 | if (o == NULL) | 893 | if (o == NULL) |
905 | return; /* stack not completely built yet */ | 894 | return; /* stack not completely built yet */ |
906 | for (; o < l->top; o++) { /* mark live elements in the stack */ | 895 | for (; o < l->top; o++) { /* mark live elements in the stack */ |
907 | if (iscollectable(o)) { | 896 | if (iscollectable(o)) |
908 | GCObject *obj = gcvalue(o); | 897 | l_setbit(gcvalue(o)->gch.marked, LOCALBLACK); |
909 | if (obj->gch.tt == LUA_TLCL && /* is it a Lua closure? */ | ||
910 | islocal(obj) && /* is it still local? */ | ||
911 | !testbit(obj->gch.marked, LOCALBLACK)) { /* not visited yet? */ | ||
912 | /* mark its upvalues as local black */ | ||
913 | localmarkclosure(gco2lcl(obj), LOCALBLACK); | ||
914 | } | ||
915 | l_setbit(obj->gch.marked, LOCALBLACK); | ||
916 | } | ||
917 | } | 898 | } |
918 | } | 899 | } |
919 | 900 | ||
@@ -937,10 +918,6 @@ static void localsweep (lua_State *L, global_State *g, GCObject **p) { | |||
937 | *p = curr->gch.next; /* remove 'curr' from list */ | 918 | *p = curr->gch.next; /* remove 'curr' from list */ |
938 | curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ | 919 | curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ |
939 | g->allgc = curr; | 920 | g->allgc = curr; |
940 | if (curr->gch.tt == LUA_TLCL) { /* is it a Lua closure? */ | ||
941 | /* mark its upvalues as non local */ | ||
942 | localmarkclosure(gco2lcl(curr), LOCALBIT); | ||
943 | } | ||
944 | } | 921 | } |
945 | else { /* still local */ | 922 | else { /* still local */ |
946 | if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ | 923 | if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ |
@@ -965,7 +942,6 @@ static void luaC_localcollection (lua_State *L) { | |||
965 | lua_assert(g->gcstate == GCSpause); | 942 | lua_assert(g->gcstate == GCSpause); |
966 | localmark(g); | 943 | localmark(g); |
967 | localsweep(L, g, &g->localgc); | 944 | localsweep(L, g, &g->localgc); |
968 | localsweep(L, g, &g->localupv); | ||
969 | } | 945 | } |
970 | 946 | ||
971 | /* }====================================================== */ | 947 | /* }====================================================== */ |
@@ -1036,7 +1012,6 @@ void luaC_freeallobjects (lua_State *L) { | |||
1036 | g->gckind = KGC_NORMAL; | 1012 | g->gckind = KGC_NORMAL; |
1037 | sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ | 1013 | sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ |
1038 | sweepwholelist(L, &g->localgc); | 1014 | sweepwholelist(L, &g->localgc); |
1039 | sweepwholelist(L, &g->localupv); | ||
1040 | sweepwholelist(L, &g->allgc); | 1015 | sweepwholelist(L, &g->allgc); |
1041 | sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ | 1016 | sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ |
1042 | lua_assert(g->strt.nuse == 0); | 1017 | lua_assert(g->strt.nuse == 0); |
@@ -1119,7 +1094,6 @@ static lu_mem singlestep (lua_State *L) { | |||
1119 | } | 1094 | } |
1120 | else { | 1095 | else { |
1121 | sweepwholelist(L, &g->localgc); | 1096 | sweepwholelist(L, &g->localgc); |
1122 | sweepwholelist(L, &g->localupv); | ||
1123 | g->gcstate = GCSsweep; | 1097 | g->gcstate = GCSsweep; |
1124 | return GCLOCALPAUSE / 4; /* some magic for now */ | 1098 | return GCLOCALPAUSE / 4; /* some magic for now */ |
1125 | } | 1099 | } |