Mercurial
comparison third_party/luajit/src/lj_state.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** State and stack handling. | |
| 3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h | |
| 4 ** | |
| 5 ** Portions taken verbatim or adapted from the Lua interpreter. | |
| 6 ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h | |
| 7 */ | |
| 8 | |
| 9 #define lj_state_c | |
| 10 #define LUA_CORE | |
| 11 | |
| 12 #include "lj_obj.h" | |
| 13 #include "lj_gc.h" | |
| 14 #include "lj_err.h" | |
| 15 #include "lj_buf.h" | |
| 16 #include "lj_str.h" | |
| 17 #include "lj_tab.h" | |
| 18 #include "lj_func.h" | |
| 19 #include "lj_meta.h" | |
| 20 #include "lj_state.h" | |
| 21 #include "lj_frame.h" | |
| 22 #if LJ_HASFFI | |
| 23 #include "lj_ctype.h" | |
| 24 #endif | |
| 25 #include "lj_trace.h" | |
| 26 #include "lj_dispatch.h" | |
| 27 #include "lj_vm.h" | |
| 28 #include "lj_prng.h" | |
| 29 #include "lj_lex.h" | |
| 30 #include "lj_alloc.h" | |
| 31 #include "luajit.h" | |
| 32 | |
| 33 /* -- Stack handling ------------------------------------------------------ */ | |
| 34 | |
| 35 /* Stack sizes. */ | |
| 36 #define LJ_STACK_MIN LUA_MINSTACK /* Min. stack size. */ | |
| 37 #define LJ_STACK_MAX LUAI_MAXSTACK /* Max. stack size. */ | |
| 38 #define LJ_STACK_START (2*LJ_STACK_MIN) /* Starting stack size. */ | |
| 39 #define LJ_STACK_MAXEX (LJ_STACK_MAX + 1 + LJ_STACK_EXTRA) | |
| 40 | |
| 41 /* Explanation of LJ_STACK_EXTRA: | |
| 42 ** | |
| 43 ** Calls to metamethods store their arguments beyond the current top | |
| 44 ** without checking for the stack limit. This avoids stack resizes which | |
| 45 ** would invalidate passed TValue pointers. The stack check is performed | |
| 46 ** later by the function header. This can safely resize the stack or raise | |
| 47 ** an error. Thus we need some extra slots beyond the current stack limit. | |
| 48 ** | |
| 49 ** Most metamethods need 4 slots above top (cont, mobj, arg1, arg2) plus | |
| 50 ** one extra slot if mobj is not a function. Only lj_meta_tset needs 5 | |
| 51 ** slots above top, but then mobj is always a function. So we can get by | |
| 52 ** with 5 extra slots. | |
| 53 ** LJ_FR2: We need 2 more slots for the frame PC and the continuation PC. | |
| 54 */ | |
| 55 | |
| 56 /* Resize stack slots and adjust pointers in state. */ | |
| 57 static void resizestack(lua_State *L, MSize n) | |
| 58 { | |
| 59 TValue *st, *oldst = tvref(L->stack); | |
| 60 ptrdiff_t delta; | |
| 61 MSize oldsize = L->stacksize; | |
| 62 MSize realsize = n + 1 + LJ_STACK_EXTRA; | |
| 63 GCobj *up; | |
| 64 lj_assertL((MSize)(tvref(L->maxstack)-oldst) == L->stacksize-LJ_STACK_EXTRA-1, | |
| 65 "inconsistent stack size"); | |
| 66 st = (TValue *)lj_mem_realloc(L, tvref(L->stack), | |
| 67 (MSize)(oldsize*sizeof(TValue)), | |
| 68 (MSize)(realsize*sizeof(TValue))); | |
| 69 setmref(L->stack, st); | |
| 70 delta = (char *)st - (char *)oldst; | |
| 71 setmref(L->maxstack, st + n); | |
| 72 while (oldsize < realsize) /* Clear new slots. */ | |
| 73 setnilV(st + oldsize++); | |
| 74 L->stacksize = realsize; | |
| 75 if ((size_t)(mref(G(L)->jit_base, char) - (char *)oldst) < oldsize) | |
| 76 setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + delta); | |
| 77 L->base = (TValue *)((char *)L->base + delta); | |
| 78 L->top = (TValue *)((char *)L->top + delta); | |
| 79 for (up = gcref(L->openupval); up != NULL; up = gcnext(up)) | |
| 80 setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta)); | |
| 81 } | |
| 82 | |
| 83 /* Relimit stack after error, in case the limit was overdrawn. */ | |
| 84 void lj_state_relimitstack(lua_State *L) | |
| 85 { | |
| 86 if (L->stacksize > LJ_STACK_MAXEX && L->top-tvref(L->stack) < LJ_STACK_MAX-1) | |
| 87 resizestack(L, LJ_STACK_MAX); | |
| 88 } | |
| 89 | |
| 90 /* Try to shrink the stack (called from GC). */ | |
| 91 void lj_state_shrinkstack(lua_State *L, MSize used) | |
| 92 { | |
| 93 if (L->stacksize > LJ_STACK_MAXEX) | |
| 94 return; /* Avoid stack shrinking while handling stack overflow. */ | |
| 95 if (4*used < L->stacksize && | |
| 96 2*(LJ_STACK_START+LJ_STACK_EXTRA) < L->stacksize && | |
| 97 /* Don't shrink stack of live trace. */ | |
| 98 (tvref(G(L)->jit_base) == NULL || obj2gco(L) != gcref(G(L)->cur_L))) | |
| 99 resizestack(L, L->stacksize >> 1); | |
| 100 } | |
| 101 | |
| 102 /* Try to grow stack. */ | |
| 103 void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need) | |
| 104 { | |
| 105 MSize n; | |
| 106 if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */ | |
| 107 lj_err_throw(L, LUA_ERRERR); | |
| 108 n = L->stacksize + need; | |
| 109 if (n > LJ_STACK_MAX) { | |
| 110 n += 2*LUA_MINSTACK; | |
| 111 } else if (n < 2*L->stacksize) { | |
| 112 n = 2*L->stacksize; | |
| 113 if (n >= LJ_STACK_MAX) | |
| 114 n = LJ_STACK_MAX; | |
| 115 } | |
| 116 resizestack(L, n); | |
| 117 if (L->stacksize >= LJ_STACK_MAXEX) | |
| 118 lj_err_msg(L, LJ_ERR_STKOV); | |
| 119 } | |
| 120 | |
| 121 void LJ_FASTCALL lj_state_growstack1(lua_State *L) | |
| 122 { | |
| 123 lj_state_growstack(L, 1); | |
| 124 } | |
| 125 | |
| 126 /* Allocate basic stack for new state. */ | |
| 127 static void stack_init(lua_State *L1, lua_State *L) | |
| 128 { | |
| 129 TValue *stend, *st = lj_mem_newvec(L, LJ_STACK_START+LJ_STACK_EXTRA, TValue); | |
| 130 setmref(L1->stack, st); | |
| 131 L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA; | |
| 132 stend = st + L1->stacksize; | |
| 133 setmref(L1->maxstack, stend - LJ_STACK_EXTRA - 1); | |
| 134 setthreadV(L1, st++, L1); /* Needed for curr_funcisL() on empty stack. */ | |
| 135 if (LJ_FR2) setnilV(st++); | |
| 136 L1->base = L1->top = st; | |
| 137 while (st < stend) /* Clear new slots. */ | |
| 138 setnilV(st++); | |
| 139 } | |
| 140 | |
| 141 /* -- State handling ------------------------------------------------------ */ | |
| 142 | |
| 143 /* Open parts that may cause memory-allocation errors. */ | |
| 144 static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud) | |
| 145 { | |
| 146 global_State *g = G(L); | |
| 147 UNUSED(dummy); | |
| 148 UNUSED(ud); | |
| 149 stack_init(L, L); | |
| 150 /* NOBARRIER: State initialization, all objects are white. */ | |
| 151 setgcref(L->env, obj2gco(lj_tab_new(L, 0, LJ_MIN_GLOBAL))); | |
| 152 settabV(L, registry(L), lj_tab_new(L, 0, LJ_MIN_REGISTRY)); | |
| 153 lj_str_init(L); | |
| 154 lj_meta_init(L); | |
| 155 lj_lex_init(L); | |
| 156 fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */ | |
| 157 g->gc.threshold = 4*g->gc.total; | |
| 158 lj_trace_initstate(g); | |
| 159 lj_err_verify(); | |
| 160 return NULL; | |
| 161 } | |
| 162 | |
| 163 static void close_state(lua_State *L) | |
| 164 { | |
| 165 global_State *g = G(L); | |
| 166 lj_func_closeuv(L, tvref(L->stack)); | |
| 167 lj_gc_freeall(g); | |
| 168 lj_assertG(gcref(g->gc.root) == obj2gco(L), | |
| 169 "main thread is not first GC object"); | |
| 170 lj_assertG(g->str.num == 0, "leaked %d strings", g->str.num); | |
| 171 lj_trace_freestate(g); | |
| 172 #if LJ_HASFFI | |
| 173 lj_ctype_freestate(g); | |
| 174 #endif | |
| 175 lj_str_freetab(g); | |
| 176 lj_buf_free(g, &g->tmpbuf); | |
| 177 lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); | |
| 178 #if LJ_64 | |
| 179 if (mref(g->gc.lightudseg, uint32_t)) { | |
| 180 MSize segnum = g->gc.lightudnum ? (2 << lj_fls(g->gc.lightudnum)) : 2; | |
| 181 lj_mem_freevec(g, mref(g->gc.lightudseg, uint32_t), segnum, uint32_t); | |
| 182 } | |
| 183 #endif | |
| 184 lj_assertG(g->gc.total == sizeof(GG_State), | |
| 185 "memory leak of %lld bytes", | |
| 186 (long long)(g->gc.total - sizeof(GG_State))); | |
| 187 #ifndef LUAJIT_USE_SYSMALLOC | |
| 188 if (g->allocf == lj_alloc_f) | |
| 189 lj_alloc_destroy(g->allocd); | |
| 190 else | |
| 191 #endif | |
| 192 g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0); | |
| 193 } | |
| 194 | |
| 195 #if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC)) | |
| 196 lua_State *lj_state_newstate(lua_Alloc allocf, void *allocd) | |
| 197 #else | |
| 198 LUA_API lua_State *lua_newstate(lua_Alloc allocf, void *allocd) | |
| 199 #endif | |
| 200 { | |
| 201 PRNGState prng; | |
| 202 GG_State *GG; | |
| 203 lua_State *L; | |
| 204 global_State *g; | |
| 205 /* We need the PRNG for the memory allocator, so initialize this first. */ | |
| 206 if (!lj_prng_seed_secure(&prng)) { | |
| 207 lj_assertX(0, "secure PRNG seeding failed"); | |
| 208 /* Can only return NULL here, so this errors with "not enough memory". */ | |
| 209 return NULL; | |
| 210 } | |
| 211 #ifndef LUAJIT_USE_SYSMALLOC | |
| 212 if (allocf == LJ_ALLOCF_INTERNAL) { | |
| 213 allocd = lj_alloc_create(&prng); | |
| 214 if (!allocd) return NULL; | |
| 215 allocf = lj_alloc_f; | |
| 216 } | |
| 217 #endif | |
| 218 GG = (GG_State *)allocf(allocd, NULL, 0, sizeof(GG_State)); | |
| 219 if (GG == NULL || !checkptrGC(GG)) return NULL; | |
| 220 memset(GG, 0, sizeof(GG_State)); | |
| 221 L = &GG->L; | |
| 222 g = &GG->g; | |
| 223 L->gct = ~LJ_TTHREAD; | |
| 224 L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED; /* Prevent free. */ | |
| 225 L->dummy_ffid = FF_C; | |
| 226 setmref(L->glref, g); | |
| 227 g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED; | |
| 228 g->strempty.marked = LJ_GC_WHITE0; | |
| 229 g->strempty.gct = ~LJ_TSTR; | |
| 230 g->allocf = allocf; | |
| 231 g->allocd = allocd; | |
| 232 g->prng = prng; | |
| 233 #ifndef LUAJIT_USE_SYSMALLOC | |
| 234 if (allocf == lj_alloc_f) { | |
| 235 lj_alloc_setprng(allocd, &g->prng); | |
| 236 } | |
| 237 #endif | |
| 238 setgcref(g->mainthref, obj2gco(L)); | |
| 239 setgcref(g->uvhead.prev, obj2gco(&g->uvhead)); | |
| 240 setgcref(g->uvhead.next, obj2gco(&g->uvhead)); | |
| 241 g->str.mask = ~(MSize)0; | |
| 242 setnilV(registry(L)); | |
| 243 setnilV(&g->nilnode.val); | |
| 244 setnilV(&g->nilnode.key); | |
| 245 #if !LJ_GC64 | |
| 246 setmref(g->nilnode.freetop, &g->nilnode); | |
| 247 #endif | |
| 248 lj_buf_init(NULL, &g->tmpbuf); | |
| 249 g->gc.state = GCSpause; | |
| 250 setgcref(g->gc.root, obj2gco(L)); | |
| 251 setmref(g->gc.sweep, &g->gc.root); | |
| 252 g->gc.total = sizeof(GG_State); | |
| 253 g->gc.pause = LUAI_GCPAUSE; | |
| 254 g->gc.stepmul = LUAI_GCMUL; | |
| 255 lj_dispatch_init((GG_State *)L); | |
| 256 L->status = LUA_ERRERR+1; /* Avoid touching the stack upon memory error. */ | |
| 257 if (lj_vm_cpcall(L, NULL, NULL, cpluaopen) != 0) { | |
| 258 /* Memory allocation error: free partial state. */ | |
| 259 close_state(L); | |
| 260 return NULL; | |
| 261 } | |
| 262 L->status = LUA_OK; | |
| 263 return L; | |
| 264 } | |
| 265 | |
| 266 static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud) | |
| 267 { | |
| 268 UNUSED(dummy); | |
| 269 UNUSED(ud); | |
| 270 lj_gc_finalize_cdata(L); | |
| 271 lj_gc_finalize_udata(L); | |
| 272 /* Frame pop omitted. */ | |
| 273 return NULL; | |
| 274 } | |
| 275 | |
| 276 LUA_API void lua_close(lua_State *L) | |
| 277 { | |
| 278 global_State *g = G(L); | |
| 279 int i; | |
| 280 L = mainthread(g); /* Only the main thread can be closed. */ | |
| 281 #if LJ_HASPROFILE | |
| 282 luaJIT_profile_stop(L); | |
| 283 #endif | |
| 284 setgcrefnull(g->cur_L); | |
| 285 lj_func_closeuv(L, tvref(L->stack)); | |
| 286 lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */ | |
| 287 #if LJ_HASJIT | |
| 288 G2J(g)->flags &= ~JIT_F_ON; | |
| 289 G2J(g)->state = LJ_TRACE_IDLE; | |
| 290 lj_dispatch_update(g); | |
| 291 #endif | |
| 292 for (i = 0;;) { | |
| 293 hook_enter(g); | |
| 294 L->status = LUA_OK; | |
| 295 L->base = L->top = tvref(L->stack) + 1 + LJ_FR2; | |
| 296 L->cframe = NULL; | |
| 297 if (lj_vm_cpcall(L, NULL, NULL, cpfinalize) == LUA_OK) { | |
| 298 if (++i >= 10) break; | |
| 299 lj_gc_separateudata(g, 1); /* Separate udata again. */ | |
| 300 if (gcref(g->gc.mmudata) == NULL) /* Until nothing is left to do. */ | |
| 301 break; | |
| 302 } | |
| 303 } | |
| 304 close_state(L); | |
| 305 } | |
| 306 | |
| 307 lua_State *lj_state_new(lua_State *L) | |
| 308 { | |
| 309 lua_State *L1 = lj_mem_newobj(L, lua_State); | |
| 310 L1->gct = ~LJ_TTHREAD; | |
| 311 L1->dummy_ffid = FF_C; | |
| 312 L1->status = LUA_OK; | |
| 313 L1->stacksize = 0; | |
| 314 setmref(L1->stack, NULL); | |
| 315 L1->cframe = NULL; | |
| 316 /* NOBARRIER: The lua_State is new (marked white). */ | |
| 317 setgcrefnull(L1->openupval); | |
| 318 setmrefr(L1->glref, L->glref); | |
| 319 setgcrefr(L1->env, L->env); | |
| 320 stack_init(L1, L); /* init stack */ | |
| 321 lj_assertL(iswhite(obj2gco(L1)), "new thread object is not white"); | |
| 322 return L1; | |
| 323 } | |
| 324 | |
| 325 void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L) | |
| 326 { | |
| 327 lj_assertG(L != mainthread(g), "free of main thread"); | |
| 328 if (obj2gco(L) == gcref(g->cur_L)) | |
| 329 setgcrefnull(g->cur_L); | |
| 330 lj_func_closeuv(L, tvref(L->stack)); | |
| 331 lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues"); | |
| 332 lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); | |
| 333 lj_mem_freet(g, L); | |
| 334 } | |
| 335 |