diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-09-19 19:02:14 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-09-19 19:02:14 -0300 |
commit | ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba (patch) | |
tree | df467dc5dc5c64a21bb976ec661796d17d37f791 | |
parent | b443145ff3415fcaee903a7d95fa7212df5a77db (diff) | |
download | lua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.tar.gz lua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.tar.bz2 lua-ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba.zip |
GC back to controling pace counting bytes
Memory is the resource we want to save. Still to be reviewed again.
-rw-r--r-- | lapi.c | 19 | ||||
-rw-r--r-- | lauxlib.c | 1 | ||||
-rw-r--r-- | lgc.c | 307 | ||||
-rw-r--r-- | lgc.h | 34 | ||||
-rw-r--r-- | llimits.h | 19 | ||||
-rw-r--r-- | lmem.c | 8 | ||||
-rw-r--r-- | lobject.c | 12 | ||||
-rw-r--r-- | lobject.h | 2 | ||||
-rw-r--r-- | lstate.c | 14 | ||||
-rw-r--r-- | lstate.h | 15 | ||||
-rw-r--r-- | ltests.c | 18 |
11 files changed, 247 insertions, 202 deletions
@@ -53,16 +53,6 @@ const char lua_ident[] = | |||
53 | #define isupvalue(i) ((i) < LUA_REGISTRYINDEX) | 53 | #define isupvalue(i) ((i) < LUA_REGISTRYINDEX) |
54 | 54 | ||
55 | 55 | ||
56 | /* Advance the garbage collector when creating large objects */ | ||
57 | static void advancegc (lua_State *L, size_t delta) { | ||
58 | delta >>= 5; /* one object for each 32 bytes (empirical) */ | ||
59 | if (delta > 0) { | ||
60 | global_State *g = G(L); | ||
61 | luaE_setdebt(g, g->GCdebt - cast(l_obj, delta)); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | |||
66 | /* | 56 | /* |
67 | ** Convert an acceptable index to a pointer to its respective value. | 57 | ** Convert an acceptable index to a pointer to its respective value. |
68 | ** Non-valid indices return the special nil value 'G(L)->nilvalue'. | 58 | ** Non-valid indices return the special nil value 'G(L)->nilvalue'. |
@@ -540,7 +530,6 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { | |||
540 | ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); | 530 | ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); |
541 | setsvalue2s(L, L->top.p, ts); | 531 | setsvalue2s(L, L->top.p, ts); |
542 | api_incr_top(L); | 532 | api_incr_top(L); |
543 | advancegc(L, len); | ||
544 | luaC_checkGC(L); | 533 | luaC_checkGC(L); |
545 | lua_unlock(L); | 534 | lua_unlock(L); |
546 | return getstr(ts); | 535 | return getstr(ts); |
@@ -557,7 +546,6 @@ LUA_API const char *lua_pushextlstring (lua_State *L, | |||
557 | setsvalue2s(L, L->top.p, ts); | 546 | setsvalue2s(L, L->top.p, ts); |
558 | api_incr_top(L); | 547 | api_incr_top(L); |
559 | if (falloc != NULL) /* non-static string? */ | 548 | if (falloc != NULL) /* non-static string? */ |
560 | advancegc(L, len); /* count its memory */ | ||
561 | luaC_checkGC(L); | 549 | luaC_checkGC(L); |
562 | lua_unlock(L); | 550 | lua_unlock(L); |
563 | return getstr(ts); | 551 | return getstr(ts); |
@@ -1190,16 +1178,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
1190 | } | 1178 | } |
1191 | case LUA_GCCOUNT: { | 1179 | case LUA_GCCOUNT: { |
1192 | /* GC values are expressed in Kbytes: #bytes/2^10 */ | 1180 | /* GC values are expressed in Kbytes: #bytes/2^10 */ |
1193 | res = cast_int(g->GCtotalbytes >> 10); | 1181 | res = cast_int(gettotalbytes(g) >> 10); |
1194 | break; | 1182 | break; |
1195 | } | 1183 | } |
1196 | case LUA_GCCOUNTB: { | 1184 | case LUA_GCCOUNTB: { |
1197 | res = cast_int(g->GCtotalbytes & 0x3ff); | 1185 | res = cast_int(gettotalbytes(g) & 0x3ff); |
1198 | break; | 1186 | break; |
1199 | } | 1187 | } |
1200 | case LUA_GCSTEP: { | 1188 | case LUA_GCSTEP: { |
1201 | lu_byte oldstp = g->gcstp; | 1189 | lu_byte oldstp = g->gcstp; |
1202 | l_obj n = cast(l_obj, va_arg(argp, size_t)); | 1190 | l_mem n = cast(l_mem, va_arg(argp, size_t)); |
1203 | int work = 0; /* true if GC did some work */ | 1191 | int work = 0; /* true if GC did some work */ |
1204 | g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ | 1192 | g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ |
1205 | if (n <= 0) | 1193 | if (n <= 0) |
@@ -1356,7 +1344,6 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { | |||
1356 | u = luaS_newudata(L, size, cast(unsigned short, nuvalue)); | 1344 | u = luaS_newudata(L, size, cast(unsigned short, nuvalue)); |
1357 | setuvalue(L, s2v(L->top.p), u); | 1345 | setuvalue(L, s2v(L->top.p), u); |
1358 | api_incr_top(L); | 1346 | api_incr_top(L); |
1359 | advancegc(L, size); | ||
1360 | luaC_checkGC(L); | 1347 | luaC_checkGC(L); |
1361 | lua_unlock(L); | 1348 | lua_unlock(L); |
1362 | return getudatamem(u); | 1349 | return getudatamem(u); |
@@ -618,6 +618,7 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | |||
618 | box->bsize = 0; box->box = NULL; | 618 | box->bsize = 0; box->box = NULL; |
619 | lua_pushextlstring(L, s, len, allocf, ud); | 619 | lua_pushextlstring(L, s, len, allocf, ud); |
620 | lua_closeslot(L, -2); /* close the box */ | 620 | lua_closeslot(L, -2); /* close the box */ |
621 | lua_gc(L, LUA_GCSTEP, len); | ||
621 | } | 622 | } |
622 | lua_remove(L, -2); /* remove box or placeholder from the stack */ | 623 | lua_remove(L, -2); /* remove box or placeholder from the stack */ |
623 | } | 624 | } |
@@ -18,7 +18,6 @@ | |||
18 | #include "ldo.h" | 18 | #include "ldo.h" |
19 | #include "lfunc.h" | 19 | #include "lfunc.h" |
20 | #include "lgc.h" | 20 | #include "lgc.h" |
21 | #include "llex.h" | ||
22 | #include "lmem.h" | 21 | #include "lmem.h" |
23 | #include "lobject.h" | 22 | #include "lobject.h" |
24 | #include "lstate.h" | 23 | #include "lstate.h" |
@@ -28,13 +27,6 @@ | |||
28 | 27 | ||
29 | 28 | ||
30 | /* | 29 | /* |
31 | ** Number of fixed (luaC_fix) objects in a Lua state: metafield names, | ||
32 | ** plus reserved words, plus "_ENV", plus the memory-error message. | ||
33 | */ | ||
34 | #define NFIXED (TM_N + NUM_RESERVED + 2) | ||
35 | |||
36 | |||
37 | /* | ||
38 | ** Maximum number of elements to sweep in each single step. | 30 | ** Maximum number of elements to sweep in each single step. |
39 | ** (Large enough to dissipate fixed overheads but small enough | 31 | ** (Large enough to dissipate fixed overheads but small enough |
40 | ** to allow small steps for the collector.) | 32 | ** to allow small steps for the collector.) |
@@ -42,6 +34,12 @@ | |||
42 | #define GCSWEEPMAX 20 | 34 | #define GCSWEEPMAX 20 |
43 | 35 | ||
44 | 36 | ||
37 | /* | ||
38 | ** Cost (in work units) of running one finalizer. | ||
39 | */ | ||
40 | #define CWUFIN 10 | ||
41 | |||
42 | |||
45 | /* mask with all color bits */ | 43 | /* mask with all color bits */ |
46 | #define maskcolors (bitmask(BLACKBIT) | WHITEBITS) | 44 | #define maskcolors (bitmask(BLACKBIT) | WHITEBITS) |
47 | 45 | ||
@@ -95,7 +93,7 @@ | |||
95 | 93 | ||
96 | 94 | ||
97 | static void reallymarkobject (global_State *g, GCObject *o); | 95 | static void reallymarkobject (global_State *g, GCObject *o); |
98 | static l_obj atomic (lua_State *L); | 96 | static void atomic (lua_State *L); |
99 | static void entersweep (lua_State *L); | 97 | static void entersweep (lua_State *L); |
100 | 98 | ||
101 | 99 | ||
@@ -112,6 +110,66 @@ static void entersweep (lua_State *L); | |||
112 | #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) | 110 | #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) |
113 | 111 | ||
114 | 112 | ||
113 | static size_t objsize (GCObject *o) { | ||
114 | switch (o->tt) { | ||
115 | case LUA_VTABLE: { | ||
116 | /* Fow now, table size does not consider 'haslastfree' */ | ||
117 | Table *t = gco2t(o); | ||
118 | size_t sz = sizeof(Table) | ||
119 | + luaH_realasize(t) * (sizeof(Value) + 1); | ||
120 | if (!isdummy(t)) | ||
121 | sz += sizenode(t) * sizeof(Node); | ||
122 | return sz; | ||
123 | } | ||
124 | case LUA_VLCL: { | ||
125 | LClosure *cl = gco2lcl(o); | ||
126 | return sizeLclosure(cl->nupvalues); | ||
127 | } | ||
128 | case LUA_VCCL: { | ||
129 | CClosure *cl = gco2ccl(o); | ||
130 | return sizeCclosure(cl->nupvalues); | ||
131 | break; | ||
132 | } | ||
133 | case LUA_VUSERDATA: { | ||
134 | Udata *u = gco2u(o); | ||
135 | return sizeudata(u->nuvalue, u->len); | ||
136 | } | ||
137 | case LUA_VPROTO: { | ||
138 | Proto *p = gco2p(o); | ||
139 | size_t sz = sizeof(Proto) | ||
140 | + cast_uint(p->sizep) * sizeof(Proto*) | ||
141 | + cast_uint(p->sizek) * sizeof(TValue) | ||
142 | + cast_uint(p->sizelocvars) * sizeof(LocVar) | ||
143 | + cast_uint(p->sizeupvalues) * sizeof(Upvaldesc); | ||
144 | if (!(p->flag & PF_FIXED)) { | ||
145 | sz += cast_uint(p->sizecode) * sizeof(Instruction) | ||
146 | + cast_uint(p->sizelineinfo) * sizeof(lu_byte) | ||
147 | + cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo); | ||
148 | } | ||
149 | return sz; | ||
150 | } | ||
151 | case LUA_VTHREAD: { | ||
152 | lua_State *L1 = gco2th(o); | ||
153 | size_t sz = sizeof(lua_State) + LUA_EXTRASPACE | ||
154 | + cast_uint(L1->nci) * sizeof(CallInfo); | ||
155 | if (L1->stack.p != NULL) | ||
156 | sz += cast_uint(stacksize(L1) + EXTRA_STACK) * sizeof(StackValue); | ||
157 | return sz; | ||
158 | } | ||
159 | case LUA_VSHRSTR: { | ||
160 | TString *ts = gco2ts(o); | ||
161 | return sizestrshr(cast_uint(ts->shrlen)); | ||
162 | } | ||
163 | case LUA_VLNGSTR: { | ||
164 | TString *ts = gco2ts(o); | ||
165 | return luaS_sizelngstr(ts->u.lnglen, ts->shrlen); | ||
166 | } | ||
167 | case LUA_VUPVAL: return sizeof(UpVal); | ||
168 | default: lua_assert(0); return 0; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | |||
115 | static GCObject **getgclist (GCObject *o) { | 173 | static GCObject **getgclist (GCObject *o) { |
116 | switch (o->tt) { | 174 | switch (o->tt) { |
117 | case LUA_VTABLE: return &gco2t(o)->gclist; | 175 | case LUA_VTABLE: return &gco2t(o)->gclist; |
@@ -250,7 +308,6 @@ GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, size_t offset) { | |||
250 | global_State *g = G(L); | 308 | global_State *g = G(L); |
251 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); | 309 | char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); |
252 | GCObject *o = cast(GCObject *, p + offset); | 310 | GCObject *o = cast(GCObject *, p + offset); |
253 | g->GCdebt--; | ||
254 | o->marked = luaC_white(g); | 311 | o->marked = luaC_white(g); |
255 | o->tt = tt; | 312 | o->tt = tt; |
256 | o->next = g->allgc; | 313 | o->next = g->allgc; |
@@ -290,7 +347,7 @@ GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz) { | |||
290 | ** (only closures can), and a userdata's metatable must be a table. | 347 | ** (only closures can), and a userdata's metatable must be a table. |
291 | */ | 348 | */ |
292 | static void reallymarkobject (global_State *g, GCObject *o) { | 349 | static void reallymarkobject (global_State *g, GCObject *o) { |
293 | g->GCmarked++; | 350 | g->GCmarked += cast(l_mem, objsize(o)); |
294 | switch (o->tt) { | 351 | switch (o->tt) { |
295 | case LUA_VSHRSTR: | 352 | case LUA_VSHRSTR: |
296 | case LUA_VLNGSTR: { | 353 | case LUA_VLNGSTR: { |
@@ -338,14 +395,10 @@ static void markmt (global_State *g) { | |||
338 | /* | 395 | /* |
339 | ** mark all objects in list of being-finalized | 396 | ** mark all objects in list of being-finalized |
340 | */ | 397 | */ |
341 | static l_obj markbeingfnz (global_State *g) { | 398 | static void markbeingfnz (global_State *g) { |
342 | GCObject *o; | 399 | GCObject *o; |
343 | l_obj count = 0; | 400 | for (o = g->tobefnz; o != NULL; o = o->next) |
344 | for (o = g->tobefnz; o != NULL; o = o->next) { | ||
345 | count++; | ||
346 | markobject(g, o); | 401 | markobject(g, o); |
347 | } | ||
348 | return count; | ||
349 | } | 402 | } |
350 | 403 | ||
351 | 404 | ||
@@ -360,8 +413,7 @@ static l_obj markbeingfnz (global_State *g) { | |||
360 | ** upvalues, as they have nothing to be checked. (If the thread gets an | 413 | ** upvalues, as they have nothing to be checked. (If the thread gets an |
361 | ** upvalue later, it will be linked in the list again.) | 414 | ** upvalue later, it will be linked in the list again.) |
362 | */ | 415 | */ |
363 | static l_obj remarkupvals (global_State *g) { | 416 | static void remarkupvals (global_State *g) { |
364 | l_obj work = 0; | ||
365 | lua_State *thread; | 417 | lua_State *thread; |
366 | lua_State **p = &g->twups; | 418 | lua_State **p = &g->twups; |
367 | while ((thread = *p) != NULL) { | 419 | while ((thread = *p) != NULL) { |
@@ -380,9 +432,7 @@ static l_obj remarkupvals (global_State *g) { | |||
380 | } | 432 | } |
381 | } | 433 | } |
382 | } | 434 | } |
383 | work++; | ||
384 | } | 435 | } |
385 | return work; | ||
386 | } | 436 | } |
387 | 437 | ||
388 | 438 | ||
@@ -401,7 +451,7 @@ static void cleargraylists (global_State *g) { | |||
401 | */ | 451 | */ |
402 | static void restartcollection (global_State *g) { | 452 | static void restartcollection (global_State *g) { |
403 | cleargraylists(g); | 453 | cleargraylists(g); |
404 | g->GCmarked = NFIXED; | 454 | g->GCmarked = 0; |
405 | markobject(g, g->mainthread); | 455 | markobject(g, g->mainthread); |
406 | markvalue(g, &g->l_registry); | 456 | markvalue(g, &g->l_registry); |
407 | markmt(g); | 457 | markmt(g); |
@@ -546,7 +596,7 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
546 | } | 596 | } |
547 | 597 | ||
548 | 598 | ||
549 | static void traversetable (global_State *g, Table *h) { | 599 | static l_mem traversetable (global_State *g, Table *h) { |
550 | const char *weakkey, *weakvalue; | 600 | const char *weakkey, *weakvalue; |
551 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); | 601 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); |
552 | TString *smode; | 602 | TString *smode; |
@@ -565,15 +615,17 @@ static void traversetable (global_State *g, Table *h) { | |||
565 | } | 615 | } |
566 | else /* not weak */ | 616 | else /* not weak */ |
567 | traversestrongtable(g, h); | 617 | traversestrongtable(g, h); |
618 | return 1 + sizenode(h) + h->alimit; | ||
568 | } | 619 | } |
569 | 620 | ||
570 | 621 | ||
571 | static void traverseudata (global_State *g, Udata *u) { | 622 | static l_mem traverseudata (global_State *g, Udata *u) { |
572 | int i; | 623 | int i; |
573 | markobjectN(g, u->metatable); /* mark its metatable */ | 624 | markobjectN(g, u->metatable); /* mark its metatable */ |
574 | for (i = 0; i < u->nuvalue; i++) | 625 | for (i = 0; i < u->nuvalue; i++) |
575 | markvalue(g, &u->uv[i].uv); | 626 | markvalue(g, &u->uv[i].uv); |
576 | genlink(g, obj2gco(u)); | 627 | genlink(g, obj2gco(u)); |
628 | return 1 + u->nuvalue; | ||
577 | } | 629 | } |
578 | 630 | ||
579 | 631 | ||
@@ -582,7 +634,7 @@ static void traverseudata (global_State *g, Udata *u) { | |||
582 | ** arrays can be larger than needed; the extra slots are filled with | 634 | ** arrays can be larger than needed; the extra slots are filled with |
583 | ** NULL, so the use of 'markobjectN') | 635 | ** NULL, so the use of 'markobjectN') |
584 | */ | 636 | */ |
585 | static void traverseproto (global_State *g, Proto *f) { | 637 | static l_mem traverseproto (global_State *g, Proto *f) { |
586 | int i; | 638 | int i; |
587 | markobjectN(g, f->source); | 639 | markobjectN(g, f->source); |
588 | for (i = 0; i < f->sizek; i++) /* mark literals */ | 640 | for (i = 0; i < f->sizek; i++) /* mark literals */ |
@@ -593,26 +645,29 @@ static void traverseproto (global_State *g, Proto *f) { | |||
593 | markobjectN(g, f->p[i]); | 645 | markobjectN(g, f->p[i]); |
594 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ | 646 | for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ |
595 | markobjectN(g, f->locvars[i].varname); | 647 | markobjectN(g, f->locvars[i].varname); |
648 | return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; | ||
596 | } | 649 | } |
597 | 650 | ||
598 | 651 | ||
599 | static void traverseCclosure (global_State *g, CClosure *cl) { | 652 | static l_mem traverseCclosure (global_State *g, CClosure *cl) { |
600 | int i; | 653 | int i; |
601 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ | 654 | for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ |
602 | markvalue(g, &cl->upvalue[i]); | 655 | markvalue(g, &cl->upvalue[i]); |
656 | return 1 + cl->nupvalues; | ||
603 | } | 657 | } |
604 | 658 | ||
605 | /* | 659 | /* |
606 | ** Traverse a Lua closure, marking its prototype and its upvalues. | 660 | ** Traverse a Lua closure, marking its prototype and its upvalues. |
607 | ** (Both can be NULL while closure is being created.) | 661 | ** (Both can be NULL while closure is being created.) |
608 | */ | 662 | */ |
609 | static void traverseLclosure (global_State *g, LClosure *cl) { | 663 | static l_mem traverseLclosure (global_State *g, LClosure *cl) { |
610 | int i; | 664 | int i; |
611 | markobjectN(g, cl->p); /* mark its prototype */ | 665 | markobjectN(g, cl->p); /* mark its prototype */ |
612 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ | 666 | for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ |
613 | UpVal *uv = cl->upvals[i]; | 667 | UpVal *uv = cl->upvals[i]; |
614 | markobjectN(g, uv); /* mark upvalue */ | 668 | markobjectN(g, uv); /* mark upvalue */ |
615 | } | 669 | } |
670 | return 1 + cl->nupvalues; | ||
616 | } | 671 | } |
617 | 672 | ||
618 | 673 | ||
@@ -628,13 +683,13 @@ static void traverseLclosure (global_State *g, LClosure *cl) { | |||
628 | ** (which can only happen in generational mode) or if the traverse is in | 683 | ** (which can only happen in generational mode) or if the traverse is in |
629 | ** the propagate phase (which can only happen in incremental mode). | 684 | ** the propagate phase (which can only happen in incremental mode). |
630 | */ | 685 | */ |
631 | static void traversethread (global_State *g, lua_State *th) { | 686 | static l_mem traversethread (global_State *g, lua_State *th) { |
632 | UpVal *uv; | 687 | UpVal *uv; |
633 | StkId o = th->stack.p; | 688 | StkId o = th->stack.p; |
634 | if (isold(th) || g->gcstate == GCSpropagate) | 689 | if (isold(th) || g->gcstate == GCSpropagate) |
635 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | 690 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ |
636 | if (o == NULL) | 691 | if (o == NULL) |
637 | return; /* stack not completely built yet */ | 692 | return 0; /* stack not completely built yet */ |
638 | lua_assert(g->gcstate == GCSatomic || | 693 | lua_assert(g->gcstate == GCSatomic || |
639 | th->openupval == NULL || isintwups(th)); | 694 | th->openupval == NULL || isintwups(th)); |
640 | for (; o < th->top.p; o++) /* mark live elements in the stack */ | 695 | for (; o < th->top.p; o++) /* mark live elements in the stack */ |
@@ -652,35 +707,33 @@ static void traversethread (global_State *g, lua_State *th) { | |||
652 | g->twups = th; | 707 | g->twups = th; |
653 | } | 708 | } |
654 | } | 709 | } |
710 | return 1 + (th->top.p - th->stack.p); | ||
655 | } | 711 | } |
656 | 712 | ||
657 | 713 | ||
658 | /* | 714 | /* |
659 | ** traverse one gray object, turning it to black. | 715 | ** traverse one gray object, turning it to black. Return an estimate |
716 | ** of the number of slots traversed. | ||
660 | */ | 717 | */ |
661 | static void propagatemark (global_State *g) { | 718 | static l_mem propagatemark (global_State *g) { |
662 | GCObject *o = g->gray; | 719 | GCObject *o = g->gray; |
663 | nw2black(o); | 720 | nw2black(o); |
664 | g->gray = *getgclist(o); /* remove from 'gray' list */ | 721 | g->gray = *getgclist(o); /* remove from 'gray' list */ |
665 | switch (o->tt) { | 722 | switch (o->tt) { |
666 | case LUA_VTABLE: traversetable(g, gco2t(o)); break; | 723 | case LUA_VTABLE: return traversetable(g, gco2t(o)); |
667 | case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break; | 724 | case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); |
668 | case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break; | 725 | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); |
669 | case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break; | 726 | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); |
670 | case LUA_VPROTO: traverseproto(g, gco2p(o)); break; | 727 | case LUA_VPROTO: return traverseproto(g, gco2p(o)); |
671 | case LUA_VTHREAD: traversethread(g, gco2th(o)); break; | 728 | case LUA_VTHREAD: return traversethread(g, gco2th(o)); |
672 | default: lua_assert(0); | 729 | default: lua_assert(0); return 0; |
673 | } | 730 | } |
674 | } | 731 | } |
675 | 732 | ||
676 | 733 | ||
677 | static l_obj propagateall (global_State *g) { | 734 | static void propagateall (global_State *g) { |
678 | l_obj work = 0; | 735 | while (g->gray) |
679 | while (g->gray) { | ||
680 | propagatemark(g); | 736 | propagatemark(g); |
681 | work++; | ||
682 | } | ||
683 | return work; | ||
684 | } | 737 | } |
685 | 738 | ||
686 | 739 | ||
@@ -690,9 +743,8 @@ static l_obj propagateall (global_State *g) { | |||
690 | ** inverts the direction of the traversals, trying to speed up | 743 | ** inverts the direction of the traversals, trying to speed up |
691 | ** convergence on chains in the same table. | 744 | ** convergence on chains in the same table. |
692 | */ | 745 | */ |
693 | static l_obj convergeephemerons (global_State *g) { | 746 | static void convergeephemerons (global_State *g) { |
694 | int changed; | 747 | int changed; |
695 | l_obj work = 0; | ||
696 | int dir = 0; | 748 | int dir = 0; |
697 | do { | 749 | do { |
698 | GCObject *w; | 750 | GCObject *w; |
@@ -707,11 +759,9 @@ static l_obj convergeephemerons (global_State *g) { | |||
707 | propagateall(g); /* propagate changes */ | 759 | propagateall(g); /* propagate changes */ |
708 | changed = 1; /* will have to revisit all ephemeron tables */ | 760 | changed = 1; /* will have to revisit all ephemeron tables */ |
709 | } | 761 | } |
710 | work++; | ||
711 | } | 762 | } |
712 | dir = !dir; /* invert direction next time */ | 763 | dir = !dir; /* invert direction next time */ |
713 | } while (changed); /* repeat until no more changes */ | 764 | } while (changed); /* repeat until no more changes */ |
714 | return work; | ||
715 | } | 765 | } |
716 | 766 | ||
717 | /* }====================================================== */ | 767 | /* }====================================================== */ |
@@ -727,8 +777,7 @@ static l_obj convergeephemerons (global_State *g) { | |||
727 | /* | 777 | /* |
728 | ** clear entries with unmarked keys from all weaktables in list 'l' | 778 | ** clear entries with unmarked keys from all weaktables in list 'l' |
729 | */ | 779 | */ |
730 | static l_obj clearbykeys (global_State *g, GCObject *l) { | 780 | static void clearbykeys (global_State *g, GCObject *l) { |
731 | l_obj work = 0; | ||
732 | for (; l; l = gco2t(l)->gclist) { | 781 | for (; l; l = gco2t(l)->gclist) { |
733 | Table *h = gco2t(l); | 782 | Table *h = gco2t(l); |
734 | Node *limit = gnodelast(h); | 783 | Node *limit = gnodelast(h); |
@@ -739,9 +788,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) { | |||
739 | if (isempty(gval(n))) /* is entry empty? */ | 788 | if (isempty(gval(n))) /* is entry empty? */ |
740 | clearkey(n); /* clear its key */ | 789 | clearkey(n); /* clear its key */ |
741 | } | 790 | } |
742 | work++; | ||
743 | } | 791 | } |
744 | return work; | ||
745 | } | 792 | } |
746 | 793 | ||
747 | 794 | ||
@@ -749,8 +796,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) { | |||
749 | ** clear entries with unmarked values from all weaktables in list 'l' up | 796 | ** clear entries with unmarked values from all weaktables in list 'l' up |
750 | ** to element 'f' | 797 | ** to element 'f' |
751 | */ | 798 | */ |
752 | static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | 799 | static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { |
753 | l_obj work = 0; | ||
754 | for (; l != f; l = gco2t(l)->gclist) { | 800 | for (; l != f; l = gco2t(l)->gclist) { |
755 | Table *h = gco2t(l); | 801 | Table *h = gco2t(l); |
756 | Node *n, *limit = gnodelast(h); | 802 | Node *n, *limit = gnodelast(h); |
@@ -767,9 +813,7 @@ static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { | |||
767 | if (isempty(gval(n))) /* is entry empty? */ | 813 | if (isempty(gval(n))) /* is entry empty? */ |
768 | clearkey(n); /* clear its key */ | 814 | clearkey(n); /* clear its key */ |
769 | } | 815 | } |
770 | work++; | ||
771 | } | 816 | } |
772 | return work; | ||
773 | } | 817 | } |
774 | 818 | ||
775 | 819 | ||
@@ -781,7 +825,6 @@ static void freeupval (lua_State *L, UpVal *uv) { | |||
781 | 825 | ||
782 | 826 | ||
783 | static void freeobj (lua_State *L, GCObject *o) { | 827 | static void freeobj (lua_State *L, GCObject *o) { |
784 | G(L)->GCtotalobjs--; | ||
785 | switch (o->tt) { | 828 | switch (o->tt) { |
786 | case LUA_VPROTO: | 829 | case LUA_VPROTO: |
787 | luaF_freeproto(L, gco2p(o)); | 830 | luaF_freeproto(L, gco2p(o)); |
@@ -835,12 +878,11 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
835 | ** for next collection cycle. Return where to continue the traversal or | 878 | ** for next collection cycle. Return where to continue the traversal or |
836 | ** NULL if list is finished. | 879 | ** NULL if list is finished. |
837 | */ | 880 | */ |
838 | static GCObject **sweeplist (lua_State *L, GCObject **p, l_obj countin) { | 881 | static GCObject **sweeplist (lua_State *L, GCObject **p, l_mem countin) { |
839 | global_State *g = G(L); | 882 | global_State *g = G(L); |
840 | int ow = otherwhite(g); | 883 | int ow = otherwhite(g); |
841 | l_obj i; | ||
842 | int white = luaC_white(g); /* current white */ | 884 | int white = luaC_white(g); /* current white */ |
843 | for (i = 0; *p != NULL && i < countin; i++) { | 885 | while (*p != NULL && countin-- > 0) { |
844 | GCObject *curr = *p; | 886 | GCObject *curr = *p; |
845 | int marked = curr->marked; | 887 | int marked = curr->marked; |
846 | if (isdeadm(ow, marked)) { /* is 'curr' dead? */ | 888 | if (isdeadm(ow, marked)) { /* is 'curr' dead? */ |
@@ -1052,8 +1094,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
1052 | ** approximately (marked * pause / 100). | 1094 | ** approximately (marked * pause / 100). |
1053 | */ | 1095 | */ |
1054 | static void setpause (global_State *g) { | 1096 | static void setpause (global_State *g) { |
1055 | l_obj threshold = applygcparam(g, PAUSE, g->GCmarked); | 1097 | l_mem threshold = applygcparam(g, PAUSE, g->GCmarked); |
1056 | l_obj debt = threshold - gettotalobjs(g); | 1098 | l_mem debt = threshold - gettotalbytes(g); |
1057 | if (debt < 0) debt = 0; | 1099 | if (debt < 0) debt = 0; |
1058 | luaE_setdebt(g, debt); | 1100 | luaE_setdebt(g, debt); |
1059 | } | 1101 | } |
@@ -1103,7 +1145,7 @@ static void sweep2old (lua_State *L, GCObject **p) { | |||
1103 | */ | 1145 | */ |
1104 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | 1146 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, |
1105 | GCObject *limit, GCObject **pfirstold1, | 1147 | GCObject *limit, GCObject **pfirstold1, |
1106 | l_obj *paddedold) { | 1148 | l_mem *paddedold) { |
1107 | static const lu_byte nextage[] = { | 1149 | static const lu_byte nextage[] = { |
1108 | G_SURVIVAL, /* from G_NEW */ | 1150 | G_SURVIVAL, /* from G_NEW */ |
1109 | G_OLD1, /* from G_SURVIVAL */ | 1151 | G_OLD1, /* from G_SURVIVAL */ |
@@ -1113,7 +1155,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1113 | G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ | 1155 | G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ |
1114 | G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ | 1156 | G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ |
1115 | }; | 1157 | }; |
1116 | l_obj addedold = 0; | 1158 | l_mem addedold = 0; |
1117 | int white = luaC_white(g); | 1159 | int white = luaC_white(g); |
1118 | GCObject *curr; | 1160 | GCObject *curr; |
1119 | while ((curr = *p) != limit) { | 1161 | while ((curr = *p) != limit) { |
@@ -1132,7 +1174,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1132 | lua_assert(age != G_OLD1); /* advanced in 'markold' */ | 1174 | lua_assert(age != G_OLD1); /* advanced in 'markold' */ |
1133 | setage(curr, nextage[age]); | 1175 | setage(curr, nextage[age]); |
1134 | if (getage(curr) == G_OLD1) { | 1176 | if (getage(curr) == G_OLD1) { |
1135 | addedold++; /* one more object becoming old */ | 1177 | addedold += cast(l_mem, objsize(curr)); /* bytes becoming old */ |
1136 | if (*pfirstold1 == NULL) | 1178 | if (*pfirstold1 == NULL) |
1137 | *pfirstold1 = curr; /* first OLD1 object in the list */ | 1179 | *pfirstold1 = curr; /* first OLD1 object in the list */ |
1138 | } | 1180 | } |
@@ -1257,9 +1299,9 @@ static void minor2inc (lua_State *L, global_State *g, lu_byte kind) { | |||
1257 | ** than 'minormajor'% of the number of lived objects after the last | 1299 | ** than 'minormajor'% of the number of lived objects after the last |
1258 | ** major collection. (That percentage is computed in 'limit'.) | 1300 | ** major collection. (That percentage is computed in 'limit'.) |
1259 | */ | 1301 | */ |
1260 | static int checkminormajor (global_State *g, l_obj addedold1) { | 1302 | static int checkminormajor (global_State *g, l_mem addedold1) { |
1261 | l_obj step = applygcparam(g, MINORMUL, g->GCmajorminor); | 1303 | l_mem step = applygcparam(g, MINORMUL, g->GCmajorminor); |
1262 | l_obj limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); | 1304 | l_mem limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); |
1263 | return (addedold1 >= (step >> 1) || g->GCmarked >= limit); | 1305 | return (addedold1 >= (step >> 1) || g->GCmarked >= limit); |
1264 | } | 1306 | } |
1265 | 1307 | ||
@@ -1269,8 +1311,8 @@ static int checkminormajor (global_State *g, l_obj addedold1) { | |||
1269 | ** sweep all lists and advance pointers. Finally, finish the collection. | 1311 | ** sweep all lists and advance pointers. Finally, finish the collection. |
1270 | */ | 1312 | */ |
1271 | static void youngcollection (lua_State *L, global_State *g) { | 1313 | static void youngcollection (lua_State *L, global_State *g) { |
1272 | l_obj addedold1 = 0; | 1314 | l_mem addedold1 = 0; |
1273 | l_obj marked = g->GCmarked; /* preserve 'g->GCmarked' */ | 1315 | l_mem marked = g->GCmarked; /* preserve 'g->GCmarked' */ |
1274 | GCObject **psurvival; /* to point to first non-dead survival object */ | 1316 | GCObject **psurvival; /* to point to first non-dead survival object */ |
1275 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ | 1317 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ |
1276 | lua_assert(g->gcstate == GCSpropagate); | 1318 | lua_assert(g->gcstate == GCSpropagate); |
@@ -1346,7 +1388,9 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
1346 | 1388 | ||
1347 | /* | 1389 | /* |
1348 | ** Set debt for the next minor collection, which will happen when | 1390 | ** Set debt for the next minor collection, which will happen when |
1349 | ** total number of objects grows 'genminormul'%. | 1391 | ** total number of bytes grows 'genminormul'% in relation to |
1392 | ** the base, GCmajorminor, which is the number of bytes being used | ||
1393 | ** after the last major collection. | ||
1350 | */ | 1394 | */ |
1351 | static void setminordebt (global_State *g) { | 1395 | static void setminordebt (global_State *g) { |
1352 | luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); | 1396 | luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); |
@@ -1404,18 +1448,18 @@ static void fullgen (lua_State *L, global_State *g) { | |||
1404 | */ | 1448 | */ |
1405 | static int checkmajorminor (lua_State *L, global_State *g) { | 1449 | static int checkmajorminor (lua_State *L, global_State *g) { |
1406 | if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ | 1450 | if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ |
1407 | l_obj numobjs = gettotalobjs(g); | 1451 | l_mem numbytes = gettotalbytes(g); |
1408 | l_obj addedobjs = numobjs - g->GCmajorminor; | 1452 | l_mem addedobjs = numbytes - g->GCmajorminor; |
1409 | l_obj limit = applygcparam(g, MAJORMINOR, addedobjs); | 1453 | l_mem limit = applygcparam(g, MAJORMINOR, addedobjs); |
1410 | l_obj tobecollected = numobjs - g->GCmarked; | 1454 | l_mem tobecollected = numbytes - g->GCmarked; |
1411 | if (tobecollected > limit) { | 1455 | if (tobecollected > limit) { |
1412 | atomic2gen(L, g); /* return to generational mode */ | 1456 | atomic2gen(L, g); /* return to generational mode */ |
1413 | setminordebt(g); | 1457 | setminordebt(g); |
1414 | return 0; /* exit incremental collection */ | 1458 | return 1; /* exit incremental collection */ |
1415 | } | 1459 | } |
1416 | } | 1460 | } |
1417 | g->GCmajorminor = g->GCmarked; /* prepare for next collection */ | 1461 | g->GCmajorminor = g->GCmarked; /* prepare for next collection */ |
1418 | return 1; /* stay doing incremental collections */ | 1462 | return 0; /* stay doing incremental collections */ |
1419 | } | 1463 | } |
1420 | 1464 | ||
1421 | /* }====================================================== */ | 1465 | /* }====================================================== */ |
@@ -1474,8 +1518,7 @@ void luaC_freeallobjects (lua_State *L) { | |||
1474 | } | 1518 | } |
1475 | 1519 | ||
1476 | 1520 | ||
1477 | static l_obj atomic (lua_State *L) { | 1521 | static void atomic (lua_State *L) { |
1478 | l_obj work = 0; | ||
1479 | global_State *g = G(L); | 1522 | global_State *g = G(L); |
1480 | GCObject *origweak, *origall; | 1523 | GCObject *origweak, *origall; |
1481 | GCObject *grayagain = g->grayagain; /* save original list */ | 1524 | GCObject *grayagain = g->grayagain; /* save original list */ |
@@ -1487,33 +1530,32 @@ static l_obj atomic (lua_State *L) { | |||
1487 | /* registry and global metatables may be changed by API */ | 1530 | /* registry and global metatables may be changed by API */ |
1488 | markvalue(g, &g->l_registry); | 1531 | markvalue(g, &g->l_registry); |
1489 | markmt(g); /* mark global metatables */ | 1532 | markmt(g); /* mark global metatables */ |
1490 | work += propagateall(g); /* empties 'gray' list */ | 1533 | propagateall(g); /* empties 'gray' list */ |
1491 | /* remark occasional upvalues of (maybe) dead threads */ | 1534 | /* remark occasional upvalues of (maybe) dead threads */ |
1492 | work += remarkupvals(g); | 1535 | remarkupvals(g); |
1493 | work += propagateall(g); /* propagate changes */ | 1536 | propagateall(g); /* propagate changes */ |
1494 | g->gray = grayagain; | 1537 | g->gray = grayagain; |
1495 | work += propagateall(g); /* traverse 'grayagain' list */ | 1538 | propagateall(g); /* traverse 'grayagain' list */ |
1496 | work += convergeephemerons(g); | 1539 | convergeephemerons(g); |
1497 | /* at this point, all strongly accessible objects are marked. */ | 1540 | /* at this point, all strongly accessible objects are marked. */ |
1498 | /* Clear values from weak tables, before checking finalizers */ | 1541 | /* Clear values from weak tables, before checking finalizers */ |
1499 | work += clearbyvalues(g, g->weak, NULL); | 1542 | clearbyvalues(g, g->weak, NULL); |
1500 | work += clearbyvalues(g, g->allweak, NULL); | 1543 | clearbyvalues(g, g->allweak, NULL); |
1501 | origweak = g->weak; origall = g->allweak; | 1544 | origweak = g->weak; origall = g->allweak; |
1502 | separatetobefnz(g, 0); /* separate objects to be finalized */ | 1545 | separatetobefnz(g, 0); /* separate objects to be finalized */ |
1503 | work += markbeingfnz(g); /* mark objects that will be finalized */ | 1546 | markbeingfnz(g); /* mark objects that will be finalized */ |
1504 | work += propagateall(g); /* remark, to propagate 'resurrection' */ | 1547 | propagateall(g); /* remark, to propagate 'resurrection' */ |
1505 | work += convergeephemerons(g); | 1548 | convergeephemerons(g); |
1506 | /* at this point, all resurrected objects are marked. */ | 1549 | /* at this point, all resurrected objects are marked. */ |
1507 | /* remove dead objects from weak tables */ | 1550 | /* remove dead objects from weak tables */ |
1508 | work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ | 1551 | clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ |
1509 | work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ | 1552 | clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ |
1510 | /* clear values from resurrected weak tables */ | 1553 | /* clear values from resurrected weak tables */ |
1511 | work += clearbyvalues(g, g->weak, origweak); | 1554 | clearbyvalues(g, g->weak, origweak); |
1512 | work += clearbyvalues(g, g->allweak, origall); | 1555 | clearbyvalues(g, g->allweak, origall); |
1513 | luaS_clearcache(g); | 1556 | luaS_clearcache(g); |
1514 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1557 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
1515 | lua_assert(g->gray == NULL); | 1558 | lua_assert(g->gray == NULL); |
1516 | return work; | ||
1517 | } | 1559 | } |
1518 | 1560 | ||
1519 | 1561 | ||
@@ -1524,7 +1566,7 @@ static l_obj atomic (lua_State *L) { | |||
1524 | static void sweepstep (lua_State *L, global_State *g, | 1566 | static void sweepstep (lua_State *L, global_State *g, |
1525 | lu_byte nextstate, GCObject **nextlist, int fast) { | 1567 | lu_byte nextstate, GCObject **nextlist, int fast) { |
1526 | if (g->sweepgc) | 1568 | if (g->sweepgc) |
1527 | g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LOBJ : GCSWEEPMAX); | 1569 | g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LMEM : GCSWEEPMAX); |
1528 | else { /* enter next state */ | 1570 | else { /* enter next state */ |
1529 | g->gcstate = nextstate; | 1571 | g->gcstate = nextstate; |
1530 | g->sweepgc = nextlist; | 1572 | g->sweepgc = nextlist; |
@@ -1544,72 +1586,80 @@ static void sweepstep (lua_State *L, global_State *g, | |||
1544 | ** That avoids traversing twice some objects, such as threads and | 1586 | ** That avoids traversing twice some objects, such as threads and |
1545 | ** weak tables. | 1587 | ** weak tables. |
1546 | */ | 1588 | */ |
1547 | static l_obj singlestep (lua_State *L, int fast) { | 1589 | |
1590 | #define step2pause -3 /* finished collection; entered pause state */ | ||
1591 | #define atomicstep -2 /* atomic step */ | ||
1592 | #define step2minor -1 /* moved to minor collections */ | ||
1593 | |||
1594 | |||
1595 | static l_mem singlestep (lua_State *L, int fast) { | ||
1548 | global_State *g = G(L); | 1596 | global_State *g = G(L); |
1549 | l_obj work; | 1597 | l_mem stepresult; |
1550 | lua_assert(!g->gcstopem); /* collector is not reentrant */ | 1598 | lua_assert(!g->gcstopem); /* collector is not reentrant */ |
1551 | g->gcstopem = 1; /* no emergency collections while collecting */ | 1599 | g->gcstopem = 1; /* no emergency collections while collecting */ |
1552 | switch (g->gcstate) { | 1600 | switch (g->gcstate) { |
1553 | case GCSpause: { | 1601 | case GCSpause: { |
1554 | restartcollection(g); | 1602 | restartcollection(g); |
1555 | g->gcstate = GCSpropagate; | 1603 | g->gcstate = GCSpropagate; |
1556 | work = 1; | 1604 | stepresult = 1; |
1557 | break; | 1605 | break; |
1558 | } | 1606 | } |
1559 | case GCSpropagate: { | 1607 | case GCSpropagate: { |
1560 | if (fast || g->gray == NULL) { | 1608 | if (fast || g->gray == NULL) { |
1561 | g->gcstate = GCSenteratomic; /* finish propagate phase */ | 1609 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1562 | work = 0; | 1610 | stepresult = 1; |
1563 | } | ||
1564 | else { | ||
1565 | propagatemark(g); /* traverse one gray object */ | ||
1566 | work = 1; | ||
1567 | } | 1611 | } |
1612 | else | ||
1613 | stepresult = propagatemark(g); /* traverse one gray object */ | ||
1568 | break; | 1614 | break; |
1569 | } | 1615 | } |
1570 | case GCSenteratomic: { | 1616 | case GCSenteratomic: { |
1571 | work = atomic(L); | 1617 | atomic(L); |
1572 | if (checkmajorminor(L, g)) | 1618 | if (checkmajorminor(L, g)) |
1619 | stepresult = step2minor; | ||
1620 | else { | ||
1573 | entersweep(L); | 1621 | entersweep(L); |
1622 | stepresult = atomicstep; | ||
1623 | } | ||
1574 | break; | 1624 | break; |
1575 | } | 1625 | } |
1576 | case GCSswpallgc: { /* sweep "regular" objects */ | 1626 | case GCSswpallgc: { /* sweep "regular" objects */ |
1577 | sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); | 1627 | sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); |
1578 | work = GCSWEEPMAX; | 1628 | stepresult = GCSWEEPMAX; |
1579 | break; | 1629 | break; |
1580 | } | 1630 | } |
1581 | case GCSswpfinobj: { /* sweep objects with finalizers */ | 1631 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1582 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); | 1632 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); |
1583 | work = GCSWEEPMAX; | 1633 | stepresult = GCSWEEPMAX; |
1584 | break; | 1634 | break; |
1585 | } | 1635 | } |
1586 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1636 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1587 | sweepstep(L, g, GCSswpend, NULL, fast); | 1637 | sweepstep(L, g, GCSswpend, NULL, fast); |
1588 | work = GCSWEEPMAX; | 1638 | stepresult = GCSWEEPMAX; |
1589 | break; | 1639 | break; |
1590 | } | 1640 | } |
1591 | case GCSswpend: { /* finish sweeps */ | 1641 | case GCSswpend: { /* finish sweeps */ |
1592 | checkSizes(L, g); | 1642 | checkSizes(L, g); |
1593 | g->gcstate = GCScallfin; | 1643 | g->gcstate = GCScallfin; |
1594 | work = 0; | 1644 | stepresult = GCSWEEPMAX; |
1595 | break; | 1645 | break; |
1596 | } | 1646 | } |
1597 | case GCScallfin: { /* call finalizers */ | 1647 | case GCScallfin: { /* call finalizers */ |
1598 | if (g->tobefnz && !g->gcemergency) { | 1648 | if (g->tobefnz && !g->gcemergency) { |
1599 | g->gcstopem = 0; /* ok collections during finalizers */ | 1649 | g->gcstopem = 0; /* ok collections during finalizers */ |
1600 | GCTM(L); /* call one finalizer */ | 1650 | GCTM(L); /* call one finalizer */ |
1601 | work = 1; | 1651 | stepresult = CWUFIN; |
1602 | } | 1652 | } |
1603 | else { /* emergency mode or no more finalizers */ | 1653 | else { /* emergency mode or no more finalizers */ |
1604 | g->gcstate = GCSpause; /* finish collection */ | 1654 | g->gcstate = GCSpause; /* finish collection */ |
1605 | work = 0; | 1655 | stepresult = step2pause; |
1606 | } | 1656 | } |
1607 | break; | 1657 | break; |
1608 | } | 1658 | } |
1609 | default: lua_assert(0); return 0; | 1659 | default: lua_assert(0); return 0; |
1610 | } | 1660 | } |
1611 | g->gcstopem = 0; | 1661 | g->gcstopem = 0; |
1612 | return work; | 1662 | return stepresult; |
1613 | } | 1663 | } |
1614 | 1664 | ||
1615 | 1665 | ||
@@ -1635,25 +1685,26 @@ void luaC_runtilstate (lua_State *L, int state, int fast) { | |||
1635 | ** controls when next step will be performed. | 1685 | ** controls when next step will be performed. |
1636 | */ | 1686 | */ |
1637 | static void incstep (lua_State *L, global_State *g) { | 1687 | static void incstep (lua_State *L, global_State *g) { |
1638 | l_obj stepsize = applygcparam(g, STEPSIZE, 100); | 1688 | l_mem stepsize = applygcparam(g, STEPSIZE, 100); |
1639 | l_obj work2do = applygcparam(g, STEPMUL, stepsize); | 1689 | l_mem work2do = applygcparam(g, STEPMUL, stepsize); |
1640 | int fast = 0; | 1690 | l_mem stres; |
1641 | if (work2do == 0) { /* special case: do a full collection */ | 1691 | int fast = (work2do == 0); /* special case: do a full collection */ |
1642 | work2do = MAX_LOBJ; /* do unlimited work */ | 1692 | do { /* repeat until enough work */ |
1643 | fast = 1; | 1693 | stres = singlestep(L, fast); /* perform one single step */ |
1644 | } | 1694 | if (stres == step2minor) /* returned to minor collections? */ |
1645 | do { /* repeat until pause or enough work */ | ||
1646 | l_obj work = singlestep(L, fast); /* perform one single step */ | ||
1647 | if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */ | ||
1648 | return; /* nothing else to be done here */ | 1695 | return; /* nothing else to be done here */ |
1649 | work2do -= work; | 1696 | else if (stres == step2pause || (stres == atomicstep && !fast)) |
1650 | } while (work2do > 0 && g->gcstate != GCSpause); | 1697 | break; /* end of cycle or atomic */ |
1698 | else | ||
1699 | work2do -= stres; | ||
1700 | } while (fast || work2do > 0); | ||
1651 | if (g->gcstate == GCSpause) | 1701 | if (g->gcstate == GCSpause) |
1652 | setpause(g); /* pause until next cycle */ | 1702 | setpause(g); /* pause until next cycle */ |
1653 | else | 1703 | else |
1654 | luaE_setdebt(g, stepsize); | 1704 | luaE_setdebt(g, stepsize); |
1655 | } | 1705 | } |
1656 | 1706 | ||
1707 | |||
1657 | /* | 1708 | /* |
1658 | ** Performs a basic GC step if collector is running. (If collector is | 1709 | ** Performs a basic GC step if collector is running. (If collector is |
1659 | ** not running, set a reasonable debt to avoid it being called at | 1710 | ** not running, set a reasonable debt to avoid it being called at |
@@ -1663,17 +1714,23 @@ void luaC_step (lua_State *L) { | |||
1663 | global_State *g = G(L); | 1714 | global_State *g = G(L); |
1664 | lua_assert(!g->gcemergency); | 1715 | lua_assert(!g->gcemergency); |
1665 | if (!gcrunning(g)) /* not running? */ | 1716 | if (!gcrunning(g)) /* not running? */ |
1666 | luaE_setdebt(g, 2000); | 1717 | luaE_setdebt(g, 20000); |
1667 | else { | 1718 | else { |
1719 | // printf("mem: %ld kind: %s ", gettotalbytes(g), | ||
1720 | // g->gckind == KGC_INC ? "inc" : g->gckind == KGC_GENMAJOR ? "genmajor" : | ||
1721 | // "genminor"); | ||
1668 | switch (g->gckind) { | 1722 | switch (g->gckind) { |
1669 | case KGC_INC: case KGC_GENMAJOR: | 1723 | case KGC_INC: case KGC_GENMAJOR: |
1724 | // printf("(%d -> ", g->gcstate); | ||
1670 | incstep(L, g); | 1725 | incstep(L, g); |
1726 | // printf("%d) ", g->gcstate); | ||
1671 | break; | 1727 | break; |
1672 | case KGC_GENMINOR: | 1728 | case KGC_GENMINOR: |
1673 | youngcollection(L, g); | 1729 | youngcollection(L, g); |
1674 | setminordebt(g); | 1730 | setminordebt(g); |
1675 | break; | 1731 | break; |
1676 | } | 1732 | } |
1733 | // printf("-> mem: %ld debt: %ld\n", gettotalbytes(g), g->GCdebt); | ||
1677 | } | 1734 | } |
1678 | } | 1735 | } |
1679 | 1736 | ||
@@ -1692,7 +1749,7 @@ static void fullinc (lua_State *L, global_State *g) { | |||
1692 | luaC_runtilstate(L, GCSpause, 1); | 1749 | luaC_runtilstate(L, GCSpause, 1); |
1693 | luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ | 1750 | luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ |
1694 | /* 'marked' must be correct after a full GC cycle */ | 1751 | /* 'marked' must be correct after a full GC cycle */ |
1695 | lua_assert(g->GCmarked == gettotalobjs(g)); | 1752 | /* lua_assert(g->GCmarked == gettotalobjs(g)); ??? */ |
1696 | luaC_runtilstate(L, GCSpause, 1); /* finish collection */ | 1753 | luaC_runtilstate(L, GCSpause, 1); /* finish collection */ |
1697 | setpause(g); | 1754 | setpause(g); |
1698 | } | 1755 | } |
@@ -23,8 +23,9 @@ | |||
23 | ** never point to a white one. Moreover, any gray object must be in a | 23 | ** never point to a white one. Moreover, any gray object must be in a |
24 | ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it | 24 | ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it |
25 | ** can be visited again before finishing the collection cycle. (Open | 25 | ** can be visited again before finishing the collection cycle. (Open |
26 | ** upvalues are an exception to this rule.) These lists have no meaning | 26 | ** upvalues are an exception to this rule, as they are attached to |
27 | ** when the invariant is not being enforced (e.g., sweep phase). | 27 | ** a corresponding thread.) These lists have no meaning when the |
28 | ** invariant is not being enforced (e.g., sweep phase). | ||
28 | */ | 29 | */ |
29 | 30 | ||
30 | 31 | ||
@@ -48,10 +49,10 @@ | |||
48 | 49 | ||
49 | /* | 50 | /* |
50 | ** macro to tell when main invariant (white objects cannot point to black | 51 | ** macro to tell when main invariant (white objects cannot point to black |
51 | ** ones) must be kept. During a collection, the sweep | 52 | ** ones) must be kept. During a collection, the sweep phase may break |
52 | ** phase may break the invariant, as objects turned white may point to | 53 | ** the invariant, as objects turned white may point to still-black |
53 | ** still-black objects. The invariant is restored when sweep ends and | 54 | ** objects. The invariant is restored when sweep ends and all objects |
54 | ** all objects are white again. | 55 | ** are white again. |
55 | */ | 56 | */ |
56 | 57 | ||
57 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) | 58 | #define keepinvariant(g) ((g)->gcstate <= GCSatomic) |
@@ -163,34 +164,37 @@ | |||
163 | 164 | ||
164 | /* | 165 | /* |
165 | ** Minor collections will shift to major ones after LUAI_MINORMAJOR% | 166 | ** Minor collections will shift to major ones after LUAI_MINORMAJOR% |
166 | ** objects become old. | 167 | ** bytes become old. |
167 | */ | 168 | */ |
168 | #define LUAI_MINORMAJOR 100 | 169 | #define LUAI_MINORMAJOR 100 |
169 | 170 | ||
170 | /* | 171 | /* |
171 | ** Major collections will shift to minor ones after a collection | 172 | ** Major collections will shift to minor ones after a collection |
172 | ** collects at least LUAI_MAJORMINOR% of the new objects. | 173 | ** collects at least LUAI_MAJORMINOR% of the new bytes. |
173 | */ | 174 | */ |
174 | #define LUAI_MAJORMINOR 50 | 175 | #define LUAI_MAJORMINOR 50 |
175 | 176 | ||
176 | /* | 177 | /* |
177 | ** A young (minor) collection will run after creating LUAI_GENMINORMUL% | 178 | ** A young (minor) collection will run after creating LUAI_GENMINORMUL% |
178 | ** new objects. | 179 | ** new bytes. |
179 | */ | 180 | */ |
180 | #define LUAI_GENMINORMUL 25 | 181 | #define LUAI_GENMINORMUL 25 |
181 | 182 | ||
182 | 183 | ||
183 | /* incremental */ | 184 | /* incremental */ |
184 | 185 | ||
185 | /* Number of objects must be LUAI_GCPAUSE% before starting new cycle */ | 186 | /* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */ |
186 | #define LUAI_GCPAUSE 200 | 187 | #define LUAI_GCPAUSE 200 |
187 | 188 | ||
188 | /* Step multiplier. (Roughly, the collector handles LUAI_GCMUL% objects | 189 | /* |
189 | for each new allocated object.) */ | 190 | ** Step multiplier: The collector handles LUAI_GCMUL% work units for |
190 | #define LUAI_GCMUL 200 | 191 | ** each new allocated byte. (Each "work unit" corresponds roughly to |
192 | ** sweeping or marking one object.) | ||
193 | */ | ||
194 | #define LUAI_GCMUL 20 /* ??? */ | ||
191 | 195 | ||
192 | /* How many objects to allocate before next GC step */ | 196 | /* How many bytes to allocate before next GC step */ |
193 | #define LUAI_GCSTEPSIZE 250 | 197 | #define LUAI_GCSTEPSIZE (250 * sizeof(void*)) |
194 | 198 | ||
195 | 199 | ||
196 | #define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) | 200 | #define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) |
@@ -16,25 +16,24 @@ | |||
16 | 16 | ||
17 | 17 | ||
18 | /* | 18 | /* |
19 | ** 'lu_mem' is an unsigned integer big enough to count the total memory | 19 | ** 'l_mem' is a signed integer big enough to count the total memory |
20 | ** used by Lua (in bytes). 'l_obj' is a signed integer big enough to | 20 | ** used by Lua. (It is signed due to the use of debt in several |
21 | ** count the total number of objects used by Lua. (It is signed due | 21 | ** computations.) Usually, 'ptrdiff_t' should work, but we use 'long' |
22 | ** to the use of debt in several computations.) Usually, 'size_t' and | 22 | ** for 16-bit machines. |
23 | ** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. | ||
24 | */ | 23 | */ |
25 | #if defined(LUAI_MEM) /* { external definitions? */ | 24 | #if defined(LUAI_MEM) /* { external definitions? */ |
25 | typedef LUAI_MEM l_mem; | ||
26 | typedef LUAI_UMEM lu_mem; | 26 | typedef LUAI_UMEM lu_mem; |
27 | typedef LUAI_MEM l_obj; | ||
28 | #elif LUAI_IS32INT /* }{ */ | 27 | #elif LUAI_IS32INT /* }{ */ |
28 | typedef ptrdiff_t l_mem; | ||
29 | typedef size_t lu_mem; | 29 | typedef size_t lu_mem; |
30 | typedef ptrdiff_t l_obj; | ||
31 | #else /* 16-bit ints */ /* }{ */ | 30 | #else /* 16-bit ints */ /* }{ */ |
31 | typedef long l_mem; | ||
32 | typedef unsigned long lu_mem; | 32 | typedef unsigned long lu_mem; |
33 | typedef long l_obj; | ||
34 | #endif /* } */ | 33 | #endif /* } */ |
35 | 34 | ||
36 | #define MAX_LOBJ \ | 35 | #define MAX_LMEM \ |
37 | cast(l_obj, (cast(lu_mem, 1) << (sizeof(l_obj) * CHAR_BIT - 1)) - 1) | 36 | cast(l_mem, (cast(lu_mem, 1) << (sizeof(l_mem) * 8 - 1)) - 1) |
38 | 37 | ||
39 | 38 | ||
40 | /* chars used as small naturals (so that 'char' is reserved for characters) */ | 39 | /* chars used as small naturals (so that 'char' is reserved for characters) */ |
@@ -151,7 +151,7 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { | |||
151 | global_State *g = G(L); | 151 | global_State *g = G(L); |
152 | lua_assert((osize == 0) == (block == NULL)); | 152 | lua_assert((osize == 0) == (block == NULL)); |
153 | callfrealloc(g, block, osize, 0); | 153 | callfrealloc(g, block, osize, 0); |
154 | g->GCtotalbytes -= osize; | 154 | g->GCdebt += cast(l_mem, osize); |
155 | } | 155 | } |
156 | 156 | ||
157 | 157 | ||
@@ -181,10 +181,10 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | |||
181 | if (l_unlikely(newblock == NULL && nsize > 0)) { | 181 | if (l_unlikely(newblock == NULL && nsize > 0)) { |
182 | newblock = tryagain(L, block, osize, nsize); | 182 | newblock = tryagain(L, block, osize, nsize); |
183 | if (newblock == NULL) /* still no memory? */ | 183 | if (newblock == NULL) /* still no memory? */ |
184 | return NULL; /* do not update 'GCtotalbytes' */ | 184 | return NULL; /* do not update 'GCdebt' */ |
185 | } | 185 | } |
186 | lua_assert((nsize == 0) == (newblock == NULL)); | 186 | lua_assert((nsize == 0) == (newblock == NULL)); |
187 | g->GCtotalbytes += nsize - osize; | 187 | g->GCdebt -= cast(l_mem, nsize) - cast(l_mem, osize); |
188 | return newblock; | 188 | return newblock; |
189 | } | 189 | } |
190 | 190 | ||
@@ -209,7 +209,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) { | |||
209 | if (newblock == NULL) | 209 | if (newblock == NULL) |
210 | luaM_error(L); | 210 | luaM_error(L); |
211 | } | 211 | } |
212 | g->GCtotalbytes += size; | 212 | g->GCdebt -= cast(l_mem, size); |
213 | return newblock; | 213 | return newblock; |
214 | } | 214 | } |
215 | } | 215 | } |
@@ -85,7 +85,7 @@ lu_byte luaO_codeparam (unsigned int p) { | |||
85 | ** more significant bits, as long as the multiplication does not | 85 | ** more significant bits, as long as the multiplication does not |
86 | ** overflow, so we check which order is best. | 86 | ** overflow, so we check which order is best. |
87 | */ | 87 | */ |
88 | l_obj luaO_applyparam (lu_byte p, l_obj x) { | 88 | l_mem luaO_applyparam (lu_byte p, l_mem x) { |
89 | unsigned int m = p & 0xF; /* mantissa */ | 89 | unsigned int m = p & 0xF; /* mantissa */ |
90 | int e = (p >> 4); /* exponent */ | 90 | int e = (p >> 4); /* exponent */ |
91 | if (e > 0) { /* normalized? */ | 91 | if (e > 0) { /* normalized? */ |
@@ -94,19 +94,19 @@ l_obj luaO_applyparam (lu_byte p, l_obj x) { | |||
94 | } | 94 | } |
95 | e -= 7; /* correct excess-7 */ | 95 | e -= 7; /* correct excess-7 */ |
96 | if (e >= 0) { | 96 | if (e >= 0) { |
97 | if (x < (MAX_LOBJ / 0x1F) >> e) /* no overflow? */ | 97 | if (x < (MAX_LMEM / 0x1F) >> e) /* no overflow? */ |
98 | return (x * m) << e; /* order doesn't matter here */ | 98 | return (x * m) << e; /* order doesn't matter here */ |
99 | else /* real overflow */ | 99 | else /* real overflow */ |
100 | return MAX_LOBJ; | 100 | return MAX_LMEM; |
101 | } | 101 | } |
102 | else { /* negative exponent */ | 102 | else { /* negative exponent */ |
103 | e = -e; | 103 | e = -e; |
104 | if (x < MAX_LOBJ / 0x1F) /* multiplication cannot overflow? */ | 104 | if (x < MAX_LMEM / 0x1F) /* multiplication cannot overflow? */ |
105 | return (x * m) >> e; /* multiplying first gives more precision */ | 105 | return (x * m) >> e; /* multiplying first gives more precision */ |
106 | else if ((x >> e) < MAX_LOBJ / 0x1F) /* cannot overflow after shift? */ | 106 | else if ((x >> e) < MAX_LMEM / 0x1F) /* cannot overflow after shift? */ |
107 | return (x >> e) * m; | 107 | return (x >> e) * m; |
108 | else /* real overflow */ | 108 | else /* real overflow */ |
109 | return MAX_LOBJ; | 109 | return MAX_LMEM; |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
@@ -838,7 +838,7 @@ typedef struct Table { | |||
838 | LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); | 838 | LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); |
839 | LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x); | 839 | LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x); |
840 | LUAI_FUNC lu_byte luaO_codeparam (unsigned int p); | 840 | LUAI_FUNC lu_byte luaO_codeparam (unsigned int p); |
841 | LUAI_FUNC l_obj luaO_applyparam (lu_byte p, l_obj x); | 841 | LUAI_FUNC l_mem luaO_applyparam (lu_byte p, l_mem x); |
842 | 842 | ||
843 | LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, | 843 | LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, |
844 | const TValue *p2, TValue *res); | 844 | const TValue *p2, TValue *res); |
@@ -77,12 +77,12 @@ typedef struct LG { | |||
77 | ** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in | 77 | ** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in |
78 | ** 'GCtotalobjs'. | 78 | ** 'GCtotalobjs'. |
79 | */ | 79 | */ |
80 | void luaE_setdebt (global_State *g, l_obj debt) { | 80 | void luaE_setdebt (global_State *g, l_mem debt) { |
81 | l_obj tb = gettotalobjs(g); | 81 | l_mem tb = gettotalbytes(g); |
82 | lua_assert(tb > 0); | 82 | lua_assert(tb > 0); |
83 | if (debt > MAX_LOBJ - tb) | 83 | if (debt > MAX_LMEM - tb) |
84 | debt = MAX_LOBJ - tb; /* will make GCtotalobjs == MAX_LOBJ */ | 84 | debt = MAX_LMEM - tb; /* will make GCtotalbytes == MAX_LMEM */ |
85 | g->GCtotalobjs = tb + debt; | 85 | g->GCtotalbytes = tb + debt; |
86 | g->GCdebt = debt; | 86 | g->GCdebt = debt; |
87 | } | 87 | } |
88 | 88 | ||
@@ -269,8 +269,7 @@ static void close_state (lua_State *L) { | |||
269 | } | 269 | } |
270 | luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size)); | 270 | luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size)); |
271 | freestack(L); | 271 | freestack(L); |
272 | lua_assert(g->GCtotalbytes == sizeof(LG)); | 272 | lua_assert(gettotalbytes(g) == sizeof(LG)); |
273 | lua_assert(gettotalobjs(g) == 1); | ||
274 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ | 273 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ |
275 | } | 274 | } |
276 | 275 | ||
@@ -379,7 +378,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned seed) { | |||
379 | g->weak = g->ephemeron = g->allweak = NULL; | 378 | g->weak = g->ephemeron = g->allweak = NULL; |
380 | g->twups = NULL; | 379 | g->twups = NULL; |
381 | g->GCtotalbytes = sizeof(LG); | 380 | g->GCtotalbytes = sizeof(LG); |
382 | g->GCtotalobjs = 1; | ||
383 | g->GCmarked = 0; | 381 | g->GCmarked = 0; |
384 | g->GCdebt = 0; | 382 | g->GCdebt = 0; |
385 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ | 383 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ |
@@ -274,11 +274,10 @@ struct CallInfo { | |||
274 | typedef struct global_State { | 274 | typedef struct global_State { |
275 | lua_Alloc frealloc; /* function to reallocate memory */ | 275 | lua_Alloc frealloc; /* function to reallocate memory */ |
276 | void *ud; /* auxiliary data to 'frealloc' */ | 276 | void *ud; /* auxiliary data to 'frealloc' */ |
277 | lu_mem GCtotalbytes; /* number of bytes currently allocated */ | 277 | l_mem GCtotalbytes; /* number of bytes currently allocated + debt */ |
278 | l_obj GCtotalobjs; /* total number of objects allocated + GCdebt */ | 278 | l_mem GCdebt; /* bytes counted but not yet allocated */ |
279 | l_obj GCdebt; /* objects counted but not yet allocated */ | 279 | l_mem GCmarked; /* number of objects marked in a GC cycle */ |
280 | l_obj GCmarked; /* number of objects marked in a GC cycle */ | 280 | l_mem GCmajorminor; /* auxiliary counter to control major-minor shifts */ |
281 | l_obj GCmajorminor; /* auxiliary counter to control major-minor shifts */ | ||
282 | stringtable strt; /* hash table for strings */ | 281 | stringtable strt; /* hash table for strings */ |
283 | TValue l_registry; | 282 | TValue l_registry; |
284 | TValue nilvalue; /* a nil value */ | 283 | TValue nilvalue; /* a nil value */ |
@@ -411,11 +410,11 @@ union GCUnion { | |||
411 | #define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) | 410 | #define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc)) |
412 | 411 | ||
413 | 412 | ||
414 | /* actual number of total objects allocated */ | 413 | /* actual number of total memory allocated */ |
415 | #define gettotalobjs(g) ((g)->GCtotalobjs - (g)->GCdebt) | 414 | #define gettotalbytes(g) ((g)->GCtotalbytes - (g)->GCdebt) |
416 | 415 | ||
417 | 416 | ||
418 | LUAI_FUNC void luaE_setdebt (global_State *g, l_obj debt); | 417 | LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); |
419 | LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); | 418 | LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); |
420 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); | 419 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); |
421 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); | 420 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); |
@@ -537,7 +537,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead, | |||
537 | } | 537 | } |
538 | 538 | ||
539 | 539 | ||
540 | static l_obj checkgraylist (global_State *g, GCObject *o) { | 540 | static l_mem checkgraylist (global_State *g, GCObject *o) { |
541 | int total = 0; /* count number of elements in the list */ | 541 | int total = 0; /* count number of elements in the list */ |
542 | cast_void(g); /* better to keep it if we need to print an object */ | 542 | cast_void(g); /* better to keep it if we need to print an object */ |
543 | while (o) { | 543 | while (o) { |
@@ -566,8 +566,8 @@ static l_obj checkgraylist (global_State *g, GCObject *o) { | |||
566 | /* | 566 | /* |
567 | ** Check objects in gray lists. | 567 | ** Check objects in gray lists. |
568 | */ | 568 | */ |
569 | static l_obj checkgrays (global_State *g) { | 569 | static l_mem checkgrays (global_State *g) { |
570 | l_obj total = 0; /* count number of elements in all lists */ | 570 | l_mem total = 0; /* count number of elements in all lists */ |
571 | if (!keepinvariant(g)) return total; | 571 | if (!keepinvariant(g)) return total; |
572 | total += checkgraylist(g, g->gray); | 572 | total += checkgraylist(g, g->gray); |
573 | total += checkgraylist(g, g->grayagain); | 573 | total += checkgraylist(g, g->grayagain); |
@@ -583,7 +583,7 @@ static l_obj checkgrays (global_State *g) { | |||
583 | ** 'count' and check its TESTBIT. (It must have been previously set by | 583 | ** 'count' and check its TESTBIT. (It must have been previously set by |
584 | ** 'checkgraylist'.) | 584 | ** 'checkgraylist'.) |
585 | */ | 585 | */ |
586 | static void incifingray (global_State *g, GCObject *o, l_obj *count) { | 586 | static void incifingray (global_State *g, GCObject *o, l_mem *count) { |
587 | if (!keepinvariant(g)) | 587 | if (!keepinvariant(g)) |
588 | return; /* gray lists not being kept in these phases */ | 588 | return; /* gray lists not being kept in these phases */ |
589 | if (o->tt == LUA_VUPVAL) { | 589 | if (o->tt == LUA_VUPVAL) { |
@@ -600,10 +600,10 @@ static void incifingray (global_State *g, GCObject *o, l_obj *count) { | |||
600 | } | 600 | } |
601 | 601 | ||
602 | 602 | ||
603 | static l_obj checklist (global_State *g, int maybedead, int tof, | 603 | static l_mem checklist (global_State *g, int maybedead, int tof, |
604 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { | 604 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { |
605 | GCObject *o; | 605 | GCObject *o; |
606 | l_obj total = 0; /* number of object that should be in gray lists */ | 606 | l_mem total = 0; /* number of object that should be in gray lists */ |
607 | for (o = newl; o != survival; o = o->next) { | 607 | for (o = newl; o != survival; o = o->next) { |
608 | checkobject(g, o, maybedead, G_NEW); | 608 | checkobject(g, o, maybedead, G_NEW); |
609 | incifingray(g, o, &total); | 609 | incifingray(g, o, &total); |
@@ -632,8 +632,8 @@ int lua_checkmemory (lua_State *L) { | |||
632 | global_State *g = G(L); | 632 | global_State *g = G(L); |
633 | GCObject *o; | 633 | GCObject *o; |
634 | int maybedead; | 634 | int maybedead; |
635 | l_obj totalin; /* total of objects that are in gray lists */ | 635 | l_mem totalin; /* total of objects that are in gray lists */ |
636 | l_obj totalshould; /* total of objects that should be in gray lists */ | 636 | l_mem totalshould; /* total of objects that should be in gray lists */ |
637 | if (keepinvariant(g)) { | 637 | if (keepinvariant(g)) { |
638 | assert(!iswhite(g->mainthread)); | 638 | assert(!iswhite(g->mainthread)); |
639 | assert(!iswhite(gcvalue(&g->l_registry))); | 639 | assert(!iswhite(gcvalue(&g->l_registry))); |
@@ -1040,7 +1040,7 @@ static int table_query (lua_State *L) { | |||
1040 | 1040 | ||
1041 | static int query_GCparams (lua_State *L) { | 1041 | static int query_GCparams (lua_State *L) { |
1042 | global_State *g = G(L); | 1042 | global_State *g = G(L); |
1043 | lua_pushinteger(L, cast(lua_Integer, gettotalobjs(g))); | 1043 | lua_pushinteger(L, cast(lua_Integer, gettotalbytes(g))); |
1044 | lua_pushinteger(L, cast(lua_Integer, g->GCdebt)); | 1044 | lua_pushinteger(L, cast(lua_Integer, g->GCdebt)); |
1045 | lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100))); | 1045 | lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100))); |
1046 | lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100))); | 1046 | lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100))); |