diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-02-16 16:09:52 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-02-16 16:09:52 -0300 |
| commit | 2aaf7394ad17180565423ce360d5faffb60f4e4f (patch) | |
| tree | 32caa2d7b0079b4bc9b0ac392d216c5094a6433d | |
| parent | b3ce4505296253e6da1fa780c23e7ed012efc88e (diff) | |
| download | lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.gz lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.bz2 lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.zip | |
more and better tools (assertions & inspectors) to check incremental GC
| -rw-r--r-- | lfunc.c | 9 | ||||
| -rw-r--r-- | lgc.c | 61 | ||||
| -rw-r--r-- | lgc.h | 4 | ||||
| -rw-r--r-- | lobject.h | 20 | ||||
| -rw-r--r-- | lstate.c | 4 | ||||
| -rw-r--r-- | ltests.c | 184 | ||||
| -rw-r--r-- | ltests.h | 4 | ||||
| -rw-r--r-- | ltm.c | 5 |
8 files changed, 249 insertions, 42 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.c,v 1.74 2003/12/09 16:56:11 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ |
| 3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -57,7 +57,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 57 | } | 57 | } |
| 58 | uv = luaM_new(L, UpVal); /* not found: create a new one */ | 58 | uv = luaM_new(L, UpVal); /* not found: create a new one */ |
| 59 | uv->tt = LUA_TUPVAL; | 59 | uv->tt = LUA_TUPVAL; |
| 60 | uv->marked = bitmask(FIXEDBIT); /* open upvalues cannot be collected */ | 60 | uv->marked = luaC_white(G(L)); |
| 61 | uv->v = level; /* current value lives in the stack */ | 61 | uv->v = level; /* current value lives in the stack */ |
| 62 | uv->next = *pp; /* chain it in the proper position */ | 62 | uv->next = *pp; /* chain it in the proper position */ |
| 63 | *pp = obj2gco(uv); | 63 | *pp = obj2gco(uv); |
| @@ -68,11 +68,16 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 68 | void luaF_close (lua_State *L, StkId level) { | 68 | void luaF_close (lua_State *L, StkId level) { |
| 69 | UpVal *uv; | 69 | UpVal *uv; |
| 70 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { | 70 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { |
| 71 | lu_byte mark = uv->marked; | ||
| 72 | lua_assert(!isblack(obj2gco(uv))); | ||
| 71 | setobj(L, &uv->value, uv->v); | 73 | setobj(L, &uv->value, uv->v); |
| 72 | luaC_barrier(L, uv, uv->v); | 74 | luaC_barrier(L, uv, uv->v); |
| 73 | uv->v = &uv->value; /* now current value lives here */ | 75 | uv->v = &uv->value; /* now current value lives here */ |
| 74 | L->openupval = uv->next; /* remove from `open' list */ | 76 | L->openupval = uv->next; /* remove from `open' list */ |
| 75 | luaC_link(L, obj2gco(uv), LUA_TUPVAL); | 77 | luaC_link(L, obj2gco(uv), LUA_TUPVAL); |
| 78 | if (G(L)->gcstate == GCSpropagate) | ||
| 79 | uv->marked = mark; /* preserve previous mark */ | ||
| 80 | lua_assert(!isdead(G(L), obj2gco(uv))); | ||
| 76 | } | 81 | } |
| 77 | } | 82 | } |
| 78 | 83 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -60,6 +60,7 @@ | |||
| 60 | 60 | ||
| 61 | 61 | ||
| 62 | 62 | ||
| 63 | |||
| 63 | /* | 64 | /* |
| 64 | ** computes the size of a collectible object | 65 | ** computes the size of a collectible object |
| 65 | */ | 66 | */ |
| @@ -152,7 +153,7 @@ static void marktmu (global_State *g) { | |||
| 152 | 153 | ||
| 153 | 154 | ||
| 154 | /* move `dead' udata that need finalization to list `tmudata' */ | 155 | /* move `dead' udata that need finalization to list `tmudata' */ |
| 155 | size_t luaC_separateudata (lua_State *L) { | 156 | size_t luaC_separateudata (lua_State *L, int all) { |
| 156 | size_t deadmem = 0; | 157 | size_t deadmem = 0; |
| 157 | GCObject **p = &G(L)->firstudata; | 158 | GCObject **p = &G(L)->firstudata; |
| 158 | GCObject *curr; | 159 | GCObject *curr; |
| @@ -160,7 +161,7 @@ size_t luaC_separateudata (lua_State *L) { | |||
| 160 | GCObject **lastcollected = &collected; | 161 | GCObject **lastcollected = &collected; |
| 161 | while ((curr = *p) != NULL) { | 162 | while ((curr = *p) != NULL) { |
| 162 | lua_assert(curr->gch.tt == LUA_TUSERDATA); | 163 | lua_assert(curr->gch.tt == LUA_TUSERDATA); |
| 163 | if (!iswhite(curr) || isfinalized(gco2u(curr))) | 164 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) |
| 164 | p = &curr->gch.next; /* don't bother with them */ | 165 | p = &curr->gch.next; /* don't bother with them */ |
| 165 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | 166 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { |
| 166 | markfinalized(gco2u(curr)); /* don't need finalization */ | 167 | markfinalized(gco2u(curr)); /* don't need finalization */ |
| @@ -182,7 +183,7 @@ size_t luaC_separateudata (lua_State *L) { | |||
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | 185 | ||
| 185 | static void traversetable (global_State *g, Table *h) { | 186 | static int traversetable (global_State *g, Table *h) { |
| 186 | int i; | 187 | int i; |
| 187 | int weakkey = 0; | 188 | int weakkey = 0; |
| 188 | int weakvalue = 0; | 189 | int weakvalue = 0; |
| @@ -202,7 +203,7 @@ static void traversetable (global_State *g, Table *h) { | |||
| 202 | g->weak = obj2gco(h); /* ... so put in the appropriate list */ | 203 | g->weak = obj2gco(h); /* ... so put in the appropriate list */ |
| 203 | } | 204 | } |
| 204 | } | 205 | } |
| 205 | if (weakkey && weakvalue) return; | 206 | if (weakkey && weakvalue) return 1; |
| 206 | if (!weakvalue) { | 207 | if (!weakvalue) { |
| 207 | i = h->sizearray; | 208 | i = h->sizearray; |
| 208 | while (i--) | 209 | while (i--) |
| @@ -217,6 +218,7 @@ static void traversetable (global_State *g, Table *h) { | |||
| 217 | condmarkobject(g, gval(n), !weakvalue); | 218 | condmarkobject(g, gval(n), !weakvalue); |
| 218 | } | 219 | } |
| 219 | } | 220 | } |
| 221 | return weakkey || weakvalue; | ||
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | 224 | ||
| @@ -227,10 +229,8 @@ static void traversetable (global_State *g, Table *h) { | |||
| 227 | static void traverseproto (global_State *g, Proto *f) { | 229 | static void traverseproto (global_State *g, Proto *f) { |
| 228 | int i; | 230 | int i; |
| 229 | if (f->source) stringmark(f->source); | 231 | if (f->source) stringmark(f->source); |
| 230 | for (i=0; i<f->sizek; i++) { /* mark literal strings */ | 232 | for (i=0; i<f->sizek; i++) /* mark literals */ |
| 231 | if (ttisstring(f->k+i)) | 233 | markvalue(g, &f->k[i]); |
| 232 | stringmark(rawtsvalue(f->k+i)); | ||
| 233 | } | ||
| 234 | for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ | 234 | for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ |
| 235 | if (f->upvalues[i]) | 235 | if (f->upvalues[i]) |
| 236 | stringmark(f->upvalues[i]); | 236 | stringmark(f->upvalues[i]); |
| @@ -258,9 +258,8 @@ static void traverseclosure (global_State *g, Closure *cl) { | |||
| 258 | lua_assert(cl->l.nupvalues == cl->l.p->nups); | 258 | lua_assert(cl->l.nupvalues == cl->l.p->nups); |
| 259 | markobject(g, hvalue(&cl->l.g)); | 259 | markobject(g, hvalue(&cl->l.g)); |
| 260 | markobject(g, cl->l.p); | 260 | markobject(g, cl->l.p); |
| 261 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 261 | for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ |
| 262 | markobject(g, cl->l.upvals[i]); | 262 | markobject(g, cl->l.upvals[i]); |
| 263 | } | ||
| 264 | } | 263 | } |
| 265 | } | 264 | } |
| 266 | 265 | ||
| @@ -307,7 +306,8 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
| 307 | case LUA_TTABLE: { | 306 | case LUA_TTABLE: { |
| 308 | Table *h = gco2h(o); | 307 | Table *h = gco2h(o); |
| 309 | g->gray = h->gclist; | 308 | g->gray = h->gclist; |
| 310 | traversetable(g, h); | 309 | if (traversetable(g, h)) /* table is weak? */ |
| 310 | black2gray(o); /* keep it gray */ | ||
| 311 | break; | 311 | break; |
| 312 | } | 312 | } |
| 313 | case LUA_TFUNCTION: { | 313 | case LUA_TFUNCTION: { |
| @@ -339,7 +339,8 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
| 339 | g->grayagain = o; | 339 | g->grayagain = o; |
| 340 | black2gray(o); | 340 | black2gray(o); |
| 341 | } | 341 | } |
| 342 | markvalue(g, &uv->value); | 342 | else |
| 343 | markvalue(g, &uv->value); | ||
| 343 | break; | 344 | break; |
| 344 | } | 345 | } |
| 345 | default: lua_assert(0); | 346 | default: lua_assert(0); |
| @@ -428,6 +429,13 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 428 | } | 429 | } |
| 429 | 430 | ||
| 430 | 431 | ||
| 432 | static void sweepupvalues (global_State *g, lua_State *L1) { | ||
| 433 | GCObject *curr; | ||
| 434 | for (curr = L1->openupval; curr != NULL; curr = curr->gch.next) | ||
| 435 | makewhite(g, curr); | ||
| 436 | } | ||
| 437 | |||
| 438 | |||
| 431 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | 439 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, |
| 432 | l_mem *plim) { | 440 | l_mem *plim) { |
| 433 | GCObject *curr; | 441 | GCObject *curr; |
| @@ -439,10 +447,14 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
| 439 | lim -= objsize(curr); | 447 | lim -= objsize(curr); |
| 440 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 448 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { |
| 441 | makewhite(g, curr); | 449 | makewhite(g, curr); |
| 450 | if (curr->gch.tt == LUA_TTHREAD) | ||
| 451 | sweepupvalues(g, gco2th(curr)); | ||
| 442 | p = &curr->gch.next; | 452 | p = &curr->gch.next; |
| 443 | } | 453 | } |
| 444 | else { | 454 | else { |
| 445 | *p = curr->gch.next; | 455 | *p = curr->gch.next; |
| 456 | if (curr == g->rootgc) /* is the first element of the list? */ | ||
| 457 | g->rootgc = curr->gch.next; /* adjust first */ | ||
| 446 | freeobj(L, curr); | 458 | freeobj(L, curr); |
| 447 | } | 459 | } |
| 448 | if (lim <= 0) break; | 460 | if (lim <= 0) break; |
| @@ -537,7 +549,8 @@ void luaC_sweepall (lua_State *L) { | |||
| 537 | /* mark root set */ | 549 | /* mark root set */ |
| 538 | static void markroot (lua_State *L) { | 550 | static void markroot (lua_State *L) { |
| 539 | global_State *g = G(L); | 551 | global_State *g = G(L); |
| 540 | lua_assert(g->gray == NULL && g->grayagain == NULL); | 552 | lua_assert(g->gray == NULL); |
| 553 | g->grayagain = NULL; | ||
| 541 | g->weak = NULL; | 554 | g->weak = NULL; |
| 542 | makewhite(g, obj2gco(g->mainthread)); | 555 | makewhite(g, obj2gco(g->mainthread)); |
| 543 | markobject(g, g->mainthread); | 556 | markobject(g, g->mainthread); |
| @@ -550,28 +563,30 @@ static void markroot (lua_State *L) { | |||
| 550 | static void atomic (lua_State *L) { | 563 | static void atomic (lua_State *L) { |
| 551 | global_State *g = G(L); | 564 | global_State *g = G(L); |
| 552 | lua_assert(g->gray == NULL); | 565 | lua_assert(g->gray == NULL); |
| 566 | /* remark weak tables */ | ||
| 567 | g->gray = g->weak; | ||
| 568 | g->weak = NULL; | ||
| 569 | propagatemarks(g, MAXLMEM); | ||
| 570 | /* remark gray again */ | ||
| 553 | g->gray = g->grayagain; | 571 | g->gray = g->grayagain; |
| 554 | g->grayagain = NULL; | 572 | g->grayagain = NULL; |
| 555 | propagatemarks(g, MAXLMEM); | 573 | propagatemarks(g, MAXLMEM); |
| 556 | luaC_separateudata(L); /* separate userdata to be preserved */ | 574 | luaC_separateudata(L, 0); /* separate userdata to be preserved */ |
| 557 | marktmu(g); /* mark `preserved' userdata */ | 575 | marktmu(g); /* mark `preserved' userdata */ |
| 558 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ | 576 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ |
| 559 | cleartable(g->weak); /* remove collected objects from weak tables */ | 577 | cleartable(g->weak); /* remove collected objects from weak tables */ |
| 560 | /* flip current white */ | 578 | /* flip current white */ |
| 561 | g->currentwhite = otherwhite(g); | 579 | g->currentwhite = otherwhite(g); |
| 562 | /* first element of root list will be used as temporary head for sweep | 580 | g->sweepgc = &g->rootgc; |
| 563 | phase, so it won't be swept */ | ||
| 564 | makewhite(g, g->rootgc); | ||
| 565 | g->sweepgc = &g->rootgc->gch.next; | ||
| 566 | g->sweepstrgc = 0; | 581 | g->sweepstrgc = 0; |
| 567 | g->gcstate = GCSsweepstring; | 582 | g->gcstate = GCSsweepstring; |
| 568 | g->grayagain = NULL; | ||
| 569 | } | 583 | } |
| 570 | 584 | ||
| 571 | 585 | ||
| 572 | void luaC_step (lua_State *L) { | 586 | void luaC_step (lua_State *L) { |
| 573 | global_State *g = G(L); | 587 | global_State *g = G(L); |
| 574 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; | 588 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; |
| 589 | luaC_checkall(L); | ||
| 575 | switch (g->gcstate) { | 590 | switch (g->gcstate) { |
| 576 | case GCSpropagate: { | 591 | case GCSpropagate: { |
| 577 | if (g->gray) | 592 | if (g->gray) |
| @@ -593,8 +608,9 @@ void luaC_step (lua_State *L) { | |||
| 593 | case GCSsweep: { | 608 | case GCSsweep: { |
| 594 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); | 609 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); |
| 595 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 610 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
| 596 | g->gcstate = GCSfinalize; /* end sweep phase */ | ||
| 597 | checkSizes(L); | 611 | checkSizes(L); |
| 612 | sweepupvalues(g, g->mainthread); | ||
| 613 | g->gcstate = GCSfinalize; /* end sweep phase */ | ||
| 598 | } | 614 | } |
| 599 | break; | 615 | break; |
| 600 | } | 616 | } |
| @@ -610,13 +626,14 @@ void luaC_step (lua_State *L) { | |||
| 610 | default: lua_assert(0); | 626 | default: lua_assert(0); |
| 611 | } | 627 | } |
| 612 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; | 628 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; |
| 629 | luaC_checkall(L); | ||
| 613 | } | 630 | } |
| 614 | 631 | ||
| 615 | 632 | ||
| 616 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | 633 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { |
| 617 | global_State *g = G(L); | 634 | global_State *g = G(L); |
| 618 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 635 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
| 619 | if (g->gcstate >= GCSsweepstring) /* sweeping phases? */ | 636 | if (g->gcstate != GCSpropagate) /* sweeping phases? */ |
| 620 | black2gray(o); /* just mark as gray to avoid other barriers */ | 637 | black2gray(o); /* just mark as gray to avoid other barriers */ |
| 621 | else /* breaking invariant! */ | 638 | else /* breaking invariant! */ |
| 622 | reallymarkobject(g, v); /* restore it */ | 639 | reallymarkobject(g, v); /* restore it */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -81,7 +81,7 @@ | |||
| 81 | { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ | 81 | { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ |
| 82 | luaC_barrierf(L,obj2gco(p),obj2gco(o)); } | 82 | luaC_barrierf(L,obj2gco(p),obj2gco(o)); } |
| 83 | 83 | ||
| 84 | size_t luaC_separateudata (lua_State *L); | 84 | size_t luaC_separateudata (lua_State *L, int all); |
| 85 | void luaC_callGCTM (lua_State *L); | 85 | void luaC_callGCTM (lua_State *L); |
| 86 | void luaC_sweepall (lua_State *L); | 86 | void luaC_sweepall (lua_State *L); |
| 87 | void luaC_step (lua_State *L); | 87 | void luaC_step (lua_State *L); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lobject.h,v 1.162 2003/11/18 14:55:11 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ |
| 3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -99,9 +99,9 @@ typedef struct lua_TValue { | |||
| 99 | #define checkconsistency(obj) \ | 99 | #define checkconsistency(obj) \ |
| 100 | lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) | 100 | lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) |
| 101 | 101 | ||
| 102 | #define checkliveness(L,obj) \ | 102 | #define checkliveness(g,obj) \ |
| 103 | lua_assert(!iscollectable(obj) || \ | 103 | lua_assert(!iscollectable(obj) || \ |
| 104 | ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(G(L), (obj)->value.gc))) | 104 | ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) |
| 105 | 105 | ||
| 106 | 106 | ||
| 107 | /* Macros to set values */ | 107 | /* Macros to set values */ |
| @@ -122,32 +122,32 @@ typedef struct lua_TValue { | |||
| 122 | #define setsvalue(L,obj,x) \ | 122 | #define setsvalue(L,obj,x) \ |
| 123 | { TValue *i_o=(obj); \ | 123 | { TValue *i_o=(obj); \ |
| 124 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ | 124 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ |
| 125 | checkliveness(L,i_o); } | 125 | checkliveness(G(L),i_o); } |
| 126 | 126 | ||
| 127 | #define setuvalue(L,obj,x) \ | 127 | #define setuvalue(L,obj,x) \ |
| 128 | { TValue *i_o=(obj); \ | 128 | { TValue *i_o=(obj); \ |
| 129 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ | 129 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ |
| 130 | checkliveness(L,i_o); } | 130 | checkliveness(G(L),i_o); } |
| 131 | 131 | ||
| 132 | #define setthvalue(L,obj,x) \ | 132 | #define setthvalue(L,obj,x) \ |
| 133 | { TValue *i_o=(obj); \ | 133 | { TValue *i_o=(obj); \ |
| 134 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ | 134 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ |
| 135 | checkliveness(L,i_o); } | 135 | checkliveness(G(L),i_o); } |
| 136 | 136 | ||
| 137 | #define setclvalue(L,obj,x) \ | 137 | #define setclvalue(L,obj,x) \ |
| 138 | { TValue *i_o=(obj); \ | 138 | { TValue *i_o=(obj); \ |
| 139 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ | 139 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ |
| 140 | checkliveness(L,i_o); } | 140 | checkliveness(G(L),i_o); } |
| 141 | 141 | ||
| 142 | #define sethvalue(L,obj,x) \ | 142 | #define sethvalue(L,obj,x) \ |
| 143 | { TValue *i_o=(obj); \ | 143 | { TValue *i_o=(obj); \ |
| 144 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ | 144 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ |
| 145 | checkliveness(L,i_o); } | 145 | checkliveness(G(L),i_o); } |
| 146 | 146 | ||
| 147 | #define setptvalue(L,obj,x) \ | 147 | #define setptvalue(L,obj,x) \ |
| 148 | { TValue *i_o=(obj); \ | 148 | { TValue *i_o=(obj); \ |
| 149 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ | 149 | i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ |
| 150 | checkliveness(L,i_o); } | 150 | checkliveness(G(L),i_o); } |
| 151 | 151 | ||
| 152 | 152 | ||
| 153 | 153 | ||
| @@ -155,7 +155,7 @@ typedef struct lua_TValue { | |||
| 155 | #define setobj(L,obj1,obj2) \ | 155 | #define setobj(L,obj1,obj2) \ |
| 156 | { const TValue *o2=(obj2); TValue *o1=(obj1); \ | 156 | { const TValue *o2=(obj2); TValue *o1=(obj1); \ |
| 157 | o1->tt=o2->tt; o1->value = o2->value; \ | 157 | o1->tt=o2->tt; o1->value = o2->value; \ |
| 158 | checkliveness(L,o1); } | 158 | checkliveness(G(L),o1); } |
| 159 | 159 | ||
| 160 | 160 | ||
| 161 | /* | 161 | /* |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -200,7 +200,7 @@ LUA_API void lua_close (lua_State *L) { | |||
| 200 | lua_lock(L); | 200 | lua_lock(L); |
| 201 | L = G(L)->mainthread; /* only the main thread can be closed */ | 201 | L = G(L)->mainthread; /* only the main thread can be closed */ |
| 202 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | 202 | luaF_close(L, L->stack); /* close all upvalues for this thread */ |
| 203 | luaC_separateudata(L); /* separate udata that have GC metamethods */ | 203 | luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ |
| 204 | L->errfunc = 0; /* no error function during GC metamethods */ | 204 | L->errfunc = 0; /* no error function during GC metamethods */ |
| 205 | do { /* repeat until no more errors */ | 205 | do { /* repeat until no more errors */ |
| 206 | L->ci = L->base_ci; | 206 | L->ci = L->base_ci; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 1.169 2003/11/19 12:21:57 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -143,6 +143,188 @@ void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) { | |||
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | ** {====================================================== | 145 | ** {====================================================== |
| 146 | ** Functions to check memory consistency | ||
| 147 | ** ======================================================= | ||
| 148 | */ | ||
| 149 | |||
| 150 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | ||
| 151 | if (isdead(g,t)) return 0; | ||
| 152 | if (g->gcstate == GCSpropagate) | ||
| 153 | return !isblack(f) || !iswhite(t); | ||
| 154 | else if (g->gcstate == GCSfinalize) | ||
| 155 | return iswhite(f); | ||
| 156 | else | ||
| 157 | return 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | static void printobj (global_State *g, GCObject *o) { | ||
| 162 | int i = 0; | ||
| 163 | GCObject *p; | ||
| 164 | for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++; | ||
| 165 | if (p == NULL) i = -1; | ||
| 166 | printf("%d:%s(%p)-%c", | ||
| 167 | i, luaT_typenames[o->gch.tt], (void *)o, | ||
| 168 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g'); | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 172 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | ||
| 173 | int r = testobjref1(g,f,t); | ||
| 174 | if (!r) { | ||
| 175 | printf("%d - ", g->gcstate); | ||
| 176 | printobj(g, f); | ||
| 177 | printf("\t-> "); | ||
| 178 | printobj(g, t); | ||
| 179 | printf("\n"); | ||
| 180 | } | ||
| 181 | return r; | ||
| 182 | } | ||
| 183 | |||
| 184 | #define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t))) | ||
| 185 | |||
| 186 | #define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \ | ||
| 187 | ((ttype(t) == (t)->value.gc->gch.tt) && testobjref(g,f,gcvalue(t)))) | ||
| 188 | |||
| 189 | |||
| 190 | |||
| 191 | static void checktable (global_State *g, Table *h) { | ||
| 192 | int i; | ||
| 193 | int weakkey = 0; | ||
| 194 | int weakvalue = 0; | ||
| 195 | const TValue *mode; | ||
| 196 | GCObject *hgc = obj2gco(h); | ||
| 197 | if (h->metatable) | ||
| 198 | checkobjref(g, hgc, h->metatable); | ||
| 199 | lua_assert(h->lsizenode || h->node == g->dummynode); | ||
| 200 | mode = gfasttm(g, h->metatable, TM_MODE); | ||
| 201 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | ||
| 202 | weakkey = (strchr(svalue(mode), 'k') != NULL); | ||
| 203 | weakvalue = (strchr(svalue(mode), 'v') != NULL); | ||
| 204 | } | ||
| 205 | i = h->sizearray; | ||
| 206 | while (i--) | ||
| 207 | checkvalref(g, hgc, &h->array[i]); | ||
| 208 | i = sizenode(h); | ||
| 209 | while (i--) { | ||
| 210 | Node *n = gnode(h, i); | ||
| 211 | if (!ttisnil(gval(n))) { | ||
| 212 | lua_assert(!ttisnil(gkey(n))); | ||
| 213 | checkvalref(g, hgc, gkey(n)); | ||
| 214 | checkvalref(g, hgc, gval(n)); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | /* | ||
| 221 | ** All marks are conditional because a GC may happen while the | ||
| 222 | ** prototype is still being created | ||
| 223 | */ | ||
| 224 | static void checkproto (global_State *g, Proto *f) { | ||
| 225 | int i; | ||
| 226 | GCObject *fgc = obj2gco(f); | ||
| 227 | if (f->source) checkobjref(g, fgc, f->source); | ||
| 228 | for (i=0; i<f->sizek; i++) { | ||
| 229 | if (ttisstring(f->k+i)) | ||
| 230 | checkobjref(g, fgc, rawtsvalue(f->k+i)); | ||
| 231 | } | ||
| 232 | for (i=0; i<f->sizeupvalues; i++) { | ||
| 233 | if (f->upvalues[i]) | ||
| 234 | checkobjref(g, fgc, f->upvalues[i]); | ||
| 235 | } | ||
| 236 | for (i=0; i<f->sizep; i++) { | ||
| 237 | if (f->p[i]) | ||
| 238 | checkobjref(g, fgc, f->p[i]); | ||
| 239 | } | ||
| 240 | for (i=0; i<f->sizelocvars; i++) { | ||
| 241 | if (f->locvars[i].varname) | ||
| 242 | checkobjref(g, fgc, f->locvars[i].varname); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | |||
| 248 | static void checkclosure (global_State *g, Closure *cl) { | ||
| 249 | GCObject *clgc = obj2gco(cl); | ||
| 250 | if (cl->c.isC) { | ||
| 251 | int i; | ||
| 252 | for (i=0; i<cl->c.nupvalues; i++) | ||
| 253 | checkvalref(g, clgc, &cl->c.upvalue[i]); | ||
| 254 | } | ||
| 255 | else { | ||
| 256 | int i; | ||
| 257 | lua_assert(cl->l.nupvalues == cl->l.p->nups); | ||
| 258 | checkobjref(g, clgc, hvalue(&cl->l.g)); | ||
| 259 | checkobjref(g, clgc, cl->l.p); | ||
| 260 | for (i=0; i<cl->l.nupvalues; i++) { | ||
| 261 | lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL); | ||
| 262 | checkobjref(g, clgc, cl->l.upvals[i]); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | static void checkstack (global_State *g, lua_State *L1) { | ||
| 269 | StkId o; | ||
| 270 | CallInfo *ci; | ||
| 271 | lua_assert(!isdead(g, obj2gco(L1))); | ||
| 272 | checkliveness(g, gt(L1)); | ||
| 273 | for (ci = L1->base_ci; ci <= L1->ci; ci++) | ||
| 274 | lua_assert(ci->top <= L1->stack_last); | ||
| 275 | for (o = L1->stack; o < L1->top; o++) | ||
| 276 | checkliveness(g, o); | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | void luaC_checkall (lua_State *L) { | ||
| 281 | global_State *g = G(L); | ||
| 282 | GCObject *o; | ||
| 283 | checkstack(g, g->mainthread); | ||
| 284 | for (o = g->rootgc; o; o = o->gch.next) { | ||
| 285 | if (isdead(g, o)) | ||
| 286 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | ||
| 287 | else { | ||
| 288 | switch (o->gch.tt) { | ||
| 289 | case LUA_TUPVAL: { | ||
| 290 | UpVal *uv = gco2uv(o); | ||
| 291 | lua_assert(uv->v == &uv->value); /* must be closed */ | ||
| 292 | checkvalref(g, o, uv->v); | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | case LUA_TUSERDATA: { | ||
| 296 | Table *mt = gco2u(o)->metatable; | ||
| 297 | if (mt) checkobjref(g, o, mt); | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | case LUA_TTABLE: { | ||
| 301 | checktable(g, gco2h(o)); | ||
| 302 | break; | ||
| 303 | } | ||
| 304 | case LUA_TTHREAD: { | ||
| 305 | checkstack(g, gco2th(o)); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | case LUA_TFUNCTION: { | ||
| 309 | checkclosure(g, gco2cl(o)); | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | case LUA_TPROTO: { | ||
| 313 | checkproto(g, gco2p(o)); | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | default: lua_assert(0); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /* }====================================================== */ | ||
| 323 | |||
| 324 | |||
| 325 | |||
| 326 | /* | ||
| 327 | ** {====================================================== | ||
| 146 | ** Disassembler | 328 | ** Disassembler |
| 147 | ** ======================================================= | 329 | ** ======================================================= |
| 148 | */ | 330 | */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.h,v 1.21 2003/10/02 20:31:17 roberto Exp roberto $ | 2 | ** $Id: ltests.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ |
| 3 | ** Internal Header for Debugging of the Lua Implementation | 3 | ** Internal Header for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -42,6 +42,8 @@ void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); | |||
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | void luaC_checkall (lua_State *L); | ||
| 46 | |||
| 45 | 47 | ||
| 46 | /* test for lock/unlock */ | 48 | /* test for lock/unlock */ |
| 47 | extern int islocked; | 49 | extern int islocked; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltm.c,v 1.107 2003/12/01 18:22:56 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ |
| 3 | ** Tag methods | 3 | ** Tag methods |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -21,7 +21,8 @@ | |||
| 21 | 21 | ||
| 22 | const char *const luaT_typenames[] = { | 22 | const char *const luaT_typenames[] = { |
| 23 | "nil", "boolean", "userdata", "number", | 23 | "nil", "boolean", "userdata", "number", |
| 24 | "string", "table", "function", "userdata", "thread" | 24 | "string", "table", "function", "userdata", "thread", |
| 25 | "proto", "upval" | ||
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | 28 | ||
