aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2004-02-16 16:09:52 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2004-02-16 16:09:52 -0300
commit2aaf7394ad17180565423ce360d5faffb60f4e4f (patch)
tree32caa2d7b0079b4bc9b0ac392d216c5094a6433d
parentb3ce4505296253e6da1fa780c23e7ed012efc88e (diff)
downloadlua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.gz
lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.tar.bz2
lua-2aaf7394ad17180565423ce360d5faffb60f4e4f.zip
more and better tools (assertions & inspectors) to check incremental GC
-rw-r--r--lfunc.c9
-rw-r--r--lgc.c61
-rw-r--r--lgc.h4
-rw-r--r--lobject.h20
-rw-r--r--lstate.c4
-rw-r--r--ltests.c184
-rw-r--r--ltests.h4
-rw-r--r--ltm.c5
8 files changed, 249 insertions, 42 deletions
diff --git a/lfunc.c b/lfunc.c
index af27bf0d..36bf3f32 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -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) {
68void luaF_close (lua_State *L, StkId level) { 68void 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
diff --git a/lgc.c b/lgc.c
index fe6461c0..ae5cd686 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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' */
155size_t luaC_separateudata (lua_State *L) { 156size_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
185static void traversetable (global_State *g, Table *h) { 186static 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) {
227static void traverseproto (global_State *g, Proto *f) { 229static 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
432static 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
431static GCObject **sweeplist (lua_State *L, GCObject **p, int all, 439static 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 */
538static void markroot (lua_State *L) { 550static 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) {
550static void atomic (lua_State *L) { 563static 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
572void luaC_step (lua_State *L) { 586void 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;
589luaC_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;
629luaC_checkall(L);
613} 630}
614 631
615 632
616void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { 633void 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 */
diff --git a/lgc.h b/lgc.h
index bd8bdadc..a6901076 100644
--- a/lgc.h
+++ b/lgc.h
@@ -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
84size_t luaC_separateudata (lua_State *L); 84size_t luaC_separateudata (lua_State *L, int all);
85void luaC_callGCTM (lua_State *L); 85void luaC_callGCTM (lua_State *L);
86void luaC_sweepall (lua_State *L); 86void luaC_sweepall (lua_State *L);
87void luaC_step (lua_State *L); 87void luaC_step (lua_State *L);
diff --git a/lobject.h b/lobject.h
index fa5364c2..4cdb1701 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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/*
diff --git a/lstate.c b/lstate.c
index 13b15f6f..36e7d9c3 100644
--- a/lstate.c
+++ b/lstate.c
@@ -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;
diff --git a/ltests.c b/ltests.c
index 05093162..581b47ff 100644
--- a/ltests.c
+++ b/ltests.c
@@ -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
150static 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
161static void printobj (global_State *g, GCObject *o) {
162int i = 0;
163GCObject *p;
164for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++;
165if (p == NULL) i = -1;
166printf("%d:%s(%p)-%c",
167i, luaT_typenames[o->gch.tt], (void *)o,
168isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g');
169}
170
171
172static int testobjref (global_State *g, GCObject *f, GCObject *t) {
173 int r = testobjref1(g,f,t);
174if (!r) {
175printf("%d - ", g->gcstate);
176printobj(g, f);
177printf("\t-> ");
178printobj(g, t);
179printf("\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
191static 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*/
224static 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
248static 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
268static 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
280void 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*/
diff --git a/ltests.h b/ltests.h
index 2fc73fda..648b351f 100644
--- a/ltests.h
+++ b/ltests.h
@@ -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
45void luaC_checkall (lua_State *L);
46
45 47
46/* test for lock/unlock */ 48/* test for lock/unlock */
47extern int islocked; 49extern int islocked;
diff --git a/ltm.c b/ltm.c
index 230fbba6..389cd7c4 100644
--- a/ltm.c
+++ b/ltm.c
@@ -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
22const char *const luaT_typenames[] = { 22const 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