summaryrefslogtreecommitdiff
path: root/libs/luajit-cmake/luajit/src/lj_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/luajit-cmake/luajit/src/lj_state.c')
-rw-r--r--libs/luajit-cmake/luajit/src/lj_state.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/libs/luajit-cmake/luajit/src/lj_state.c b/libs/luajit-cmake/luajit/src/lj_state.c
new file mode 100644
index 0000000..0b9c46b
--- /dev/null
+++ b/libs/luajit-cmake/luajit/src/lj_state.c
@@ -0,0 +1,335 @@
+/*
+** State and stack handling.
+** Copyright (C) 2005-2022 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);
+}
+