diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:54 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:54 -0300 |
| commit | 48a8d781020ec86e9870cdca2f5276b30cd20fa4 (patch) | |
| tree | 9db420ebe8846be2a604b052f3e3060840ca3770 | |
| parent | a4e1230f95223f2106cf0e118426ba91f1017d89 (diff) | |
| download | lua-48a8d781020ec86e9870cdca2f5276b30cd20fa4.tar.gz lua-48a8d781020ec86e9870cdca2f5276b30cd20fa4.tar.bz2 lua-48a8d781020ec86e9870cdca2f5276b30cd20fa4.zip | |
new tests to check memory consistency (for incremental GC)
| -rw-r--r-- | ltests.c | 202 | ||||
| -rw-r--r-- | ltests.h | 11 |
2 files changed, 139 insertions, 74 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.2 2004/02/16 19:09:52 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 | */ |
| @@ -36,12 +36,15 @@ | |||
| 36 | #ifdef LUA_DEBUG | 36 | #ifdef LUA_DEBUG |
| 37 | 37 | ||
| 38 | 38 | ||
| 39 | int Trick = 0; | ||
| 40 | |||
| 41 | |||
| 39 | static lua_State *lua_state = NULL; | 42 | static lua_State *lua_state = NULL; |
| 40 | 43 | ||
| 41 | int islocked = 0; | 44 | int islocked = 0; |
| 42 | 45 | ||
| 43 | 46 | ||
| 44 | #define func_at(L,k) (L->ci->base+(k) - 1) | 47 | #define obj_at(L,k) (L->ci->base+(k) - 1) |
| 45 | 48 | ||
| 46 | 49 | ||
| 47 | static void setnameval (lua_State *L, const char *name, int val) { | 50 | static void setnameval (lua_State *L, const char *name, int val) { |
| @@ -159,25 +162,24 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | |||
| 159 | 162 | ||
| 160 | 163 | ||
| 161 | static void printobj (global_State *g, GCObject *o) { | 164 | static void printobj (global_State *g, GCObject *o) { |
| 162 | int i = 0; | 165 | int i = 0; |
| 163 | GCObject *p; | 166 | GCObject *p; |
| 164 | for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++; | 167 | for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++; |
| 165 | if (p == NULL) i = -1; | 168 | if (p == NULL) i = -1; |
| 166 | printf("%d:%s(%p)-%c", | 169 | printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[o->gch.tt], (void *)o, |
| 167 | i, luaT_typenames[o->gch.tt], (void *)o, | 170 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->gch.marked); |
| 168 | isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g'); | ||
| 169 | } | 171 | } |
| 170 | 172 | ||
| 171 | 173 | ||
| 172 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | 174 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { |
| 173 | int r = testobjref1(g,f,t); | 175 | int r = testobjref1(g,f,t); |
| 174 | if (!r) { | 176 | if (!r) { |
| 175 | printf("%d - ", g->gcstate); | 177 | printf("%d(%02X) - ", g->gcstate, g->currentwhite); |
| 176 | printobj(g, f); | 178 | printobj(g, f); |
| 177 | printf("\t-> "); | 179 | printf("\t-> "); |
| 178 | printobj(g, t); | 180 | printobj(g, t); |
| 179 | printf("\n"); | 181 | printf("\n"); |
| 180 | } | 182 | } |
| 181 | return r; | 183 | return r; |
| 182 | } | 184 | } |
| 183 | 185 | ||
| @@ -258,8 +260,10 @@ static void checkclosure (global_State *g, Closure *cl) { | |||
| 258 | checkobjref(g, clgc, hvalue(&cl->l.g)); | 260 | checkobjref(g, clgc, hvalue(&cl->l.g)); |
| 259 | checkobjref(g, clgc, cl->l.p); | 261 | checkobjref(g, clgc, cl->l.p); |
| 260 | for (i=0; i<cl->l.nupvalues; i++) { | 262 | for (i=0; i<cl->l.nupvalues; i++) { |
| 261 | lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL); | 263 | if (cl->l.upvals[i]) { |
| 262 | checkobjref(g, clgc, cl->l.upvals[i]); | 264 | lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL); |
| 265 | checkobjref(g, clgc, cl->l.upvals[i]); | ||
| 266 | } | ||
| 263 | } | 267 | } |
| 264 | } | 268 | } |
| 265 | } | 269 | } |
| @@ -270,53 +274,74 @@ static void checkstack (global_State *g, lua_State *L1) { | |||
| 270 | CallInfo *ci; | 274 | CallInfo *ci; |
| 271 | lua_assert(!isdead(g, obj2gco(L1))); | 275 | lua_assert(!isdead(g, obj2gco(L1))); |
| 272 | checkliveness(g, gt(L1)); | 276 | checkliveness(g, gt(L1)); |
| 273 | for (ci = L1->base_ci; ci <= L1->ci; ci++) | 277 | if (L1->base_ci) { |
| 274 | lua_assert(ci->top <= L1->stack_last); | 278 | for (ci = L1->base_ci; ci <= L1->ci; ci++) |
| 275 | for (o = L1->stack; o < L1->top; o++) | 279 | lua_assert(ci->top <= L1->stack_last); |
| 276 | checkliveness(g, o); | 280 | } |
| 281 | else lua_assert(L1->size_ci == 0); | ||
| 282 | if (L1->stack) { | ||
| 283 | for (o = L1->stack; o < L1->top; o++) | ||
| 284 | checkliveness(g, o); | ||
| 285 | } | ||
| 286 | else lua_assert(L1->stacksize == 0); | ||
| 277 | } | 287 | } |
| 278 | 288 | ||
| 279 | 289 | ||
| 280 | void luaC_checkall (lua_State *L) { | 290 | static void checkobject (global_State *g, GCObject *o) { |
| 291 | if (isdead(g, o)) | ||
| 292 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | ||
| 293 | else { | ||
| 294 | if (g->gcstate == GCSfinalize) | ||
| 295 | lua_assert(iswhite(o)); | ||
| 296 | switch (o->gch.tt) { | ||
| 297 | case LUA_TUPVAL: { | ||
| 298 | UpVal *uv = gco2uv(o); | ||
| 299 | lua_assert(uv->v == &uv->value); /* must be closed */ | ||
| 300 | checkvalref(g, o, uv->v); | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | case LUA_TUSERDATA: { | ||
| 304 | Table *mt = gco2u(o)->metatable; | ||
| 305 | if (mt) checkobjref(g, o, mt); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | case LUA_TTABLE: { | ||
| 309 | checktable(g, gco2h(o)); | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | case LUA_TTHREAD: { | ||
| 313 | checkstack(g, gco2th(o)); | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | case LUA_TFUNCTION: { | ||
| 317 | checkclosure(g, gco2cl(o)); | ||
| 318 | break; | ||
| 319 | } | ||
| 320 | case LUA_TPROTO: { | ||
| 321 | checkproto(g, gco2p(o)); | ||
| 322 | break; | ||
| 323 | } | ||
| 324 | default: lua_assert(0); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 330 | int lua_checkmemory (lua_State *L) { | ||
| 281 | global_State *g = G(L); | 331 | global_State *g = G(L); |
| 282 | GCObject *o; | 332 | GCObject *o; |
| 283 | checkstack(g, g->mainthread); | 333 | checkstack(g, g->mainthread); |
| 284 | for (o = g->rootgc; o; o = o->gch.next) { | 334 | for (o = g->rootgc; o->gch.tt != LUA_TUSERDATA; o = o->gch.next) |
| 285 | if (isdead(g, o)) | 335 | checkobject(g, o); |
| 286 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | 336 | lua_assert(o == g->firstudata); |
| 287 | else { | 337 | for (; o->gch.tt != LUA_TTHREAD; o = o->gch.next) |
| 288 | switch (o->gch.tt) { | 338 | checkobject(g, o); |
| 289 | case LUA_TUPVAL: { | 339 | lua_assert(o == obj2gco(g->mainthread)); |
| 290 | UpVal *uv = gco2uv(o); | 340 | for (; o; o = o->gch.next) { |
| 291 | lua_assert(uv->v == &uv->value); /* must be closed */ | 341 | lua_assert(o->gch.tt == LUA_TTHREAD); |
| 292 | checkvalref(g, o, uv->v); | 342 | checkobject(g, o); |
| 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 | } | 343 | } |
| 344 | return 0; | ||
| 320 | } | 345 | } |
| 321 | 346 | ||
| 322 | /* }====================================================== */ | 347 | /* }====================================================== */ |
| @@ -369,7 +394,7 @@ static int listcode (lua_State *L) { | |||
| 369 | Proto *p; | 394 | Proto *p; |
| 370 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | 395 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
| 371 | 1, "Lua function expected"); | 396 | 1, "Lua function expected"); |
| 372 | p = clvalue(func_at(L, 1))->l.p; | 397 | p = clvalue(obj_at(L, 1))->l.p; |
| 373 | lua_newtable(L); | 398 | lua_newtable(L); |
| 374 | setnameval(L, "maxstack", p->maxstacksize); | 399 | setnameval(L, "maxstack", p->maxstacksize); |
| 375 | setnameval(L, "numparams", p->numparams); | 400 | setnameval(L, "numparams", p->numparams); |
| @@ -388,7 +413,7 @@ static int listk (lua_State *L) { | |||
| 388 | int i; | 413 | int i; |
| 389 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | 414 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
| 390 | 1, "Lua function expected"); | 415 | 1, "Lua function expected"); |
| 391 | p = clvalue(func_at(L, 1))->l.p; | 416 | p = clvalue(obj_at(L, 1))->l.p; |
| 392 | lua_createtable(L, p->sizek, 0); | 417 | lua_createtable(L, p->sizek, 0); |
| 393 | for (i=0; i<p->sizek; i++) { | 418 | for (i=0; i<p->sizek; i++) { |
| 394 | luaA_pushobject(L, p->k+i); | 419 | luaA_pushobject(L, p->k+i); |
| @@ -405,7 +430,7 @@ static int listlocals (lua_State *L) { | |||
| 405 | const char *name; | 430 | const char *name; |
| 406 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | 431 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), |
| 407 | 1, "Lua function expected"); | 432 | 1, "Lua function expected"); |
| 408 | p = clvalue(func_at(L, 1))->l.p; | 433 | p = clvalue(obj_at(L, 1))->l.p; |
| 409 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) | 434 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) |
| 410 | lua_pushstring(L, name); | 435 | lua_pushstring(L, name); |
| 411 | return i-1; | 436 | return i-1; |
| @@ -428,12 +453,6 @@ static int get_limits (lua_State *L) { | |||
| 428 | } | 453 | } |
| 429 | 454 | ||
| 430 | 455 | ||
| 431 | static int setgcthreshold (lua_State *L) { | ||
| 432 | lua_setgcthreshold(L, luaL_checkint(L, 1)); | ||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | |||
| 437 | static int mem_query (lua_State *L) { | 456 | static int mem_query (lua_State *L) { |
| 438 | if (lua_isnone(L, 1)) { | 457 | if (lua_isnone(L, 1)) { |
| 439 | lua_pushinteger(L, memcontrol.total); | 458 | lua_pushinteger(L, memcontrol.total); |
| @@ -448,16 +467,52 @@ static int mem_query (lua_State *L) { | |||
| 448 | } | 467 | } |
| 449 | 468 | ||
| 450 | 469 | ||
| 470 | static int settrick (lua_State *L) { | ||
| 471 | Trick = lua_tointeger(L, 1); | ||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | |||
| 476 | /*static int set_gcstate (lua_State *L) { | ||
| 477 | static const char *const state[] = {"propagate", "sweep", "finalize"}; | ||
| 478 | return 0; | ||
| 479 | }*/ | ||
| 480 | |||
| 481 | |||
| 482 | static int get_gccolor (lua_State *L) { | ||
| 483 | TValue *o; | ||
| 484 | luaL_checkany(L, 1); | ||
| 485 | o = obj_at(L, 1); | ||
| 486 | if (!iscollectable(o)) | ||
| 487 | lua_pushstring(L, "no collectable"); | ||
| 488 | else | ||
| 489 | lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : | ||
| 490 | isblack(gcvalue(o)) ? "black" : "grey"); | ||
| 491 | return 1; | ||
| 492 | } | ||
| 493 | |||
| 494 | |||
| 495 | static int gcstate (lua_State *L) { | ||
| 496 | switch(G(L)->gcstate) { | ||
| 497 | case GCSpropagate: lua_pushstring(L, "propagate"); break; | ||
| 498 | case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; | ||
| 499 | case GCSsweep: lua_pushstring(L, "sweep"); break; | ||
| 500 | case GCSfinalize: lua_pushstring(L, "finalize"); break; | ||
| 501 | } | ||
| 502 | return 1; | ||
| 503 | } | ||
| 504 | |||
| 505 | |||
| 451 | static int hash_query (lua_State *L) { | 506 | static int hash_query (lua_State *L) { |
| 452 | if (lua_isnone(L, 2)) { | 507 | if (lua_isnone(L, 2)) { |
| 453 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); | 508 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); |
| 454 | lua_pushinteger(L, tsvalue(func_at(L, 1))->hash); | 509 | lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash); |
| 455 | } | 510 | } |
| 456 | else { | 511 | else { |
| 457 | TValue *o = func_at(L, 1); | 512 | TValue *o = obj_at(L, 1); |
| 458 | Table *t; | 513 | Table *t; |
| 459 | luaL_checktype(L, 2, LUA_TTABLE); | 514 | luaL_checktype(L, 2, LUA_TTABLE); |
| 460 | t = hvalue(func_at(L, 2)); | 515 | t = hvalue(obj_at(L, 2)); |
| 461 | lua_pushinteger(L, luaH_mainposition(t, o) - t->node); | 516 | lua_pushinteger(L, luaH_mainposition(t, o) - t->node); |
| 462 | } | 517 | } |
| 463 | return 1; | 518 | return 1; |
| @@ -479,7 +534,7 @@ static int table_query (lua_State *L) { | |||
| 479 | const Table *t; | 534 | const Table *t; |
| 480 | int i = luaL_optint(L, 2, -1); | 535 | int i = luaL_optint(L, 2, -1); |
| 481 | luaL_checktype(L, 1, LUA_TTABLE); | 536 | luaL_checktype(L, 1, LUA_TTABLE); |
| 482 | t = hvalue(func_at(L, 1)); | 537 | t = hvalue(obj_at(L, 1)); |
| 483 | if (i == -1) { | 538 | if (i == -1) { |
| 484 | lua_pushinteger(L, t->sizearray); | 539 | lua_pushinteger(L, t->sizearray); |
| 485 | lua_pushinteger(L, sizenode(t)); | 540 | lua_pushinteger(L, sizenode(t)); |
| @@ -979,6 +1034,10 @@ static const struct luaL_reg tests_funcs[] = { | |||
| 979 | {"querytab", table_query}, | 1034 | {"querytab", table_query}, |
| 980 | {"doit", test_do}, | 1035 | {"doit", test_do}, |
| 981 | {"testC", testC}, | 1036 | {"testC", testC}, |
| 1037 | {"checkmemory", lua_checkmemory}, | ||
| 1038 | {"gccolor", get_gccolor}, | ||
| 1039 | {"gcstate", gcstate}, | ||
| 1040 | {"trick", settrick}, | ||
| 982 | {"ref", tref}, | 1041 | {"ref", tref}, |
| 983 | {"getref", getref}, | 1042 | {"getref", getref}, |
| 984 | {"unref", unref}, | 1043 | {"unref", unref}, |
| @@ -995,7 +1054,6 @@ static const struct luaL_reg tests_funcs[] = { | |||
| 995 | {"doremote", doremote}, | 1054 | {"doremote", doremote}, |
| 996 | {"log2", log2_aux}, | 1055 | {"log2", log2_aux}, |
| 997 | {"int2fb", int2fb_aux}, | 1056 | {"int2fb", int2fb_aux}, |
| 998 | {"setgcthreshold", setgcthreshold}, | ||
| 999 | {"totalmem", mem_query}, | 1057 | {"totalmem", mem_query}, |
| 1000 | {"resume", coresume}, | 1058 | {"resume", coresume}, |
| 1001 | {"setyhook", setyhook}, | 1059 | {"setyhook", setyhook}, |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: ltests.h,v 2.2 2004/02/16 19:09:52 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 | */ |
| @@ -35,6 +35,13 @@ typedef struct Memcontrol { | |||
| 35 | 35 | ||
| 36 | extern Memcontrol memcontrol; | 36 | extern Memcontrol memcontrol; |
| 37 | 37 | ||
| 38 | |||
| 39 | /* | ||
| 40 | ** generic variable for debug tricks | ||
| 41 | */ | ||
| 42 | extern int Trick; | ||
| 43 | |||
| 44 | |||
| 38 | void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); | 45 | void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); |
| 39 | 46 | ||
| 40 | #ifdef lua_c | 47 | #ifdef lua_c |
| @@ -42,7 +49,7 @@ void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); | |||
| 42 | #endif | 49 | #endif |
| 43 | 50 | ||
| 44 | 51 | ||
| 45 | void luaC_checkall (lua_State *L); | 52 | int lua_checkmemory (lua_State *L); |
| 46 | 53 | ||
| 47 | 54 | ||
| 48 | /* test for lock/unlock */ | 55 | /* test for lock/unlock */ |
