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))); |
