Mercurial
view third_party/luajit/src/lj_state.c @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 94705b5986b3 |
| children |
line wrap: on
line source
/* ** State and stack handling. ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h ** ** Portions taken verbatim or adapted from the Lua interpreter. ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h */ #define lj_state_c #define LUA_CORE #include "lj_obj.h" #include "lj_gc.h" #include "lj_err.h" #include "lj_buf.h" #include "lj_str.h" #include "lj_tab.h" #include "lj_func.h" #include "lj_meta.h" #include "lj_state.h" #include "lj_frame.h" #if LJ_HASFFI #include "lj_ctype.h" #endif #include "lj_trace.h" #include "lj_dispatch.h" #include "lj_vm.h" #include "lj_prng.h" #include "lj_lex.h" #include "lj_alloc.h" #include "luajit.h" /* -- Stack handling ------------------------------------------------------ */ /* Stack sizes. */ #define LJ_STACK_MIN LUA_MINSTACK /* Min. stack size. */ #define LJ_STACK_MAX LUAI_MAXSTACK /* Max. stack size. */ #define LJ_STACK_START (2*LJ_STACK_MIN) /* Starting stack size. */ #define LJ_STACK_MAXEX (LJ_STACK_MAX + 1 + LJ_STACK_EXTRA) /* Explanation of LJ_STACK_EXTRA: ** ** Calls to metamethods store their arguments beyond the current top ** without checking for the stack limit. This avoids stack resizes which ** would invalidate passed TValue pointers. The stack check is performed ** later by the function header. This can safely resize the stack or raise ** an error. Thus we need some extra slots beyond the current stack limit. ** ** Most metamethods need 4 slots above top (cont, mobj, arg1, arg2) plus ** one extra slot if mobj is not a function. Only lj_meta_tset needs 5 ** slots above top, but then mobj is always a function. So we can get by ** with 5 extra slots. ** LJ_FR2: We need 2 more slots for the frame PC and the continuation PC. */ /* Resize stack slots and adjust pointers in state. */ static void resizestack(lua_State *L, MSize n) { TValue *st, *oldst = tvref(L->stack); ptrdiff_t delta; MSize oldsize = L->stacksize; MSize realsize = n + 1 + LJ_STACK_EXTRA; GCobj *up; lj_assertL((MSize)(tvref(L->maxstack)-oldst) == L->stacksize-LJ_STACK_EXTRA-1, "inconsistent stack size"); st = (TValue *)lj_mem_realloc(L, tvref(L->stack), (MSize)(oldsize*sizeof(TValue)), (MSize)(realsize*sizeof(TValue))); setmref(L->stack, st); delta = (char *)st - (char *)oldst; setmref(L->maxstack, st + n); while (oldsize < realsize) /* Clear new slots. */ setnilV(st + oldsize++); L->stacksize = realsize; if ((size_t)(mref(G(L)->jit_base, char) - (char *)oldst) < oldsize) setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + delta); L->base = (TValue *)((char *)L->base + delta); L->top = (TValue *)((char *)L->top + delta); for (up = gcref(L->openupval); up != NULL; up = gcnext(up)) setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta)); } /* Relimit stack after error, in case the limit was overdrawn. */ void lj_state_relimitstack(lua_State *L) { if (L->stacksize > LJ_STACK_MAXEX && L->top-tvref(L->stack) < LJ_STACK_MAX-1) resizestack(L, LJ_STACK_MAX); } /* Try to shrink the stack (called from GC). */ void lj_state_shrinkstack(lua_State *L, MSize used) { if (L->stacksize > LJ_STACK_MAXEX) return; /* Avoid stack shrinking while handling stack overflow. */ if (4*used < L->stacksize && 2*(LJ_STACK_START+LJ_STACK_EXTRA) < L->stacksize && /* Don't shrink stack of live trace. */ (tvref(G(L)->jit_base) == NULL || obj2gco(L) != gcref(G(L)->cur_L))) resizestack(L, L->stacksize >> 1); } /* Try to grow stack. */ void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need) { MSize n; if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */ lj_err_throw(L, LUA_ERRERR); n = L->stacksize + need; if (n > LJ_STACK_MAX) { n += 2*LUA_MINSTACK; } else if (n < 2*L->stacksize) { n = 2*L->stacksize; if (n >= LJ_STACK_MAX) n = LJ_STACK_MAX; } resizestack(L, n); if (L->stacksize >= LJ_STACK_MAXEX) lj_err_msg(L, LJ_ERR_STKOV); } void LJ_FASTCALL lj_state_growstack1(lua_State *L) { lj_state_growstack(L, 1); } /* Allocate basic stack for new state. */ static void stack_init(lua_State *L1, lua_State *L) { TValue *stend, *st = lj_mem_newvec(L, LJ_STACK_START+LJ_STACK_EXTRA, TValue); setmref(L1->stack, st); L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA; stend = st + L1->stacksize; setmref(L1->maxstack, stend - LJ_STACK_EXTRA - 1); setthreadV(L1, st++, L1); /* Needed for curr_funcisL() on empty stack. */ if (LJ_FR2) setnilV(st++); L1->base = L1->top = st; while (st < stend) /* Clear new slots. */ setnilV(st++); } /* -- State handling ------------------------------------------------------ */ /* Open parts that may cause memory-allocation errors. */ static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud) { global_State *g = G(L); UNUSED(dummy); UNUSED(ud); stack_init(L, L); /* NOBARRIER: State initialization, all objects are white. */ setgcref(L->env, obj2gco(lj_tab_new(L, 0, LJ_MIN_GLOBAL))); settabV(L, registry(L), lj_tab_new(L, 0, LJ_MIN_REGISTRY)); lj_str_init(L); lj_meta_init(L); lj_lex_init(L); fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */ g->gc.threshold = 4*g->gc.total; lj_trace_initstate(g); lj_err_verify(); return NULL; } static void close_state(lua_State *L) { global_State *g = G(L); lj_func_closeuv(L, tvref(L->stack)); lj_gc_freeall(g); lj_assertG(gcref(g->gc.root) == obj2gco(L), "main thread is not first GC object"); lj_assertG(g->str.num == 0, "leaked %d strings", g->str.num); lj_trace_freestate(g); #if LJ_HASFFI lj_ctype_freestate(g); #endif lj_str_freetab(g); lj_buf_free(g, &g->tmpbuf); lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); #if LJ_64 if (mref(g->gc.lightudseg, uint32_t)) { MSize segnum = g->gc.lightudnum ? (2 << lj_fls(g->gc.lightudnum)) : 2; lj_mem_freevec(g, mref(g->gc.lightudseg, uint32_t), segnum, uint32_t); } #endif lj_assertG(g->gc.total == sizeof(GG_State), "memory leak of %lld bytes", (long long)(g->gc.total - sizeof(GG_State))); #ifndef LUAJIT_USE_SYSMALLOC if (g->allocf == lj_alloc_f) lj_alloc_destroy(g->allocd); else #endif g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0); } #if LJ_64 && !LJ_GC64 && !(defined(LUAJIT_USE_VALGRIND) && defined(LUAJIT_USE_SYSMALLOC)) lua_State *lj_state_newstate(lua_Alloc allocf, void *allocd) #else LUA_API lua_State *lua_newstate(lua_Alloc allocf, void *allocd) #endif { PRNGState prng; GG_State *GG; lua_State *L; global_State *g; /* We need the PRNG for the memory allocator, so initialize this first. */ if (!lj_prng_seed_secure(&prng)) { lj_assertX(0, "secure PRNG seeding failed"); /* Can only return NULL here, so this errors with "not enough memory". */ return NULL; } #ifndef LUAJIT_USE_SYSMALLOC if (allocf == LJ_ALLOCF_INTERNAL) { allocd = lj_alloc_create(&prng); if (!allocd) return NULL; allocf = lj_alloc_f; } #endif GG = (GG_State *)allocf(allocd, NULL, 0, sizeof(GG_State)); if (GG == NULL || !checkptrGC(GG)) return NULL; memset(GG, 0, sizeof(GG_State)); L = &GG->L; g = &GG->g; L->gct = ~LJ_TTHREAD; L->marked = LJ_GC_WHITE0 | LJ_GC_FIXED | LJ_GC_SFIXED; /* Prevent free. */ L->dummy_ffid = FF_C; setmref(L->glref, g); g->gc.currentwhite = LJ_GC_WHITE0 | LJ_GC_FIXED; g->strempty.marked = LJ_GC_WHITE0; g->strempty.gct = ~LJ_TSTR; g->allocf = allocf; g->allocd = allocd; g->prng = prng; #ifndef LUAJIT_USE_SYSMALLOC if (allocf == lj_alloc_f) { lj_alloc_setprng(allocd, &g->prng); } #endif setgcref(g->mainthref, obj2gco(L)); setgcref(g->uvhead.prev, obj2gco(&g->uvhead)); setgcref(g->uvhead.next, obj2gco(&g->uvhead)); g->str.mask = ~(MSize)0; setnilV(registry(L)); setnilV(&g->nilnode.val); setnilV(&g->nilnode.key); #if !LJ_GC64 setmref(g->nilnode.freetop, &g->nilnode); #endif lj_buf_init(NULL, &g->tmpbuf); g->gc.state = GCSpause; setgcref(g->gc.root, obj2gco(L)); setmref(g->gc.sweep, &g->gc.root); g->gc.total = sizeof(GG_State); g->gc.pause = LUAI_GCPAUSE; g->gc.stepmul = LUAI_GCMUL; lj_dispatch_init((GG_State *)L); L->status = LUA_ERRERR+1; /* Avoid touching the stack upon memory error. */ if (lj_vm_cpcall(L, NULL, NULL, cpluaopen) != 0) { /* Memory allocation error: free partial state. */ close_state(L); return NULL; } L->status = LUA_OK; return L; } static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud) { UNUSED(dummy); UNUSED(ud); lj_gc_finalize_cdata(L); lj_gc_finalize_udata(L); /* Frame pop omitted. */ return NULL; } LUA_API void lua_close(lua_State *L) { global_State *g = G(L); int i; L = mainthread(g); /* Only the main thread can be closed. */ #if LJ_HASPROFILE luaJIT_profile_stop(L); #endif setgcrefnull(g->cur_L); lj_func_closeuv(L, tvref(L->stack)); lj_gc_separateudata(g, 1); /* Separate udata which have GC metamethods. */ #if LJ_HASJIT G2J(g)->flags &= ~JIT_F_ON; G2J(g)->state = LJ_TRACE_IDLE; lj_dispatch_update(g); #endif for (i = 0;;) { hook_enter(g); L->status = LUA_OK; L->base = L->top = tvref(L->stack) + 1 + LJ_FR2; L->cframe = NULL; if (lj_vm_cpcall(L, NULL, NULL, cpfinalize) == LUA_OK) { if (++i >= 10) break; lj_gc_separateudata(g, 1); /* Separate udata again. */ if (gcref(g->gc.mmudata) == NULL) /* Until nothing is left to do. */ break; } } close_state(L); } lua_State *lj_state_new(lua_State *L) { lua_State *L1 = lj_mem_newobj(L, lua_State); L1->gct = ~LJ_TTHREAD; L1->dummy_ffid = FF_C; L1->status = LUA_OK; L1->stacksize = 0; setmref(L1->stack, NULL); L1->cframe = NULL; /* NOBARRIER: The lua_State is new (marked white). */ setgcrefnull(L1->openupval); setmrefr(L1->glref, L->glref); setgcrefr(L1->env, L->env); stack_init(L1, L); /* init stack */ lj_assertL(iswhite(obj2gco(L1)), "new thread object is not white"); return L1; } void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L) { lj_assertG(L != mainthread(g), "free of main thread"); if (obj2gco(L) == gcref(g->cur_L)) setgcrefnull(g->cur_L); lj_func_closeuv(L, tvref(L->stack)); lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues"); lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); lj_mem_freet(g, L); }