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 /ltests.c | |
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
Diffstat (limited to 'ltests.c')
-rw-r--r-- | ltests.c | 184 |
1 files changed, 183 insertions, 1 deletions
@@ -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 | */ |