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 | */ |
