diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-09-19 00:43:31 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-09-19 00:43:31 +0200 |
| commit | 402b97fbdf4857adc5aa80f85fa5e59148e126b7 (patch) | |
| tree | 666e08bf605b3e09064cb965c3596684e3c0da5e /zig-lua/lua-5.4.7/ltests.c | |
| parent | 2e2da1fd114edb932954a108ddb6f7359dbb868a (diff) | |
| download | probe-402b97fbdf4857adc5aa80f85fa5e59148e126b7.tar.gz | |
Added debuggers to Nix shell
Diffstat (limited to 'zig-lua/lua-5.4.7/ltests.c')
| -rw-r--r-- | zig-lua/lua-5.4.7/ltests.c | 1983 |
1 files changed, 1983 insertions, 0 deletions
diff --git a/zig-lua/lua-5.4.7/ltests.c b/zig-lua/lua-5.4.7/ltests.c new file mode 100644 index 0000000..a27cdb0 --- /dev/null +++ b/zig-lua/lua-5.4.7/ltests.c | |||
| @@ -0,0 +1,1983 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: ltests.c $ | ||
| 3 | ** Internal Module for Debugging of the Lua Implementation | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define ltests_c | ||
| 8 | #define LUA_CORE | ||
| 9 | |||
| 10 | #include "lprefix.h" | ||
| 11 | |||
| 12 | |||
| 13 | #include <limits.h> | ||
| 14 | #include <setjmp.h> | ||
| 15 | #include <stdio.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | #include <string.h> | ||
| 18 | |||
| 19 | #include "lua.h" | ||
| 20 | |||
| 21 | #include "lapi.h" | ||
| 22 | #include "lauxlib.h" | ||
| 23 | #include "lcode.h" | ||
| 24 | #include "lctype.h" | ||
| 25 | #include "ldebug.h" | ||
| 26 | #include "ldo.h" | ||
| 27 | #include "lfunc.h" | ||
| 28 | #include "lmem.h" | ||
| 29 | #include "lopcodes.h" | ||
| 30 | #include "lopnames.h" | ||
| 31 | #include "lstate.h" | ||
| 32 | #include "lstring.h" | ||
| 33 | #include "ltable.h" | ||
| 34 | #include "lualib.h" | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* | ||
| 39 | ** The whole module only makes sense with LUA_DEBUG on | ||
| 40 | */ | ||
| 41 | #if defined(LUA_DEBUG) | ||
| 42 | |||
| 43 | |||
| 44 | void *l_Trick = 0; | ||
| 45 | |||
| 46 | |||
| 47 | #define obj_at(L,k) s2v(L->ci->func.p + (k)) | ||
| 48 | |||
| 49 | |||
| 50 | static int runC (lua_State *L, lua_State *L1, const char *pc); | ||
| 51 | |||
| 52 | |||
| 53 | static void setnameval (lua_State *L, const char *name, int val) { | ||
| 54 | lua_pushinteger(L, val); | ||
| 55 | lua_setfield(L, -2, name); | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | static void pushobject (lua_State *L, const TValue *o) { | ||
| 60 | setobj2s(L, L->top.p, o); | ||
| 61 | api_incr_top(L); | ||
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | static void badexit (const char *fmt, const char *s1, const char *s2) { | ||
| 66 | fprintf(stderr, fmt, s1); | ||
| 67 | if (s2) | ||
| 68 | fprintf(stderr, "extra info: %s\n", s2); | ||
| 69 | /* avoid assertion failures when exiting */ | ||
| 70 | l_memcontrol.numblocks = l_memcontrol.total = 0; | ||
| 71 | exit(EXIT_FAILURE); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | static int tpanic (lua_State *L) { | ||
| 76 | const char *msg = (lua_type(L, -1) == LUA_TSTRING) | ||
| 77 | ? lua_tostring(L, -1) | ||
| 78 | : "error object is not a string"; | ||
| 79 | return (badexit("PANIC: unprotected error in call to Lua API (%s)\n", | ||
| 80 | msg, NULL), | ||
| 81 | 0); /* do not return to Lua */ | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | /* | ||
| 86 | ** Warning function for tests. First, it concatenates all parts of | ||
| 87 | ** a warning in buffer 'buff'. Then, it has three modes: | ||
| 88 | ** - 0.normal: messages starting with '#' are shown on standard output; | ||
| 89 | ** - other messages abort the tests (they represent real warning | ||
| 90 | ** conditions; the standard tests should not generate these conditions | ||
| 91 | ** unexpectedly); | ||
| 92 | ** - 1.allow: all messages are shown; | ||
| 93 | ** - 2.store: all warnings go to the global '_WARN'; | ||
| 94 | */ | ||
| 95 | static void warnf (void *ud, const char *msg, int tocont) { | ||
| 96 | lua_State *L = cast(lua_State *, ud); | ||
| 97 | static char buff[200] = ""; /* should be enough for tests... */ | ||
| 98 | static int onoff = 0; | ||
| 99 | static int mode = 0; /* start in normal mode */ | ||
| 100 | static int lasttocont = 0; | ||
| 101 | if (!lasttocont && !tocont && *msg == '@') { /* control message? */ | ||
| 102 | if (buff[0] != '\0') | ||
| 103 | badexit("Control warning during warning: %s\naborting...\n", msg, buff); | ||
| 104 | if (strcmp(msg, "@off") == 0) | ||
| 105 | onoff = 0; | ||
| 106 | else if (strcmp(msg, "@on") == 0) | ||
| 107 | onoff = 1; | ||
| 108 | else if (strcmp(msg, "@normal") == 0) | ||
| 109 | mode = 0; | ||
| 110 | else if (strcmp(msg, "@allow") == 0) | ||
| 111 | mode = 1; | ||
| 112 | else if (strcmp(msg, "@store") == 0) | ||
| 113 | mode = 2; | ||
| 114 | else | ||
| 115 | badexit("Invalid control warning in test mode: %s\naborting...\n", | ||
| 116 | msg, NULL); | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | lasttocont = tocont; | ||
| 120 | if (strlen(msg) >= sizeof(buff) - strlen(buff)) | ||
| 121 | badexit("warnf-buffer overflow (%s)\n", msg, buff); | ||
| 122 | strcat(buff, msg); /* add new message to current warning */ | ||
| 123 | if (!tocont) { /* message finished? */ | ||
| 124 | lua_unlock(L); | ||
| 125 | luaL_checkstack(L, 1, "warn stack space"); | ||
| 126 | lua_getglobal(L, "_WARN"); | ||
| 127 | if (!lua_toboolean(L, -1)) | ||
| 128 | lua_pop(L, 1); /* ok, no previous unexpected warning */ | ||
| 129 | else { | ||
| 130 | badexit("Unhandled warning in store mode: %s\naborting...\n", | ||
| 131 | lua_tostring(L, -1), buff); | ||
| 132 | } | ||
| 133 | lua_lock(L); | ||
| 134 | switch (mode) { | ||
| 135 | case 0: { /* normal */ | ||
| 136 | if (buff[0] != '#' && onoff) /* unexpected warning? */ | ||
| 137 | badexit("Unexpected warning in test mode: %s\naborting...\n", | ||
| 138 | buff, NULL); | ||
| 139 | } /* FALLTHROUGH */ | ||
| 140 | case 1: { /* allow */ | ||
| 141 | if (onoff) | ||
| 142 | fprintf(stderr, "Lua warning: %s\n", buff); /* print warning */ | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | case 2: { /* store */ | ||
| 146 | lua_unlock(L); | ||
| 147 | luaL_checkstack(L, 1, "warn stack space"); | ||
| 148 | lua_pushstring(L, buff); | ||
| 149 | lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */ | ||
| 150 | lua_lock(L); | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | buff[0] = '\0'; /* prepare buffer for next warning */ | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | |||
| 159 | /* | ||
| 160 | ** {====================================================================== | ||
| 161 | ** Controlled version for realloc. | ||
| 162 | ** ======================================================================= | ||
| 163 | */ | ||
| 164 | |||
| 165 | #define MARK 0x55 /* 01010101 (a nice pattern) */ | ||
| 166 | |||
| 167 | typedef union Header { | ||
| 168 | LUAI_MAXALIGN; | ||
| 169 | struct { | ||
| 170 | size_t size; | ||
| 171 | int type; | ||
| 172 | } d; | ||
| 173 | } Header; | ||
| 174 | |||
| 175 | |||
| 176 | #if !defined(EXTERNMEMCHECK) | ||
| 177 | |||
| 178 | /* full memory check */ | ||
| 179 | #define MARKSIZE 16 /* size of marks after each block */ | ||
| 180 | #define fillmem(mem,size) memset(mem, -MARK, size) | ||
| 181 | |||
| 182 | #else | ||
| 183 | |||
| 184 | /* external memory check: don't do it twice */ | ||
| 185 | #define MARKSIZE 0 | ||
| 186 | #define fillmem(mem,size) /* empty */ | ||
| 187 | |||
| 188 | #endif | ||
| 189 | |||
| 190 | |||
| 191 | Memcontrol l_memcontrol = | ||
| 192 | {0, 0UL, 0UL, 0UL, 0UL, (~0UL), | ||
| 193 | {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}}; | ||
| 194 | |||
| 195 | |||
| 196 | static void freeblock (Memcontrol *mc, Header *block) { | ||
| 197 | if (block) { | ||
| 198 | size_t size = block->d.size; | ||
| 199 | int i; | ||
| 200 | for (i = 0; i < MARKSIZE; i++) /* check marks after block */ | ||
| 201 | lua_assert(*(cast_charp(block + 1) + size + i) == MARK); | ||
| 202 | mc->objcount[block->d.type]--; | ||
| 203 | fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ | ||
| 204 | free(block); /* actually free block */ | ||
| 205 | mc->numblocks--; /* update counts */ | ||
| 206 | mc->total -= size; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { | ||
| 212 | Memcontrol *mc = cast(Memcontrol *, ud); | ||
| 213 | Header *block = cast(Header *, b); | ||
| 214 | int type; | ||
| 215 | if (mc->memlimit == 0) { /* first time? */ | ||
| 216 | char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ | ||
| 217 | mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; | ||
| 218 | } | ||
| 219 | if (block == NULL) { | ||
| 220 | type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; | ||
| 221 | oldsize = 0; | ||
| 222 | } | ||
| 223 | else { | ||
| 224 | block--; /* go to real header */ | ||
| 225 | type = block->d.type; | ||
| 226 | lua_assert(oldsize == block->d.size); | ||
| 227 | } | ||
| 228 | if (size == 0) { | ||
| 229 | freeblock(mc, block); | ||
| 230 | return NULL; | ||
| 231 | } | ||
| 232 | if (mc->failnext) { | ||
| 233 | mc->failnext = 0; | ||
| 234 | return NULL; /* fake a single memory allocation error */ | ||
| 235 | } | ||
| 236 | if (mc->countlimit != ~0UL && size != oldsize) { /* count limit in use? */ | ||
| 237 | if (mc->countlimit == 0) | ||
| 238 | return NULL; /* fake a memory allocation error */ | ||
| 239 | mc->countlimit--; | ||
| 240 | } | ||
| 241 | if (size > oldsize && mc->total+size-oldsize > mc->memlimit) | ||
| 242 | return NULL; /* fake a memory allocation error */ | ||
| 243 | else { | ||
| 244 | Header *newblock; | ||
| 245 | int i; | ||
| 246 | size_t commonsize = (oldsize < size) ? oldsize : size; | ||
| 247 | size_t realsize = sizeof(Header) + size + MARKSIZE; | ||
| 248 | if (realsize < size) return NULL; /* arithmetic overflow! */ | ||
| 249 | newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ | ||
| 250 | if (newblock == NULL) | ||
| 251 | return NULL; /* really out of memory? */ | ||
| 252 | if (block) { | ||
| 253 | memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ | ||
| 254 | freeblock(mc, block); /* erase (and check) old copy */ | ||
| 255 | } | ||
| 256 | /* initialize new part of the block with something weird */ | ||
| 257 | fillmem(cast_charp(newblock + 1) + commonsize, size - commonsize); | ||
| 258 | /* initialize marks after block */ | ||
| 259 | for (i = 0; i < MARKSIZE; i++) | ||
| 260 | *(cast_charp(newblock + 1) + size + i) = MARK; | ||
| 261 | newblock->d.size = size; | ||
| 262 | newblock->d.type = type; | ||
| 263 | mc->total += size; | ||
| 264 | if (mc->total > mc->maxmem) | ||
| 265 | mc->maxmem = mc->total; | ||
| 266 | mc->numblocks++; | ||
| 267 | mc->objcount[type]++; | ||
| 268 | return newblock + 1; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | |||
| 273 | /* }====================================================================== */ | ||
| 274 | |||
| 275 | |||
| 276 | |||
| 277 | /* | ||
| 278 | ** {===================================================================== | ||
| 279 | ** Functions to check memory consistency. | ||
| 280 | ** Most of these checks are done through asserts, so this code does | ||
| 281 | ** not make sense with asserts off. For this reason, it uses 'assert' | ||
| 282 | ** directly, instead of 'lua_assert'. | ||
| 283 | ** ====================================================================== | ||
| 284 | */ | ||
| 285 | |||
| 286 | #include <assert.h> | ||
| 287 | |||
| 288 | /* | ||
| 289 | ** Check GC invariants. For incremental mode, a black object cannot | ||
| 290 | ** point to a white one. For generational mode, really old objects | ||
| 291 | ** cannot point to young objects. Both old1 and touched2 objects | ||
| 292 | ** cannot point to new objects (but can point to survivals). | ||
| 293 | ** (Threads and open upvalues, despite being marked "really old", | ||
| 294 | ** continue to be visited in all collections, and therefore can point to | ||
| 295 | ** new objects. They, and only they, are old but gray.) | ||
| 296 | */ | ||
| 297 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | ||
| 298 | if (isdead(g,t)) return 0; | ||
| 299 | if (issweepphase(g)) | ||
| 300 | return 1; /* no invariants */ | ||
| 301 | else if (g->gckind == KGC_INC) | ||
| 302 | return !(isblack(f) && iswhite(t)); /* basic incremental invariant */ | ||
| 303 | else { /* generational mode */ | ||
| 304 | if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) | ||
| 305 | return 0; | ||
| 306 | if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) && | ||
| 307 | getage(t) == G_NEW) | ||
| 308 | return 0; | ||
| 309 | return 1; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | static void printobj (global_State *g, GCObject *o) { | ||
| 315 | printf("||%s(%p)-%c%c(%02X)||", | ||
| 316 | ttypename(novariant(o->tt)), (void *)o, | ||
| 317 | isdead(g,o) ? 'd' : isblack(o) ? 'b' : iswhite(o) ? 'w' : 'g', | ||
| 318 | "ns01oTt"[getage(o)], o->marked); | ||
| 319 | if (o->tt == LUA_VSHRSTR || o->tt == LUA_VLNGSTR) | ||
| 320 | printf(" '%s'", getstr(gco2ts(o))); | ||
| 321 | } | ||
| 322 | |||
| 323 | |||
| 324 | void lua_printobj (lua_State *L, struct GCObject *o) { | ||
| 325 | printobj(G(L), o); | ||
| 326 | } | ||
| 327 | |||
| 328 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | ||
| 329 | int r1 = testobjref1(g, f, t); | ||
| 330 | if (!r1) { | ||
| 331 | printf("%d(%02X) - ", g->gcstate, g->currentwhite); | ||
| 332 | printobj(g, f); | ||
| 333 | printf(" -> "); | ||
| 334 | printobj(g, t); | ||
| 335 | printf("\n"); | ||
| 336 | } | ||
| 337 | return r1; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | static void checkobjref (global_State *g, GCObject *f, GCObject *t) { | ||
| 342 | assert(testobjref(g, f, t)); | ||
| 343 | } | ||
| 344 | |||
| 345 | |||
| 346 | /* | ||
| 347 | ** Version where 't' can be NULL. In that case, it should not apply the | ||
| 348 | ** macro 'obj2gco' over the object. ('t' may have several types, so this | ||
| 349 | ** definition must be a macro.) Most checks need this version, because | ||
| 350 | ** the check may run while an object is still being created. | ||
| 351 | */ | ||
| 352 | #define checkobjrefN(g,f,t) { if (t) checkobjref(g,f,obj2gco(t)); } | ||
| 353 | |||
| 354 | |||
| 355 | static void checkvalref (global_State *g, GCObject *f, const TValue *t) { | ||
| 356 | assert(!iscollectable(t) || (righttt(t) && testobjref(g, f, gcvalue(t)))); | ||
| 357 | } | ||
| 358 | |||
| 359 | |||
| 360 | static void checktable (global_State *g, Table *h) { | ||
| 361 | unsigned int i; | ||
| 362 | unsigned int asize = luaH_realasize(h); | ||
| 363 | Node *n, *limit = gnode(h, sizenode(h)); | ||
| 364 | GCObject *hgc = obj2gco(h); | ||
| 365 | checkobjrefN(g, hgc, h->metatable); | ||
| 366 | for (i = 0; i < asize; i++) | ||
| 367 | checkvalref(g, hgc, &h->array[i]); | ||
| 368 | for (n = gnode(h, 0); n < limit; n++) { | ||
| 369 | if (!isempty(gval(n))) { | ||
| 370 | TValue k; | ||
| 371 | getnodekey(g->mainthread, &k, n); | ||
| 372 | assert(!keyisnil(n)); | ||
| 373 | checkvalref(g, hgc, &k); | ||
| 374 | checkvalref(g, hgc, gval(n)); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | |||
| 380 | static void checkudata (global_State *g, Udata *u) { | ||
| 381 | int i; | ||
| 382 | GCObject *hgc = obj2gco(u); | ||
| 383 | checkobjrefN(g, hgc, u->metatable); | ||
| 384 | for (i = 0; i < u->nuvalue; i++) | ||
| 385 | checkvalref(g, hgc, &u->uv[i].uv); | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | static void checkproto (global_State *g, Proto *f) { | ||
| 390 | int i; | ||
| 391 | GCObject *fgc = obj2gco(f); | ||
| 392 | checkobjrefN(g, fgc, f->source); | ||
| 393 | for (i=0; i<f->sizek; i++) { | ||
| 394 | if (iscollectable(f->k + i)) | ||
| 395 | checkobjref(g, fgc, gcvalue(f->k + i)); | ||
| 396 | } | ||
| 397 | for (i=0; i<f->sizeupvalues; i++) | ||
| 398 | checkobjrefN(g, fgc, f->upvalues[i].name); | ||
| 399 | for (i=0; i<f->sizep; i++) | ||
| 400 | checkobjrefN(g, fgc, f->p[i]); | ||
| 401 | for (i=0; i<f->sizelocvars; i++) | ||
| 402 | checkobjrefN(g, fgc, f->locvars[i].varname); | ||
| 403 | } | ||
| 404 | |||
| 405 | |||
| 406 | static void checkCclosure (global_State *g, CClosure *cl) { | ||
| 407 | GCObject *clgc = obj2gco(cl); | ||
| 408 | int i; | ||
| 409 | for (i = 0; i < cl->nupvalues; i++) | ||
| 410 | checkvalref(g, clgc, &cl->upvalue[i]); | ||
| 411 | } | ||
| 412 | |||
| 413 | |||
| 414 | static void checkLclosure (global_State *g, LClosure *cl) { | ||
| 415 | GCObject *clgc = obj2gco(cl); | ||
| 416 | int i; | ||
| 417 | checkobjrefN(g, clgc, cl->p); | ||
| 418 | for (i=0; i<cl->nupvalues; i++) { | ||
| 419 | UpVal *uv = cl->upvals[i]; | ||
| 420 | if (uv) { | ||
| 421 | checkobjrefN(g, clgc, uv); | ||
| 422 | if (!upisopen(uv)) | ||
| 423 | checkvalref(g, obj2gco(uv), uv->v.p); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | |||
| 429 | static int lua_checkpc (CallInfo *ci) { | ||
| 430 | if (!isLua(ci)) return 1; | ||
| 431 | else { | ||
| 432 | StkId f = ci->func.p; | ||
| 433 | Proto *p = clLvalue(s2v(f))->p; | ||
| 434 | return p->code <= ci->u.l.savedpc && | ||
| 435 | ci->u.l.savedpc <= p->code + p->sizecode; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | |||
| 440 | static void checkstack (global_State *g, lua_State *L1) { | ||
| 441 | StkId o; | ||
| 442 | CallInfo *ci; | ||
| 443 | UpVal *uv; | ||
| 444 | assert(!isdead(g, L1)); | ||
| 445 | if (L1->stack.p == NULL) { /* incomplete thread? */ | ||
| 446 | assert(L1->openupval == NULL && L1->ci == NULL); | ||
| 447 | return; | ||
| 448 | } | ||
| 449 | for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) | ||
| 450 | assert(upisopen(uv)); /* must be open */ | ||
| 451 | assert(L1->top.p <= L1->stack_last.p); | ||
| 452 | assert(L1->tbclist.p <= L1->top.p); | ||
| 453 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { | ||
| 454 | assert(ci->top.p <= L1->stack_last.p); | ||
| 455 | assert(lua_checkpc(ci)); | ||
| 456 | } | ||
| 457 | for (o = L1->stack.p; o < L1->stack_last.p; o++) | ||
| 458 | checkliveness(L1, s2v(o)); /* entire stack must have valid values */ | ||
| 459 | } | ||
| 460 | |||
| 461 | |||
| 462 | static void checkrefs (global_State *g, GCObject *o) { | ||
| 463 | switch (o->tt) { | ||
| 464 | case LUA_VUSERDATA: { | ||
| 465 | checkudata(g, gco2u(o)); | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | case LUA_VUPVAL: { | ||
| 469 | checkvalref(g, o, gco2upv(o)->v.p); | ||
| 470 | break; | ||
| 471 | } | ||
| 472 | case LUA_VTABLE: { | ||
| 473 | checktable(g, gco2t(o)); | ||
| 474 | break; | ||
| 475 | } | ||
| 476 | case LUA_VTHREAD: { | ||
| 477 | checkstack(g, gco2th(o)); | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | case LUA_VLCL: { | ||
| 481 | checkLclosure(g, gco2lcl(o)); | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | case LUA_VCCL: { | ||
| 485 | checkCclosure(g, gco2ccl(o)); | ||
| 486 | break; | ||
| 487 | } | ||
| 488 | case LUA_VPROTO: { | ||
| 489 | checkproto(g, gco2p(o)); | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | case LUA_VSHRSTR: | ||
| 493 | case LUA_VLNGSTR: { | ||
| 494 | assert(!isgray(o)); /* strings are never gray */ | ||
| 495 | break; | ||
| 496 | } | ||
| 497 | default: assert(0); | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | |||
| 502 | /* | ||
| 503 | ** Check consistency of an object: | ||
| 504 | ** - Dead objects can only happen in the 'allgc' list during a sweep | ||
| 505 | ** phase (controlled by the caller through 'maybedead'). | ||
| 506 | ** - During pause, all objects must be white. | ||
| 507 | ** - In generational mode: | ||
| 508 | ** * objects must be old enough for their lists ('listage'). | ||
| 509 | ** * old objects cannot be white. | ||
| 510 | ** * old objects must be black, except for 'touched1', 'old0', | ||
| 511 | ** threads, and open upvalues. | ||
| 512 | */ | ||
| 513 | static void checkobject (global_State *g, GCObject *o, int maybedead, | ||
| 514 | int listage) { | ||
| 515 | if (isdead(g, o)) | ||
| 516 | assert(maybedead); | ||
| 517 | else { | ||
| 518 | assert(g->gcstate != GCSpause || iswhite(o)); | ||
| 519 | if (g->gckind == KGC_GEN) { /* generational mode? */ | ||
| 520 | assert(getage(o) >= listage); | ||
| 521 | assert(!iswhite(o) || !isold(o)); | ||
| 522 | if (isold(o)) { | ||
| 523 | assert(isblack(o) || | ||
| 524 | getage(o) == G_TOUCHED1 || | ||
| 525 | getage(o) == G_OLD0 || | ||
| 526 | o->tt == LUA_VTHREAD || | ||
| 527 | (o->tt == LUA_VUPVAL && upisopen(gco2upv(o)))); | ||
| 528 | } | ||
| 529 | } | ||
| 530 | checkrefs(g, o); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | |||
| 535 | static lu_mem checkgraylist (global_State *g, GCObject *o) { | ||
| 536 | int total = 0; /* count number of elements in the list */ | ||
| 537 | cast_void(g); /* better to keep it if we need to print an object */ | ||
| 538 | while (o) { | ||
| 539 | assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); | ||
| 540 | assert(!testbit(o->marked, TESTBIT)); | ||
| 541 | if (keepinvariant(g)) | ||
| 542 | l_setbit(o->marked, TESTBIT); /* mark that object is in a gray list */ | ||
| 543 | total++; | ||
| 544 | switch (o->tt) { | ||
| 545 | case LUA_VTABLE: o = gco2t(o)->gclist; break; | ||
| 546 | case LUA_VLCL: o = gco2lcl(o)->gclist; break; | ||
| 547 | case LUA_VCCL: o = gco2ccl(o)->gclist; break; | ||
| 548 | case LUA_VTHREAD: o = gco2th(o)->gclist; break; | ||
| 549 | case LUA_VPROTO: o = gco2p(o)->gclist; break; | ||
| 550 | case LUA_VUSERDATA: | ||
| 551 | assert(gco2u(o)->nuvalue > 0); | ||
| 552 | o = gco2u(o)->gclist; | ||
| 553 | break; | ||
| 554 | default: assert(0); /* other objects cannot be in a gray list */ | ||
| 555 | } | ||
| 556 | } | ||
| 557 | return total; | ||
| 558 | } | ||
| 559 | |||
| 560 | |||
| 561 | /* | ||
| 562 | ** Check objects in gray lists. | ||
| 563 | */ | ||
| 564 | static lu_mem checkgrays (global_State *g) { | ||
| 565 | int total = 0; /* count number of elements in all lists */ | ||
| 566 | if (!keepinvariant(g)) return total; | ||
| 567 | total += checkgraylist(g, g->gray); | ||
| 568 | total += checkgraylist(g, g->grayagain); | ||
| 569 | total += checkgraylist(g, g->weak); | ||
| 570 | total += checkgraylist(g, g->allweak); | ||
| 571 | total += checkgraylist(g, g->ephemeron); | ||
| 572 | return total; | ||
| 573 | } | ||
| 574 | |||
| 575 | |||
| 576 | /* | ||
| 577 | ** Check whether 'o' should be in a gray list. If so, increment | ||
| 578 | ** 'count' and check its TESTBIT. (It must have been previously set by | ||
| 579 | ** 'checkgraylist'.) | ||
| 580 | */ | ||
| 581 | static void incifingray (global_State *g, GCObject *o, lu_mem *count) { | ||
| 582 | if (!keepinvariant(g)) | ||
| 583 | return; /* gray lists not being kept in these phases */ | ||
| 584 | if (o->tt == LUA_VUPVAL) { | ||
| 585 | /* only open upvalues can be gray */ | ||
| 586 | assert(!isgray(o) || upisopen(gco2upv(o))); | ||
| 587 | return; /* upvalues are never in gray lists */ | ||
| 588 | } | ||
| 589 | /* these are the ones that must be in gray lists */ | ||
| 590 | if (isgray(o) || getage(o) == G_TOUCHED2) { | ||
| 591 | (*count)++; | ||
| 592 | assert(testbit(o->marked, TESTBIT)); | ||
| 593 | resetbit(o->marked, TESTBIT); /* prepare for next cycle */ | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | |||
| 598 | static lu_mem checklist (global_State *g, int maybedead, int tof, | ||
| 599 | GCObject *newl, GCObject *survival, GCObject *old, GCObject *reallyold) { | ||
| 600 | GCObject *o; | ||
| 601 | lu_mem total = 0; /* number of object that should be in gray lists */ | ||
| 602 | for (o = newl; o != survival; o = o->next) { | ||
| 603 | checkobject(g, o, maybedead, G_NEW); | ||
| 604 | incifingray(g, o, &total); | ||
| 605 | assert(!tof == !tofinalize(o)); | ||
| 606 | } | ||
| 607 | for (o = survival; o != old; o = o->next) { | ||
| 608 | checkobject(g, o, 0, G_SURVIVAL); | ||
| 609 | incifingray(g, o, &total); | ||
| 610 | assert(!tof == !tofinalize(o)); | ||
| 611 | } | ||
| 612 | for (o = old; o != reallyold; o = o->next) { | ||
| 613 | checkobject(g, o, 0, G_OLD1); | ||
| 614 | incifingray(g, o, &total); | ||
| 615 | assert(!tof == !tofinalize(o)); | ||
| 616 | } | ||
| 617 | for (o = reallyold; o != NULL; o = o->next) { | ||
| 618 | checkobject(g, o, 0, G_OLD); | ||
| 619 | incifingray(g, o, &total); | ||
| 620 | assert(!tof == !tofinalize(o)); | ||
| 621 | } | ||
| 622 | return total; | ||
| 623 | } | ||
| 624 | |||
| 625 | |||
| 626 | int lua_checkmemory (lua_State *L) { | ||
| 627 | global_State *g = G(L); | ||
| 628 | GCObject *o; | ||
| 629 | int maybedead; | ||
| 630 | lu_mem totalin; /* total of objects that are in gray lists */ | ||
| 631 | lu_mem totalshould; /* total of objects that should be in gray lists */ | ||
| 632 | if (keepinvariant(g)) { | ||
| 633 | assert(!iswhite(g->mainthread)); | ||
| 634 | assert(!iswhite(gcvalue(&g->l_registry))); | ||
| 635 | } | ||
| 636 | assert(!isdead(g, gcvalue(&g->l_registry))); | ||
| 637 | assert(g->sweepgc == NULL || issweepphase(g)); | ||
| 638 | totalin = checkgrays(g); | ||
| 639 | |||
| 640 | /* check 'fixedgc' list */ | ||
| 641 | for (o = g->fixedgc; o != NULL; o = o->next) { | ||
| 642 | assert(o->tt == LUA_VSHRSTR && isgray(o) && getage(o) == G_OLD); | ||
| 643 | } | ||
| 644 | |||
| 645 | /* check 'allgc' list */ | ||
| 646 | maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSswpallgc); | ||
| 647 | totalshould = checklist(g, maybedead, 0, g->allgc, | ||
| 648 | g->survival, g->old1, g->reallyold); | ||
| 649 | |||
| 650 | /* check 'finobj' list */ | ||
| 651 | totalshould += checklist(g, 0, 1, g->finobj, | ||
| 652 | g->finobjsur, g->finobjold1, g->finobjrold); | ||
| 653 | |||
| 654 | /* check 'tobefnz' list */ | ||
| 655 | for (o = g->tobefnz; o != NULL; o = o->next) { | ||
| 656 | checkobject(g, o, 0, G_NEW); | ||
| 657 | incifingray(g, o, &totalshould); | ||
| 658 | assert(tofinalize(o)); | ||
| 659 | assert(o->tt == LUA_VUSERDATA || o->tt == LUA_VTABLE); | ||
| 660 | } | ||
| 661 | if (keepinvariant(g)) | ||
| 662 | assert(totalin == totalshould); | ||
| 663 | return 0; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* }====================================================== */ | ||
| 667 | |||
| 668 | |||
| 669 | |||
| 670 | /* | ||
| 671 | ** {====================================================== | ||
| 672 | ** Disassembler | ||
| 673 | ** ======================================================= | ||
| 674 | */ | ||
| 675 | |||
| 676 | |||
| 677 | static char *buildop (Proto *p, int pc, char *buff) { | ||
| 678 | char *obuff = buff; | ||
| 679 | Instruction i = p->code[pc]; | ||
| 680 | OpCode o = GET_OPCODE(i); | ||
| 681 | const char *name = opnames[o]; | ||
| 682 | int line = luaG_getfuncline(p, pc); | ||
| 683 | int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0; | ||
| 684 | if (lineinfo == ABSLINEINFO) | ||
| 685 | buff += sprintf(buff, "(__"); | ||
| 686 | else | ||
| 687 | buff += sprintf(buff, "(%2d", lineinfo); | ||
| 688 | buff += sprintf(buff, " - %4d) %4d - ", line, pc); | ||
| 689 | switch (getOpMode(o)) { | ||
| 690 | case iABC: | ||
| 691 | sprintf(buff, "%-12s%4d %4d %4d%s", name, | ||
| 692 | GETARG_A(i), GETARG_B(i), GETARG_C(i), | ||
| 693 | GETARG_k(i) ? " (k)" : ""); | ||
| 694 | break; | ||
| 695 | case iABx: | ||
| 696 | sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); | ||
| 697 | break; | ||
| 698 | case iAsBx: | ||
| 699 | sprintf(buff, "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); | ||
| 700 | break; | ||
| 701 | case iAx: | ||
| 702 | sprintf(buff, "%-12s%4d", name, GETARG_Ax(i)); | ||
| 703 | break; | ||
| 704 | case isJ: | ||
| 705 | sprintf(buff, "%-12s%4d", name, GETARG_sJ(i)); | ||
| 706 | break; | ||
| 707 | } | ||
| 708 | return obuff; | ||
| 709 | } | ||
| 710 | |||
| 711 | |||
| 712 | #if 0 | ||
| 713 | void luaI_printcode (Proto *pt, int size) { | ||
| 714 | int pc; | ||
| 715 | for (pc=0; pc<size; pc++) { | ||
| 716 | char buff[100]; | ||
| 717 | printf("%s\n", buildop(pt, pc, buff)); | ||
| 718 | } | ||
| 719 | printf("-------\n"); | ||
| 720 | } | ||
| 721 | |||
| 722 | |||
| 723 | void luaI_printinst (Proto *pt, int pc) { | ||
| 724 | char buff[100]; | ||
| 725 | printf("%s\n", buildop(pt, pc, buff)); | ||
| 726 | } | ||
| 727 | #endif | ||
| 728 | |||
| 729 | |||
| 730 | static int listcode (lua_State *L) { | ||
| 731 | int pc; | ||
| 732 | Proto *p; | ||
| 733 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 734 | 1, "Lua function expected"); | ||
| 735 | p = getproto(obj_at(L, 1)); | ||
| 736 | lua_newtable(L); | ||
| 737 | setnameval(L, "maxstack", p->maxstacksize); | ||
| 738 | setnameval(L, "numparams", p->numparams); | ||
| 739 | for (pc=0; pc<p->sizecode; pc++) { | ||
| 740 | char buff[100]; | ||
| 741 | lua_pushinteger(L, pc+1); | ||
| 742 | lua_pushstring(L, buildop(p, pc, buff)); | ||
| 743 | lua_settable(L, -3); | ||
| 744 | } | ||
| 745 | return 1; | ||
| 746 | } | ||
| 747 | |||
| 748 | |||
| 749 | static int printcode (lua_State *L) { | ||
| 750 | int pc; | ||
| 751 | Proto *p; | ||
| 752 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 753 | 1, "Lua function expected"); | ||
| 754 | p = getproto(obj_at(L, 1)); | ||
| 755 | printf("maxstack: %d\n", p->maxstacksize); | ||
| 756 | printf("numparams: %d\n", p->numparams); | ||
| 757 | for (pc=0; pc<p->sizecode; pc++) { | ||
| 758 | char buff[100]; | ||
| 759 | printf("%s\n", buildop(p, pc, buff)); | ||
| 760 | } | ||
| 761 | return 0; | ||
| 762 | } | ||
| 763 | |||
| 764 | |||
| 765 | static int listk (lua_State *L) { | ||
| 766 | Proto *p; | ||
| 767 | int i; | ||
| 768 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 769 | 1, "Lua function expected"); | ||
| 770 | p = getproto(obj_at(L, 1)); | ||
| 771 | lua_createtable(L, p->sizek, 0); | ||
| 772 | for (i=0; i<p->sizek; i++) { | ||
| 773 | pushobject(L, p->k+i); | ||
| 774 | lua_rawseti(L, -2, i+1); | ||
| 775 | } | ||
| 776 | return 1; | ||
| 777 | } | ||
| 778 | |||
| 779 | |||
| 780 | static int listabslineinfo (lua_State *L) { | ||
| 781 | Proto *p; | ||
| 782 | int i; | ||
| 783 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 784 | 1, "Lua function expected"); | ||
| 785 | p = getproto(obj_at(L, 1)); | ||
| 786 | luaL_argcheck(L, p->abslineinfo != NULL, 1, "function has no debug info"); | ||
| 787 | lua_createtable(L, 2 * p->sizeabslineinfo, 0); | ||
| 788 | for (i=0; i < p->sizeabslineinfo; i++) { | ||
| 789 | lua_pushinteger(L, p->abslineinfo[i].pc); | ||
| 790 | lua_rawseti(L, -2, 2 * i + 1); | ||
| 791 | lua_pushinteger(L, p->abslineinfo[i].line); | ||
| 792 | lua_rawseti(L, -2, 2 * i + 2); | ||
| 793 | } | ||
| 794 | return 1; | ||
| 795 | } | ||
| 796 | |||
| 797 | |||
| 798 | static int listlocals (lua_State *L) { | ||
| 799 | Proto *p; | ||
| 800 | int pc = cast_int(luaL_checkinteger(L, 2)) - 1; | ||
| 801 | int i = 0; | ||
| 802 | const char *name; | ||
| 803 | luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), | ||
| 804 | 1, "Lua function expected"); | ||
| 805 | p = getproto(obj_at(L, 1)); | ||
| 806 | while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) | ||
| 807 | lua_pushstring(L, name); | ||
| 808 | return i-1; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* }====================================================== */ | ||
| 812 | |||
| 813 | |||
| 814 | |||
| 815 | static void printstack (lua_State *L) { | ||
| 816 | int i; | ||
| 817 | int n = lua_gettop(L); | ||
| 818 | printf("stack: >>\n"); | ||
| 819 | for (i = 1; i <= n; i++) { | ||
| 820 | printf("%3d: %s\n", i, luaL_tolstring(L, i, NULL)); | ||
| 821 | lua_pop(L, 1); | ||
| 822 | } | ||
| 823 | printf("<<\n"); | ||
| 824 | } | ||
| 825 | |||
| 826 | |||
| 827 | static int get_limits (lua_State *L) { | ||
| 828 | lua_createtable(L, 0, 6); | ||
| 829 | setnameval(L, "IS32INT", LUAI_IS32INT); | ||
| 830 | setnameval(L, "MAXARG_Ax", MAXARG_Ax); | ||
| 831 | setnameval(L, "MAXARG_Bx", MAXARG_Bx); | ||
| 832 | setnameval(L, "OFFSET_sBx", OFFSET_sBx); | ||
| 833 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); | ||
| 834 | setnameval(L, "NUM_OPCODES", NUM_OPCODES); | ||
| 835 | return 1; | ||
| 836 | } | ||
| 837 | |||
| 838 | |||
| 839 | static int mem_query (lua_State *L) { | ||
| 840 | if (lua_isnone(L, 1)) { | ||
| 841 | lua_pushinteger(L, l_memcontrol.total); | ||
| 842 | lua_pushinteger(L, l_memcontrol.numblocks); | ||
| 843 | lua_pushinteger(L, l_memcontrol.maxmem); | ||
| 844 | return 3; | ||
| 845 | } | ||
| 846 | else if (lua_isnumber(L, 1)) { | ||
| 847 | unsigned long limit = cast(unsigned long, luaL_checkinteger(L, 1)); | ||
| 848 | if (limit == 0) limit = ULONG_MAX; | ||
| 849 | l_memcontrol.memlimit = limit; | ||
| 850 | return 0; | ||
| 851 | } | ||
| 852 | else { | ||
| 853 | const char *t = luaL_checkstring(L, 1); | ||
| 854 | int i; | ||
| 855 | for (i = LUA_NUMTAGS - 1; i >= 0; i--) { | ||
| 856 | if (strcmp(t, ttypename(i)) == 0) { | ||
| 857 | lua_pushinteger(L, l_memcontrol.objcount[i]); | ||
| 858 | return 1; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | return luaL_error(L, "unknown type '%s'", t); | ||
| 862 | } | ||
| 863 | } | ||
| 864 | |||
| 865 | |||
| 866 | static int alloc_count (lua_State *L) { | ||
| 867 | if (lua_isnone(L, 1)) | ||
| 868 | l_memcontrol.countlimit = ~0L; | ||
| 869 | else | ||
| 870 | l_memcontrol.countlimit = luaL_checkinteger(L, 1); | ||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | |||
| 874 | |||
| 875 | static int alloc_failnext (lua_State *L) { | ||
| 876 | UNUSED(L); | ||
| 877 | l_memcontrol.failnext = 1; | ||
| 878 | return 0; | ||
| 879 | } | ||
| 880 | |||
| 881 | |||
| 882 | static int settrick (lua_State *L) { | ||
| 883 | if (ttisnil(obj_at(L, 1))) | ||
| 884 | l_Trick = NULL; | ||
| 885 | else | ||
| 886 | l_Trick = gcvalue(obj_at(L, 1)); | ||
| 887 | return 0; | ||
| 888 | } | ||
| 889 | |||
| 890 | |||
| 891 | static int gc_color (lua_State *L) { | ||
| 892 | TValue *o; | ||
| 893 | luaL_checkany(L, 1); | ||
| 894 | o = obj_at(L, 1); | ||
| 895 | if (!iscollectable(o)) | ||
| 896 | lua_pushstring(L, "no collectable"); | ||
| 897 | else { | ||
| 898 | GCObject *obj = gcvalue(o); | ||
| 899 | lua_pushstring(L, isdead(G(L), obj) ? "dead" : | ||
| 900 | iswhite(obj) ? "white" : | ||
| 901 | isblack(obj) ? "black" : "gray"); | ||
| 902 | } | ||
| 903 | return 1; | ||
| 904 | } | ||
| 905 | |||
| 906 | |||
| 907 | static int gc_age (lua_State *L) { | ||
| 908 | TValue *o; | ||
| 909 | luaL_checkany(L, 1); | ||
| 910 | o = obj_at(L, 1); | ||
| 911 | if (!iscollectable(o)) | ||
| 912 | lua_pushstring(L, "no collectable"); | ||
| 913 | else { | ||
| 914 | static const char *gennames[] = {"new", "survival", "old0", "old1", | ||
| 915 | "old", "touched1", "touched2"}; | ||
| 916 | GCObject *obj = gcvalue(o); | ||
| 917 | lua_pushstring(L, gennames[getage(obj)]); | ||
| 918 | } | ||
| 919 | return 1; | ||
| 920 | } | ||
| 921 | |||
| 922 | |||
| 923 | static int gc_printobj (lua_State *L) { | ||
| 924 | TValue *o; | ||
| 925 | luaL_checkany(L, 1); | ||
| 926 | o = obj_at(L, 1); | ||
| 927 | if (!iscollectable(o)) | ||
| 928 | printf("no collectable\n"); | ||
| 929 | else { | ||
| 930 | GCObject *obj = gcvalue(o); | ||
| 931 | printobj(G(L), obj); | ||
| 932 | printf("\n"); | ||
| 933 | } | ||
| 934 | return 0; | ||
| 935 | } | ||
| 936 | |||
| 937 | |||
| 938 | static int gc_state (lua_State *L) { | ||
| 939 | static const char *statenames[] = { | ||
| 940 | "propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj", | ||
| 941 | "sweeptobefnz", "sweepend", "callfin", "pause", ""}; | ||
| 942 | static const int states[] = { | ||
| 943 | GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj, | ||
| 944 | GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1}; | ||
| 945 | int option = states[luaL_checkoption(L, 1, "", statenames)]; | ||
| 946 | if (option == -1) { | ||
| 947 | lua_pushstring(L, statenames[G(L)->gcstate]); | ||
| 948 | return 1; | ||
| 949 | } | ||
| 950 | else { | ||
| 951 | global_State *g = G(L); | ||
| 952 | if (G(L)->gckind == KGC_GEN) | ||
| 953 | luaL_error(L, "cannot change states in generational mode"); | ||
| 954 | lua_lock(L); | ||
| 955 | if (option < g->gcstate) { /* must cross 'pause'? */ | ||
| 956 | luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ | ||
| 957 | } | ||
| 958 | luaC_runtilstate(L, bitmask(option)); | ||
| 959 | lua_assert(G(L)->gcstate == option); | ||
| 960 | lua_unlock(L); | ||
| 961 | return 0; | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | |||
| 966 | static int hash_query (lua_State *L) { | ||
| 967 | if (lua_isnone(L, 2)) { | ||
| 968 | luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); | ||
| 969 | lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash); | ||
| 970 | } | ||
| 971 | else { | ||
| 972 | TValue *o = obj_at(L, 1); | ||
| 973 | Table *t; | ||
| 974 | luaL_checktype(L, 2, LUA_TTABLE); | ||
| 975 | t = hvalue(obj_at(L, 2)); | ||
| 976 | lua_pushinteger(L, luaH_mainposition(t, o) - t->node); | ||
| 977 | } | ||
| 978 | return 1; | ||
| 979 | } | ||
| 980 | |||
| 981 | |||
| 982 | static int stacklevel (lua_State *L) { | ||
| 983 | unsigned long a = 0; | ||
| 984 | lua_pushinteger(L, (L->top.p - L->stack.p)); | ||
| 985 | lua_pushinteger(L, stacksize(L)); | ||
| 986 | lua_pushinteger(L, L->nCcalls); | ||
| 987 | lua_pushinteger(L, L->nci); | ||
| 988 | lua_pushinteger(L, (unsigned long)&a); | ||
| 989 | return 5; | ||
| 990 | } | ||
| 991 | |||
| 992 | |||
| 993 | static int table_query (lua_State *L) { | ||
| 994 | const Table *t; | ||
| 995 | int i = cast_int(luaL_optinteger(L, 2, -1)); | ||
| 996 | unsigned int asize; | ||
| 997 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 998 | t = hvalue(obj_at(L, 1)); | ||
| 999 | asize = luaH_realasize(t); | ||
| 1000 | if (i == -1) { | ||
| 1001 | lua_pushinteger(L, asize); | ||
| 1002 | lua_pushinteger(L, allocsizenode(t)); | ||
| 1003 | lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node); | ||
| 1004 | lua_pushinteger(L, t->alimit); | ||
| 1005 | return 4; | ||
| 1006 | } | ||
| 1007 | else if ((unsigned int)i < asize) { | ||
| 1008 | lua_pushinteger(L, i); | ||
| 1009 | pushobject(L, &t->array[i]); | ||
| 1010 | lua_pushnil(L); | ||
| 1011 | } | ||
| 1012 | else if ((i -= asize) < sizenode(t)) { | ||
| 1013 | TValue k; | ||
| 1014 | getnodekey(L, &k, gnode(t, i)); | ||
| 1015 | if (!isempty(gval(gnode(t, i))) || | ||
| 1016 | ttisnil(&k) || | ||
| 1017 | ttisnumber(&k)) { | ||
| 1018 | pushobject(L, &k); | ||
| 1019 | } | ||
| 1020 | else | ||
| 1021 | lua_pushliteral(L, "<undef>"); | ||
| 1022 | pushobject(L, gval(gnode(t, i))); | ||
| 1023 | if (gnext(&t->node[i]) != 0) | ||
| 1024 | lua_pushinteger(L, gnext(&t->node[i])); | ||
| 1025 | else | ||
| 1026 | lua_pushnil(L); | ||
| 1027 | } | ||
| 1028 | return 3; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | |||
| 1032 | static int string_query (lua_State *L) { | ||
| 1033 | stringtable *tb = &G(L)->strt; | ||
| 1034 | int s = cast_int(luaL_optinteger(L, 1, 0)) - 1; | ||
| 1035 | if (s == -1) { | ||
| 1036 | lua_pushinteger(L ,tb->size); | ||
| 1037 | lua_pushinteger(L ,tb->nuse); | ||
| 1038 | return 2; | ||
| 1039 | } | ||
| 1040 | else if (s < tb->size) { | ||
| 1041 | TString *ts; | ||
| 1042 | int n = 0; | ||
| 1043 | for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { | ||
| 1044 | setsvalue2s(L, L->top.p, ts); | ||
| 1045 | api_incr_top(L); | ||
| 1046 | n++; | ||
| 1047 | } | ||
| 1048 | return n; | ||
| 1049 | } | ||
| 1050 | else return 0; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | |||
| 1054 | static int tref (lua_State *L) { | ||
| 1055 | int level = lua_gettop(L); | ||
| 1056 | luaL_checkany(L, 1); | ||
| 1057 | lua_pushvalue(L, 1); | ||
| 1058 | lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); | ||
| 1059 | cast_void(level); /* to avoid warnings */ | ||
| 1060 | lua_assert(lua_gettop(L) == level+1); /* +1 for result */ | ||
| 1061 | return 1; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | static int getref (lua_State *L) { | ||
| 1065 | int level = lua_gettop(L); | ||
| 1066 | lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); | ||
| 1067 | cast_void(level); /* to avoid warnings */ | ||
| 1068 | lua_assert(lua_gettop(L) == level+1); | ||
| 1069 | return 1; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | static int unref (lua_State *L) { | ||
| 1073 | int level = lua_gettop(L); | ||
| 1074 | luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); | ||
| 1075 | cast_void(level); /* to avoid warnings */ | ||
| 1076 | lua_assert(lua_gettop(L) == level); | ||
| 1077 | return 0; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | |||
| 1081 | static int upvalue (lua_State *L) { | ||
| 1082 | int n = cast_int(luaL_checkinteger(L, 2)); | ||
| 1083 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
| 1084 | if (lua_isnone(L, 3)) { | ||
| 1085 | const char *name = lua_getupvalue(L, 1, n); | ||
| 1086 | if (name == NULL) return 0; | ||
| 1087 | lua_pushstring(L, name); | ||
| 1088 | return 2; | ||
| 1089 | } | ||
| 1090 | else { | ||
| 1091 | const char *name = lua_setupvalue(L, 1, n); | ||
| 1092 | lua_pushstring(L, name); | ||
| 1093 | return 1; | ||
| 1094 | } | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | |||
| 1098 | static int newuserdata (lua_State *L) { | ||
| 1099 | size_t size = cast_sizet(luaL_optinteger(L, 1, 0)); | ||
| 1100 | int nuv = luaL_optinteger(L, 2, 0); | ||
| 1101 | char *p = cast_charp(lua_newuserdatauv(L, size, nuv)); | ||
| 1102 | while (size--) *p++ = '\0'; | ||
| 1103 | return 1; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | |||
| 1107 | static int pushuserdata (lua_State *L) { | ||
| 1108 | lua_Integer u = luaL_checkinteger(L, 1); | ||
| 1109 | lua_pushlightuserdata(L, cast_voidp(cast_sizet(u))); | ||
| 1110 | return 1; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | |||
| 1114 | static int udataval (lua_State *L) { | ||
| 1115 | lua_pushinteger(L, cast(long, lua_touserdata(L, 1))); | ||
| 1116 | return 1; | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | |||
| 1120 | static int doonnewstack (lua_State *L) { | ||
| 1121 | lua_State *L1 = lua_newthread(L); | ||
| 1122 | size_t l; | ||
| 1123 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 1124 | int status = luaL_loadbuffer(L1, s, l, s); | ||
| 1125 | if (status == LUA_OK) | ||
| 1126 | status = lua_pcall(L1, 0, 0, 0); | ||
| 1127 | lua_pushinteger(L, status); | ||
| 1128 | return 1; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | |||
| 1132 | static int s2d (lua_State *L) { | ||
| 1133 | lua_pushnumber(L, cast_num(*cast(const double *, luaL_checkstring(L, 1)))); | ||
| 1134 | return 1; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | |||
| 1138 | static int d2s (lua_State *L) { | ||
| 1139 | double d = cast(double, luaL_checknumber(L, 1)); | ||
| 1140 | lua_pushlstring(L, cast_charp(&d), sizeof(d)); | ||
| 1141 | return 1; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | |||
| 1145 | static int num2int (lua_State *L) { | ||
| 1146 | lua_pushinteger(L, lua_tointeger(L, 1)); | ||
| 1147 | return 1; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | |||
| 1151 | static int newstate (lua_State *L) { | ||
| 1152 | void *ud; | ||
| 1153 | lua_Alloc f = lua_getallocf(L, &ud); | ||
| 1154 | lua_State *L1 = lua_newstate(f, ud); | ||
| 1155 | if (L1) { | ||
| 1156 | lua_atpanic(L1, tpanic); | ||
| 1157 | lua_pushlightuserdata(L, L1); | ||
| 1158 | } | ||
| 1159 | else | ||
| 1160 | lua_pushnil(L); | ||
| 1161 | return 1; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | |||
| 1165 | static lua_State *getstate (lua_State *L) { | ||
| 1166 | lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1)); | ||
| 1167 | luaL_argcheck(L, L1 != NULL, 1, "state expected"); | ||
| 1168 | return L1; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | |||
| 1172 | static int loadlib (lua_State *L) { | ||
| 1173 | static const luaL_Reg libs[] = { | ||
| 1174 | {LUA_GNAME, luaopen_base}, | ||
| 1175 | {"coroutine", luaopen_coroutine}, | ||
| 1176 | {"debug", luaopen_debug}, | ||
| 1177 | {"io", luaopen_io}, | ||
| 1178 | {"os", luaopen_os}, | ||
| 1179 | {"math", luaopen_math}, | ||
| 1180 | {"string", luaopen_string}, | ||
| 1181 | {"table", luaopen_table}, | ||
| 1182 | {"T", luaB_opentests}, | ||
| 1183 | {NULL, NULL} | ||
| 1184 | }; | ||
| 1185 | lua_State *L1 = getstate(L); | ||
| 1186 | int i; | ||
| 1187 | luaL_requiref(L1, "package", luaopen_package, 0); | ||
| 1188 | lua_assert(lua_type(L1, -1) == LUA_TTABLE); | ||
| 1189 | /* 'requiref' should not reload module already loaded... */ | ||
| 1190 | luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */ | ||
| 1191 | /* ...but should return the same module */ | ||
| 1192 | lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); | ||
| 1193 | luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); | ||
| 1194 | for (i = 0; libs[i].name; i++) { | ||
| 1195 | lua_pushcfunction(L1, libs[i].func); | ||
| 1196 | lua_setfield(L1, -2, libs[i].name); | ||
| 1197 | } | ||
| 1198 | return 0; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | static int closestate (lua_State *L) { | ||
| 1202 | lua_State *L1 = getstate(L); | ||
| 1203 | lua_close(L1); | ||
| 1204 | return 0; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | static int doremote (lua_State *L) { | ||
| 1208 | lua_State *L1 = getstate(L); | ||
| 1209 | size_t lcode; | ||
| 1210 | const char *code = luaL_checklstring(L, 2, &lcode); | ||
| 1211 | int status; | ||
| 1212 | lua_settop(L1, 0); | ||
| 1213 | status = luaL_loadbuffer(L1, code, lcode, code); | ||
| 1214 | if (status == LUA_OK) | ||
| 1215 | status = lua_pcall(L1, 0, LUA_MULTRET, 0); | ||
| 1216 | if (status != LUA_OK) { | ||
| 1217 | lua_pushnil(L); | ||
| 1218 | lua_pushstring(L, lua_tostring(L1, -1)); | ||
| 1219 | lua_pushinteger(L, status); | ||
| 1220 | return 3; | ||
| 1221 | } | ||
| 1222 | else { | ||
| 1223 | int i = 0; | ||
| 1224 | while (!lua_isnone(L1, ++i)) | ||
| 1225 | lua_pushstring(L, lua_tostring(L1, i)); | ||
| 1226 | lua_pop(L1, i-1); | ||
| 1227 | return i-1; | ||
| 1228 | } | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | |||
| 1232 | static int log2_aux (lua_State *L) { | ||
| 1233 | unsigned int x = (unsigned int)luaL_checkinteger(L, 1); | ||
| 1234 | lua_pushinteger(L, luaO_ceillog2(x)); | ||
| 1235 | return 1; | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | |||
| 1239 | struct Aux { jmp_buf jb; const char *paniccode; lua_State *L; }; | ||
| 1240 | |||
| 1241 | /* | ||
| 1242 | ** does a long-jump back to "main program". | ||
| 1243 | */ | ||
| 1244 | static int panicback (lua_State *L) { | ||
| 1245 | struct Aux *b; | ||
| 1246 | lua_checkstack(L, 1); /* open space for 'Aux' struct */ | ||
| 1247 | lua_getfield(L, LUA_REGISTRYINDEX, "_jmpbuf"); /* get 'Aux' struct */ | ||
| 1248 | b = (struct Aux *)lua_touserdata(L, -1); | ||
| 1249 | lua_pop(L, 1); /* remove 'Aux' struct */ | ||
| 1250 | runC(b->L, L, b->paniccode); /* run optional panic code */ | ||
| 1251 | longjmp(b->jb, 1); | ||
| 1252 | return 1; /* to avoid warnings */ | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | static int checkpanic (lua_State *L) { | ||
| 1256 | struct Aux b; | ||
| 1257 | void *ud; | ||
| 1258 | lua_State *L1; | ||
| 1259 | const char *code = luaL_checkstring(L, 1); | ||
| 1260 | lua_Alloc f = lua_getallocf(L, &ud); | ||
| 1261 | b.paniccode = luaL_optstring(L, 2, ""); | ||
| 1262 | b.L = L; | ||
| 1263 | L1 = lua_newstate(f, ud); /* create new state */ | ||
| 1264 | if (L1 == NULL) { /* error? */ | ||
| 1265 | lua_pushnil(L); | ||
| 1266 | return 1; | ||
| 1267 | } | ||
| 1268 | lua_atpanic(L1, panicback); /* set its panic function */ | ||
| 1269 | lua_pushlightuserdata(L1, &b); | ||
| 1270 | lua_setfield(L1, LUA_REGISTRYINDEX, "_jmpbuf"); /* store 'Aux' struct */ | ||
| 1271 | if (setjmp(b.jb) == 0) { /* set jump buffer */ | ||
| 1272 | runC(L, L1, code); /* run code unprotected */ | ||
| 1273 | lua_pushliteral(L, "no errors"); | ||
| 1274 | } | ||
| 1275 | else { /* error handling */ | ||
| 1276 | /* move error message to original state */ | ||
| 1277 | lua_pushstring(L, lua_tostring(L1, -1)); | ||
| 1278 | } | ||
| 1279 | lua_close(L1); | ||
| 1280 | return 1; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | |||
| 1284 | |||
| 1285 | /* | ||
| 1286 | ** {==================================================================== | ||
| 1287 | ** function to test the API with C. It interprets a kind of assembler | ||
| 1288 | ** language with calls to the API, so the test can be driven by Lua code | ||
| 1289 | ** ===================================================================== | ||
| 1290 | */ | ||
| 1291 | |||
| 1292 | |||
| 1293 | static void sethookaux (lua_State *L, int mask, int count, const char *code); | ||
| 1294 | |||
| 1295 | static const char *const delimits = " \t\n,;"; | ||
| 1296 | |||
| 1297 | static void skip (const char **pc) { | ||
| 1298 | for (;;) { | ||
| 1299 | if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; | ||
| 1300 | else if (**pc == '#') { /* comment? */ | ||
| 1301 | while (**pc != '\n' && **pc != '\0') (*pc)++; /* until end-of-line */ | ||
| 1302 | } | ||
| 1303 | else break; | ||
| 1304 | } | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) { | ||
| 1308 | int res = 0; | ||
| 1309 | int sig = 1; | ||
| 1310 | skip(pc); | ||
| 1311 | if (**pc == '.') { | ||
| 1312 | res = cast_int(lua_tointeger(L1, -1)); | ||
| 1313 | lua_pop(L1, 1); | ||
| 1314 | (*pc)++; | ||
| 1315 | return res; | ||
| 1316 | } | ||
| 1317 | else if (**pc == '*') { | ||
| 1318 | res = lua_gettop(L1); | ||
| 1319 | (*pc)++; | ||
| 1320 | return res; | ||
| 1321 | } | ||
| 1322 | else if (**pc == '-') { | ||
| 1323 | sig = -1; | ||
| 1324 | (*pc)++; | ||
| 1325 | } | ||
| 1326 | if (!lisdigit(cast_uchar(**pc))) | ||
| 1327 | luaL_error(L, "number expected (%s)", *pc); | ||
| 1328 | while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0'; | ||
| 1329 | return sig*res; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | static const char *getstring_aux (lua_State *L, char *buff, const char **pc) { | ||
| 1333 | int i = 0; | ||
| 1334 | skip(pc); | ||
| 1335 | if (**pc == '"' || **pc == '\'') { /* quoted string? */ | ||
| 1336 | int quote = *(*pc)++; | ||
| 1337 | while (**pc != quote) { | ||
| 1338 | if (**pc == '\0') luaL_error(L, "unfinished string in C script"); | ||
| 1339 | buff[i++] = *(*pc)++; | ||
| 1340 | } | ||
| 1341 | (*pc)++; | ||
| 1342 | } | ||
| 1343 | else { | ||
| 1344 | while (**pc != '\0' && !strchr(delimits, **pc)) | ||
| 1345 | buff[i++] = *(*pc)++; | ||
| 1346 | } | ||
| 1347 | buff[i] = '\0'; | ||
| 1348 | return buff; | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | |||
| 1352 | static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) { | ||
| 1353 | skip(pc); | ||
| 1354 | switch (*(*pc)++) { | ||
| 1355 | case 'R': return LUA_REGISTRYINDEX; | ||
| 1356 | case 'G': return luaL_error(L, "deprecated index 'G'"); | ||
| 1357 | case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc)); | ||
| 1358 | default: (*pc)--; return getnum_aux(L, L1, pc); | ||
| 1359 | } | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | |||
| 1363 | static const char *const statcodes[] = {"OK", "YIELD", "ERRRUN", | ||
| 1364 | "ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"}; | ||
| 1365 | |||
| 1366 | /* | ||
| 1367 | ** Avoid these stat codes from being collected, to avoid possible | ||
| 1368 | ** memory error when pushing them. | ||
| 1369 | */ | ||
| 1370 | static void regcodes (lua_State *L) { | ||
| 1371 | unsigned int i; | ||
| 1372 | for (i = 0; i < sizeof(statcodes) / sizeof(statcodes[0]); i++) { | ||
| 1373 | lua_pushboolean(L, 1); | ||
| 1374 | lua_setfield(L, LUA_REGISTRYINDEX, statcodes[i]); | ||
| 1375 | } | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | |||
| 1379 | #define EQ(s1) (strcmp(s1, inst) == 0) | ||
| 1380 | |||
| 1381 | #define getnum (getnum_aux(L, L1, &pc)) | ||
| 1382 | #define getstring (getstring_aux(L, buff, &pc)) | ||
| 1383 | #define getindex (getindex_aux(L, L1, &pc)) | ||
| 1384 | |||
| 1385 | |||
| 1386 | static int testC (lua_State *L); | ||
| 1387 | static int Cfunck (lua_State *L, int status, lua_KContext ctx); | ||
| 1388 | |||
| 1389 | /* | ||
| 1390 | ** arithmetic operation encoding for 'arith' instruction | ||
| 1391 | ** LUA_OPIDIV -> \ | ||
| 1392 | ** LUA_OPSHL -> < | ||
| 1393 | ** LUA_OPSHR -> > | ||
| 1394 | ** LUA_OPUNM -> _ | ||
| 1395 | ** LUA_OPBNOT -> ! | ||
| 1396 | */ | ||
| 1397 | static const char ops[] = "+-*%^/\\&|~<>_!"; | ||
| 1398 | |||
| 1399 | static int runC (lua_State *L, lua_State *L1, const char *pc) { | ||
| 1400 | char buff[300]; | ||
| 1401 | int status = 0; | ||
| 1402 | if (pc == NULL) return luaL_error(L, "attempt to runC null script"); | ||
| 1403 | for (;;) { | ||
| 1404 | const char *inst = getstring; | ||
| 1405 | if EQ("") return 0; | ||
| 1406 | else if EQ("absindex") { | ||
| 1407 | lua_pushnumber(L1, lua_absindex(L1, getindex)); | ||
| 1408 | } | ||
| 1409 | else if EQ("append") { | ||
| 1410 | int t = getindex; | ||
| 1411 | int i = lua_rawlen(L1, t); | ||
| 1412 | lua_rawseti(L1, t, i + 1); | ||
| 1413 | } | ||
| 1414 | else if EQ("arith") { | ||
| 1415 | int op; | ||
| 1416 | skip(&pc); | ||
| 1417 | op = strchr(ops, *pc++) - ops; | ||
| 1418 | lua_arith(L1, op); | ||
| 1419 | } | ||
| 1420 | else if EQ("call") { | ||
| 1421 | int narg = getnum; | ||
| 1422 | int nres = getnum; | ||
| 1423 | lua_call(L1, narg, nres); | ||
| 1424 | } | ||
| 1425 | else if EQ("callk") { | ||
| 1426 | int narg = getnum; | ||
| 1427 | int nres = getnum; | ||
| 1428 | int i = getindex; | ||
| 1429 | lua_callk(L1, narg, nres, i, Cfunck); | ||
| 1430 | } | ||
| 1431 | else if EQ("checkstack") { | ||
| 1432 | int sz = getnum; | ||
| 1433 | const char *msg = getstring; | ||
| 1434 | if (*msg == '\0') | ||
| 1435 | msg = NULL; /* to test 'luaL_checkstack' with no message */ | ||
| 1436 | luaL_checkstack(L1, sz, msg); | ||
| 1437 | } | ||
| 1438 | else if EQ("rawcheckstack") { | ||
| 1439 | int sz = getnum; | ||
| 1440 | lua_pushboolean(L1, lua_checkstack(L1, sz)); | ||
| 1441 | } | ||
| 1442 | else if EQ("compare") { | ||
| 1443 | const char *opt = getstring; /* EQ, LT, or LE */ | ||
| 1444 | int op = (opt[0] == 'E') ? LUA_OPEQ | ||
| 1445 | : (opt[1] == 'T') ? LUA_OPLT : LUA_OPLE; | ||
| 1446 | int a = getindex; | ||
| 1447 | int b = getindex; | ||
| 1448 | lua_pushboolean(L1, lua_compare(L1, a, b, op)); | ||
| 1449 | } | ||
| 1450 | else if EQ("concat") { | ||
| 1451 | lua_concat(L1, getnum); | ||
| 1452 | } | ||
| 1453 | else if EQ("copy") { | ||
| 1454 | int f = getindex; | ||
| 1455 | lua_copy(L1, f, getindex); | ||
| 1456 | } | ||
| 1457 | else if EQ("func2num") { | ||
| 1458 | lua_CFunction func = lua_tocfunction(L1, getindex); | ||
| 1459 | lua_pushnumber(L1, cast_sizet(func)); | ||
| 1460 | } | ||
| 1461 | else if EQ("getfield") { | ||
| 1462 | int t = getindex; | ||
| 1463 | lua_getfield(L1, t, getstring); | ||
| 1464 | } | ||
| 1465 | else if EQ("getglobal") { | ||
| 1466 | lua_getglobal(L1, getstring); | ||
| 1467 | } | ||
| 1468 | else if EQ("getmetatable") { | ||
| 1469 | if (lua_getmetatable(L1, getindex) == 0) | ||
| 1470 | lua_pushnil(L1); | ||
| 1471 | } | ||
| 1472 | else if EQ("gettable") { | ||
| 1473 | lua_gettable(L1, getindex); | ||
| 1474 | } | ||
| 1475 | else if EQ("gettop") { | ||
| 1476 | lua_pushinteger(L1, lua_gettop(L1)); | ||
| 1477 | } | ||
| 1478 | else if EQ("gsub") { | ||
| 1479 | int a = getnum; int b = getnum; int c = getnum; | ||
| 1480 | luaL_gsub(L1, lua_tostring(L1, a), | ||
| 1481 | lua_tostring(L1, b), | ||
| 1482 | lua_tostring(L1, c)); | ||
| 1483 | } | ||
| 1484 | else if EQ("insert") { | ||
| 1485 | lua_insert(L1, getnum); | ||
| 1486 | } | ||
| 1487 | else if EQ("iscfunction") { | ||
| 1488 | lua_pushboolean(L1, lua_iscfunction(L1, getindex)); | ||
| 1489 | } | ||
| 1490 | else if EQ("isfunction") { | ||
| 1491 | lua_pushboolean(L1, lua_isfunction(L1, getindex)); | ||
| 1492 | } | ||
| 1493 | else if EQ("isnil") { | ||
| 1494 | lua_pushboolean(L1, lua_isnil(L1, getindex)); | ||
| 1495 | } | ||
| 1496 | else if EQ("isnull") { | ||
| 1497 | lua_pushboolean(L1, lua_isnone(L1, getindex)); | ||
| 1498 | } | ||
| 1499 | else if EQ("isnumber") { | ||
| 1500 | lua_pushboolean(L1, lua_isnumber(L1, getindex)); | ||
| 1501 | } | ||
| 1502 | else if EQ("isstring") { | ||
| 1503 | lua_pushboolean(L1, lua_isstring(L1, getindex)); | ||
| 1504 | } | ||
| 1505 | else if EQ("istable") { | ||
| 1506 | lua_pushboolean(L1, lua_istable(L1, getindex)); | ||
| 1507 | } | ||
| 1508 | else if EQ("isudataval") { | ||
| 1509 | lua_pushboolean(L1, lua_islightuserdata(L1, getindex)); | ||
| 1510 | } | ||
| 1511 | else if EQ("isuserdata") { | ||
| 1512 | lua_pushboolean(L1, lua_isuserdata(L1, getindex)); | ||
| 1513 | } | ||
| 1514 | else if EQ("len") { | ||
| 1515 | lua_len(L1, getindex); | ||
| 1516 | } | ||
| 1517 | else if EQ("Llen") { | ||
| 1518 | lua_pushinteger(L1, luaL_len(L1, getindex)); | ||
| 1519 | } | ||
| 1520 | else if EQ("loadfile") { | ||
| 1521 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | ||
| 1522 | } | ||
| 1523 | else if EQ("loadstring") { | ||
| 1524 | const char *s = luaL_checkstring(L1, getnum); | ||
| 1525 | luaL_loadstring(L1, s); | ||
| 1526 | } | ||
| 1527 | else if EQ("newmetatable") { | ||
| 1528 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); | ||
| 1529 | } | ||
| 1530 | else if EQ("newtable") { | ||
| 1531 | lua_newtable(L1); | ||
| 1532 | } | ||
| 1533 | else if EQ("newthread") { | ||
| 1534 | lua_newthread(L1); | ||
| 1535 | } | ||
| 1536 | else if EQ("resetthread") { | ||
| 1537 | lua_pushinteger(L1, lua_resetthread(L1)); /* deprecated */ | ||
| 1538 | } | ||
| 1539 | else if EQ("newuserdata") { | ||
| 1540 | lua_newuserdata(L1, getnum); | ||
| 1541 | } | ||
| 1542 | else if EQ("next") { | ||
| 1543 | lua_next(L1, -2); | ||
| 1544 | } | ||
| 1545 | else if EQ("objsize") { | ||
| 1546 | lua_pushinteger(L1, lua_rawlen(L1, getindex)); | ||
| 1547 | } | ||
| 1548 | else if EQ("pcall") { | ||
| 1549 | int narg = getnum; | ||
| 1550 | int nres = getnum; | ||
| 1551 | status = lua_pcall(L1, narg, nres, getnum); | ||
| 1552 | } | ||
| 1553 | else if EQ("pcallk") { | ||
| 1554 | int narg = getnum; | ||
| 1555 | int nres = getnum; | ||
| 1556 | int i = getindex; | ||
| 1557 | status = lua_pcallk(L1, narg, nres, 0, i, Cfunck); | ||
| 1558 | } | ||
| 1559 | else if EQ("pop") { | ||
| 1560 | lua_pop(L1, getnum); | ||
| 1561 | } | ||
| 1562 | else if EQ("printstack") { | ||
| 1563 | int n = getnum; | ||
| 1564 | if (n != 0) { | ||
| 1565 | printf("%s\n", luaL_tolstring(L1, n, NULL)); | ||
| 1566 | lua_pop(L1, 1); | ||
| 1567 | } | ||
| 1568 | else printstack(L1); | ||
| 1569 | } | ||
| 1570 | else if EQ("print") { | ||
| 1571 | const char *msg = getstring; | ||
| 1572 | printf("%s\n", msg); | ||
| 1573 | } | ||
| 1574 | else if EQ("warningC") { | ||
| 1575 | const char *msg = getstring; | ||
| 1576 | lua_warning(L1, msg, 1); | ||
| 1577 | } | ||
| 1578 | else if EQ("warning") { | ||
| 1579 | const char *msg = getstring; | ||
| 1580 | lua_warning(L1, msg, 0); | ||
| 1581 | } | ||
| 1582 | else if EQ("pushbool") { | ||
| 1583 | lua_pushboolean(L1, getnum); | ||
| 1584 | } | ||
| 1585 | else if EQ("pushcclosure") { | ||
| 1586 | lua_pushcclosure(L1, testC, getnum); | ||
| 1587 | } | ||
| 1588 | else if EQ("pushint") { | ||
| 1589 | lua_pushinteger(L1, getnum); | ||
| 1590 | } | ||
| 1591 | else if EQ("pushnil") { | ||
| 1592 | lua_pushnil(L1); | ||
| 1593 | } | ||
| 1594 | else if EQ("pushnum") { | ||
| 1595 | lua_pushnumber(L1, (lua_Number)getnum); | ||
| 1596 | } | ||
| 1597 | else if EQ("pushstatus") { | ||
| 1598 | lua_pushstring(L1, statcodes[status]); | ||
| 1599 | } | ||
| 1600 | else if EQ("pushstring") { | ||
| 1601 | lua_pushstring(L1, getstring); | ||
| 1602 | } | ||
| 1603 | else if EQ("pushupvalueindex") { | ||
| 1604 | lua_pushinteger(L1, lua_upvalueindex(getnum)); | ||
| 1605 | } | ||
| 1606 | else if EQ("pushvalue") { | ||
| 1607 | lua_pushvalue(L1, getindex); | ||
| 1608 | } | ||
| 1609 | else if EQ("pushfstringI") { | ||
| 1610 | lua_pushfstring(L1, lua_tostring(L, -2), (int)lua_tointeger(L, -1)); | ||
| 1611 | } | ||
| 1612 | else if EQ("pushfstringS") { | ||
| 1613 | lua_pushfstring(L1, lua_tostring(L, -2), lua_tostring(L, -1)); | ||
| 1614 | } | ||
| 1615 | else if EQ("pushfstringP") { | ||
| 1616 | lua_pushfstring(L1, lua_tostring(L, -2), lua_topointer(L, -1)); | ||
| 1617 | } | ||
| 1618 | else if EQ("rawget") { | ||
| 1619 | int t = getindex; | ||
| 1620 | lua_rawget(L1, t); | ||
| 1621 | } | ||
| 1622 | else if EQ("rawgeti") { | ||
| 1623 | int t = getindex; | ||
| 1624 | lua_rawgeti(L1, t, getnum); | ||
| 1625 | } | ||
| 1626 | else if EQ("rawgetp") { | ||
| 1627 | int t = getindex; | ||
| 1628 | lua_rawgetp(L1, t, cast_voidp(cast_sizet(getnum))); | ||
| 1629 | } | ||
| 1630 | else if EQ("rawset") { | ||
| 1631 | int t = getindex; | ||
| 1632 | lua_rawset(L1, t); | ||
| 1633 | } | ||
| 1634 | else if EQ("rawseti") { | ||
| 1635 | int t = getindex; | ||
| 1636 | lua_rawseti(L1, t, getnum); | ||
| 1637 | } | ||
| 1638 | else if EQ("rawsetp") { | ||
| 1639 | int t = getindex; | ||
| 1640 | lua_rawsetp(L1, t, cast_voidp(cast_sizet(getnum))); | ||
| 1641 | } | ||
| 1642 | else if EQ("remove") { | ||
| 1643 | lua_remove(L1, getnum); | ||
| 1644 | } | ||
| 1645 | else if EQ("replace") { | ||
| 1646 | lua_replace(L1, getindex); | ||
| 1647 | } | ||
| 1648 | else if EQ("resume") { | ||
| 1649 | int i = getindex; | ||
| 1650 | int nres; | ||
| 1651 | status = lua_resume(lua_tothread(L1, i), L, getnum, &nres); | ||
| 1652 | } | ||
| 1653 | else if EQ("traceback") { | ||
| 1654 | const char *msg = getstring; | ||
| 1655 | int level = getnum; | ||
| 1656 | luaL_traceback(L1, L1, msg, level); | ||
| 1657 | } | ||
| 1658 | else if EQ("return") { | ||
| 1659 | int n = getnum; | ||
| 1660 | if (L1 != L) { | ||
| 1661 | int i; | ||
| 1662 | for (i = 0; i < n; i++) { | ||
| 1663 | int idx = -(n - i); | ||
| 1664 | switch (lua_type(L1, idx)) { | ||
| 1665 | case LUA_TBOOLEAN: | ||
| 1666 | lua_pushboolean(L, lua_toboolean(L1, idx)); | ||
| 1667 | break; | ||
| 1668 | default: | ||
| 1669 | lua_pushstring(L, lua_tostring(L1, idx)); | ||
| 1670 | break; | ||
| 1671 | } | ||
| 1672 | } | ||
| 1673 | } | ||
| 1674 | return n; | ||
| 1675 | } | ||
| 1676 | else if EQ("rotate") { | ||
| 1677 | int i = getindex; | ||
| 1678 | lua_rotate(L1, i, getnum); | ||
| 1679 | } | ||
| 1680 | else if EQ("setfield") { | ||
| 1681 | int t = getindex; | ||
| 1682 | const char *s = getstring; | ||
| 1683 | lua_setfield(L1, t, s); | ||
| 1684 | } | ||
| 1685 | else if EQ("seti") { | ||
| 1686 | int t = getindex; | ||
| 1687 | lua_seti(L1, t, getnum); | ||
| 1688 | } | ||
| 1689 | else if EQ("setglobal") { | ||
| 1690 | const char *s = getstring; | ||
| 1691 | lua_setglobal(L1, s); | ||
| 1692 | } | ||
| 1693 | else if EQ("sethook") { | ||
| 1694 | int mask = getnum; | ||
| 1695 | int count = getnum; | ||
| 1696 | const char *s = getstring; | ||
| 1697 | sethookaux(L1, mask, count, s); | ||
| 1698 | } | ||
| 1699 | else if EQ("setmetatable") { | ||
| 1700 | int idx = getindex; | ||
| 1701 | lua_setmetatable(L1, idx); | ||
| 1702 | } | ||
| 1703 | else if EQ("settable") { | ||
| 1704 | lua_settable(L1, getindex); | ||
| 1705 | } | ||
| 1706 | else if EQ("settop") { | ||
| 1707 | lua_settop(L1, getnum); | ||
| 1708 | } | ||
| 1709 | else if EQ("testudata") { | ||
| 1710 | int i = getindex; | ||
| 1711 | lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL); | ||
| 1712 | } | ||
| 1713 | else if EQ("error") { | ||
| 1714 | lua_error(L1); | ||
| 1715 | } | ||
| 1716 | else if EQ("abort") { | ||
| 1717 | abort(); | ||
| 1718 | } | ||
| 1719 | else if EQ("throw") { | ||
| 1720 | #if defined(__cplusplus) | ||
| 1721 | static struct X { int x; } x; | ||
| 1722 | throw x; | ||
| 1723 | #else | ||
| 1724 | luaL_error(L1, "C++"); | ||
| 1725 | #endif | ||
| 1726 | break; | ||
| 1727 | } | ||
| 1728 | else if EQ("tobool") { | ||
| 1729 | lua_pushboolean(L1, lua_toboolean(L1, getindex)); | ||
| 1730 | } | ||
| 1731 | else if EQ("tocfunction") { | ||
| 1732 | lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); | ||
| 1733 | } | ||
| 1734 | else if EQ("tointeger") { | ||
| 1735 | lua_pushinteger(L1, lua_tointeger(L1, getindex)); | ||
| 1736 | } | ||
| 1737 | else if EQ("tonumber") { | ||
| 1738 | lua_pushnumber(L1, lua_tonumber(L1, getindex)); | ||
| 1739 | } | ||
| 1740 | else if EQ("topointer") { | ||
| 1741 | lua_pushlightuserdata(L1, cast_voidp(lua_topointer(L1, getindex))); | ||
| 1742 | } | ||
| 1743 | else if EQ("touserdata") { | ||
| 1744 | lua_pushlightuserdata(L1, lua_touserdata(L1, getindex)); | ||
| 1745 | } | ||
| 1746 | else if EQ("tostring") { | ||
| 1747 | const char *s = lua_tostring(L1, getindex); | ||
| 1748 | const char *s1 = lua_pushstring(L1, s); | ||
| 1749 | cast_void(s1); /* to avoid warnings */ | ||
| 1750 | lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); | ||
| 1751 | } | ||
| 1752 | else if EQ("Ltolstring") { | ||
| 1753 | luaL_tolstring(L1, getindex, NULL); | ||
| 1754 | } | ||
| 1755 | else if EQ("type") { | ||
| 1756 | lua_pushstring(L1, luaL_typename(L1, getnum)); | ||
| 1757 | } | ||
| 1758 | else if EQ("xmove") { | ||
| 1759 | int f = getindex; | ||
| 1760 | int t = getindex; | ||
| 1761 | lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f); | ||
| 1762 | lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t); | ||
| 1763 | int n = getnum; | ||
| 1764 | if (n == 0) n = lua_gettop(fs); | ||
| 1765 | lua_xmove(fs, ts, n); | ||
| 1766 | } | ||
| 1767 | else if EQ("isyieldable") { | ||
| 1768 | lua_pushboolean(L1, lua_isyieldable(lua_tothread(L1, getindex))); | ||
| 1769 | } | ||
| 1770 | else if EQ("yield") { | ||
| 1771 | return lua_yield(L1, getnum); | ||
| 1772 | } | ||
| 1773 | else if EQ("yieldk") { | ||
| 1774 | int nres = getnum; | ||
| 1775 | int i = getindex; | ||
| 1776 | return lua_yieldk(L1, nres, i, Cfunck); | ||
| 1777 | } | ||
| 1778 | else if EQ("toclose") { | ||
| 1779 | lua_toclose(L1, getnum); | ||
| 1780 | } | ||
| 1781 | else if EQ("closeslot") { | ||
| 1782 | lua_closeslot(L1, getnum); | ||
| 1783 | } | ||
| 1784 | else luaL_error(L, "unknown instruction %s", buff); | ||
| 1785 | } | ||
| 1786 | return 0; | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | |||
| 1790 | static int testC (lua_State *L) { | ||
| 1791 | lua_State *L1; | ||
| 1792 | const char *pc; | ||
| 1793 | if (lua_isuserdata(L, 1)) { | ||
| 1794 | L1 = getstate(L); | ||
| 1795 | pc = luaL_checkstring(L, 2); | ||
| 1796 | } | ||
| 1797 | else if (lua_isthread(L, 1)) { | ||
| 1798 | L1 = lua_tothread(L, 1); | ||
| 1799 | pc = luaL_checkstring(L, 2); | ||
| 1800 | } | ||
| 1801 | else { | ||
| 1802 | L1 = L; | ||
| 1803 | pc = luaL_checkstring(L, 1); | ||
| 1804 | } | ||
| 1805 | return runC(L, L1, pc); | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | |||
| 1809 | static int Cfunc (lua_State *L) { | ||
| 1810 | return runC(L, L, lua_tostring(L, lua_upvalueindex(1))); | ||
| 1811 | } | ||
| 1812 | |||
| 1813 | |||
| 1814 | static int Cfunck (lua_State *L, int status, lua_KContext ctx) { | ||
| 1815 | lua_pushstring(L, statcodes[status]); | ||
| 1816 | lua_setglobal(L, "status"); | ||
| 1817 | lua_pushinteger(L, ctx); | ||
| 1818 | lua_setglobal(L, "ctx"); | ||
| 1819 | return runC(L, L, lua_tostring(L, ctx)); | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | |||
| 1823 | static int makeCfunc (lua_State *L) { | ||
| 1824 | luaL_checkstring(L, 1); | ||
| 1825 | lua_pushcclosure(L, Cfunc, lua_gettop(L)); | ||
| 1826 | return 1; | ||
| 1827 | } | ||
| 1828 | |||
| 1829 | |||
| 1830 | /* }====================================================== */ | ||
| 1831 | |||
| 1832 | |||
| 1833 | /* | ||
| 1834 | ** {====================================================== | ||
| 1835 | ** tests for C hooks | ||
| 1836 | ** ======================================================= | ||
| 1837 | */ | ||
| 1838 | |||
| 1839 | /* | ||
| 1840 | ** C hook that runs the C script stored in registry.C_HOOK[L] | ||
| 1841 | */ | ||
| 1842 | static void Chook (lua_State *L, lua_Debug *ar) { | ||
| 1843 | const char *scpt; | ||
| 1844 | const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; | ||
| 1845 | lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); | ||
| 1846 | lua_pushlightuserdata(L, L); | ||
| 1847 | lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ | ||
| 1848 | scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ | ||
| 1849 | lua_pop(L, 2); /* remove C_HOOK and script */ | ||
| 1850 | lua_pushstring(L, events[ar->event]); /* may be used by script */ | ||
| 1851 | lua_pushinteger(L, ar->currentline); /* may be used by script */ | ||
| 1852 | runC(L, L, scpt); /* run script from C_HOOK[L] */ | ||
| 1853 | } | ||
| 1854 | |||
| 1855 | |||
| 1856 | /* | ||
| 1857 | ** sets 'registry.C_HOOK[L] = scpt' and sets 'Chook' as a hook | ||
| 1858 | */ | ||
| 1859 | static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { | ||
| 1860 | if (*scpt == '\0') { /* no script? */ | ||
| 1861 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | ||
| 1862 | return; | ||
| 1863 | } | ||
| 1864 | lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ | ||
| 1865 | if (!lua_istable(L, -1)) { /* no hook table? */ | ||
| 1866 | lua_pop(L, 1); /* remove previous value */ | ||
| 1867 | lua_newtable(L); /* create new C_HOOK table */ | ||
| 1868 | lua_pushvalue(L, -1); | ||
| 1869 | lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ | ||
| 1870 | } | ||
| 1871 | lua_pushlightuserdata(L, L); | ||
| 1872 | lua_pushstring(L, scpt); | ||
| 1873 | lua_settable(L, -3); /* C_HOOK[L] = script */ | ||
| 1874 | lua_sethook(L, Chook, mask, count); | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | |||
| 1878 | static int sethook (lua_State *L) { | ||
| 1879 | if (lua_isnoneornil(L, 1)) | ||
| 1880 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | ||
| 1881 | else { | ||
| 1882 | const char *scpt = luaL_checkstring(L, 1); | ||
| 1883 | const char *smask = luaL_checkstring(L, 2); | ||
| 1884 | int count = cast_int(luaL_optinteger(L, 3, 0)); | ||
| 1885 | int mask = 0; | ||
| 1886 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; | ||
| 1887 | if (strchr(smask, 'r')) mask |= LUA_MASKRET; | ||
| 1888 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; | ||
| 1889 | if (count > 0) mask |= LUA_MASKCOUNT; | ||
| 1890 | sethookaux(L, mask, count, scpt); | ||
| 1891 | } | ||
| 1892 | return 0; | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | |||
| 1896 | static int coresume (lua_State *L) { | ||
| 1897 | int status, nres; | ||
| 1898 | lua_State *co = lua_tothread(L, 1); | ||
| 1899 | luaL_argcheck(L, co, 1, "coroutine expected"); | ||
| 1900 | status = lua_resume(co, L, 0, &nres); | ||
| 1901 | if (status != LUA_OK && status != LUA_YIELD) { | ||
| 1902 | lua_pushboolean(L, 0); | ||
| 1903 | lua_insert(L, -2); | ||
| 1904 | return 2; /* return false + error message */ | ||
| 1905 | } | ||
| 1906 | else { | ||
| 1907 | lua_pushboolean(L, 1); | ||
| 1908 | return 1; | ||
| 1909 | } | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | /* }====================================================== */ | ||
| 1913 | |||
| 1914 | |||
| 1915 | |||
| 1916 | static const struct luaL_Reg tests_funcs[] = { | ||
| 1917 | {"checkmemory", lua_checkmemory}, | ||
| 1918 | {"closestate", closestate}, | ||
| 1919 | {"d2s", d2s}, | ||
| 1920 | {"doonnewstack", doonnewstack}, | ||
| 1921 | {"doremote", doremote}, | ||
| 1922 | {"gccolor", gc_color}, | ||
| 1923 | {"gcage", gc_age}, | ||
| 1924 | {"gcstate", gc_state}, | ||
| 1925 | {"pobj", gc_printobj}, | ||
| 1926 | {"getref", getref}, | ||
| 1927 | {"hash", hash_query}, | ||
| 1928 | {"log2", log2_aux}, | ||
| 1929 | {"limits", get_limits}, | ||
| 1930 | {"listcode", listcode}, | ||
| 1931 | {"printcode", printcode}, | ||
| 1932 | {"listk", listk}, | ||
| 1933 | {"listabslineinfo", listabslineinfo}, | ||
| 1934 | {"listlocals", listlocals}, | ||
| 1935 | {"loadlib", loadlib}, | ||
| 1936 | {"checkpanic", checkpanic}, | ||
| 1937 | {"newstate", newstate}, | ||
| 1938 | {"newuserdata", newuserdata}, | ||
| 1939 | {"num2int", num2int}, | ||
| 1940 | {"pushuserdata", pushuserdata}, | ||
| 1941 | {"querystr", string_query}, | ||
| 1942 | {"querytab", table_query}, | ||
| 1943 | {"ref", tref}, | ||
| 1944 | {"resume", coresume}, | ||
| 1945 | {"s2d", s2d}, | ||
| 1946 | {"sethook", sethook}, | ||
| 1947 | {"stacklevel", stacklevel}, | ||
| 1948 | {"testC", testC}, | ||
| 1949 | {"makeCfunc", makeCfunc}, | ||
| 1950 | {"totalmem", mem_query}, | ||
| 1951 | {"alloccount", alloc_count}, | ||
| 1952 | {"allocfailnext", alloc_failnext}, | ||
| 1953 | {"trick", settrick}, | ||
| 1954 | {"udataval", udataval}, | ||
| 1955 | {"unref", unref}, | ||
| 1956 | {"upvalue", upvalue}, | ||
| 1957 | {NULL, NULL} | ||
| 1958 | }; | ||
| 1959 | |||
| 1960 | |||
| 1961 | static void checkfinalmem (void) { | ||
| 1962 | lua_assert(l_memcontrol.numblocks == 0); | ||
| 1963 | lua_assert(l_memcontrol.total == 0); | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | |||
| 1967 | int luaB_opentests (lua_State *L) { | ||
| 1968 | void *ud; | ||
| 1969 | lua_Alloc f = lua_getallocf(L, &ud); | ||
| 1970 | lua_atpanic(L, &tpanic); | ||
| 1971 | lua_setwarnf(L, &warnf, L); | ||
| 1972 | lua_pushboolean(L, 0); | ||
| 1973 | lua_setglobal(L, "_WARN"); /* _WARN = false */ | ||
| 1974 | regcodes(L); | ||
| 1975 | atexit(checkfinalmem); | ||
| 1976 | lua_assert(f == debug_realloc && ud == cast_voidp(&l_memcontrol)); | ||
| 1977 | lua_setallocf(L, f, ud); /* exercise this function */ | ||
| 1978 | luaL_newlib(L, tests_funcs); | ||
| 1979 | return 1; | ||
| 1980 | } | ||
| 1981 | |||
| 1982 | #endif | ||
| 1983 | |||
