From 55b16959717084884fd4a0cbae6d19e3786c20c7 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Tue, 8 Dec 2009 19:46:35 +0100 Subject: RELEASE LuaJIT-2.0.0-beta1 --- src/lj_state.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/lj_state.c (limited to 'src/lj_state.c') diff --git a/src/lj_state.c b/src/lj_state.c new file mode 100644 index 00000000..b4bc7a0c --- /dev/null +++ b/src/lj_state.c @@ -0,0 +1,255 @@ +/* +** State and stack handling. +** Copyright (C) 2005-2009 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_str.h" +#include "lj_tab.h" +#include "lj_func.h" +#include "lj_meta.h" +#include "lj_state.h" +#include "lj_frame.h" +#include "lj_trace.h" +#include "lj_dispatch.h" +#include "lj_vm.h" +#include "lj_lex.h" +#include "lj_alloc.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 call gate. 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. +*/ + +/* Resize stack slots and adjust pointers in state. */ +static void resizestack(lua_State *L, MSize n) +{ + TValue *oldst = L->stack; + ptrdiff_t delta; + MSize realsize = n + 1 + LJ_STACK_EXTRA; + GCobj *up; + lua_assert((MSize)(L->maxstack-L->stack) == L->stacksize-LJ_STACK_EXTRA-1); + lj_mem_reallocvec(L, L->stack, L->stacksize, realsize, TValue); + delta = (char *)L->stack - (char *)oldst; + L->maxstack = L->stack + n; + L->stacksize = realsize; + L->base = (TValue *)((char *)L->base + delta); + L->top = (TValue *)((char *)L->top + delta); + for (up = gcref(L->openupval); up != NULL; up = gcnext(up)) + gco2uv(up)->v = (TValue *)((char *)gco2uv(up)->v + delta); + if (obj2gco(L) == gcref(G(L)->jit_L)) + setmref(G(L)->jit_base, mref(G(L)->jit_base, char) + 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 - 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 && + obj2gco(L) != gcref(G(L)->jit_L)) /* Don't shrink stack of live trace. */ + resizestack(L, L->stacksize >> 1); +} + +/* Try to grow stack. */ +void lj_state_growstack(lua_State *L, MSize need) +{ + if (L->stacksize > LJ_STACK_MAXEX) /* overflow while handling overflow? */ + lj_err_throw(L, LUA_ERRERR); + resizestack(L, L->stacksize + (need > L->stacksize ? need : L->stacksize)); + if (L->stacksize > LJ_STACK_MAXEX) { + if (curr_funcisL(L)) { /* Clear slots of incomplete Lua frame. */ + TValue *top = curr_topL(L); + while (--top >= L->top) setnilV(top); + } + lj_err_msg(L, LJ_ERR_STKOV); /* ... to allow L->top = curr_topL(L). */ + } +} + +void 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) +{ + L1->stack = lj_mem_newvec(L, LJ_STACK_START + LJ_STACK_EXTRA, TValue); + L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA; + L1->top = L1->stack; + L1->maxstack = L1->stack+(L1->stacksize - LJ_STACK_EXTRA)-1; + setthreadV(L1, L1->top, L1); /* needed for curr_funcisL() on empty stack */ + setnilV(L1->top); /* but clear its type */ + L1->base = ++L1->top; +} + +/* -- 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_resize(L, LJ_MIN_STRTAB-1); + 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; + return NULL; +} + +static void close_state(lua_State *L) +{ + global_State *g = G(L); +#ifndef LUAJIT_USE_SYSMALLOC + if (g->allocf == lj_alloc_f) { + lj_alloc_destroy(g->allocd); + } else +#endif + { + lj_func_closeuv(L, L->stack); + lj_gc_freeall(g); + lua_assert(gcref(g->gc.root) == obj2gco(L)); + lua_assert(g->strnum == 0); + lj_trace_freestate(g); + lj_mem_freevec(g, g->strhash, g->strmask+1, GCstr *); + lj_str_freebuf(g, &g->tmpbuf); + lj_mem_freevec(g, L->stack, L->stacksize, TValue); + lua_assert(g->gc.total == sizeof(GG_State)); + g->allocf(g->allocd, G2GG(g), sizeof(GG_State), 0); + } +} + +LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud) +{ + GG_State *GG = cast(GG_State *, f(ud, NULL, 0, sizeof(GG_State))); + lua_State *L = &GG->L; + global_State *g = &GG->g; + if (GG == NULL) return NULL; + memset(GG, 0, sizeof(GG_State)); + 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->allocf = f; + g->allocd = ud; + setgcref(g->mainthref, obj2gco(L)); + setgcref(g->uvhead.prev, obj2gco(&g->uvhead)); + setgcref(g->uvhead.next, obj2gco(&g->uvhead)); + g->strmask = ~(MSize)0; + setnilV(registry(L)); + setnilV(&g->nilnode.val); + setnilV(&g->nilnode.key); + lj_str_initbuf(L, &g->tmpbuf); + g->gc.state = GCSpause; + setgcref(g->gc.root, obj2gco(L)); + 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, cpluaopen, NULL, NULL) != 0) { + /* Memory allocation error: free partial state. */ + close_state(L); + return NULL; + } + L->status = 0; + return L; +} + +static TValue *cpfinalize(lua_State *L, lua_CFunction dummy, void *ud) +{ + UNUSED(dummy); + UNUSED(ud); + lj_gc_finalizeudata(L); + /* Frame pop omitted. */ + return NULL; +} + +LUA_API void lua_close(lua_State *L) +{ + global_State *g = G(L); + L = mainthread(g); /* Only the main thread can be closed. */ + lj_func_closeuv(L, 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 + do { + hook_enter(g); + L->status = 0; + L->cframe = NULL; + L->base = L->top = L->stack + 1; + } while (lj_vm_cpcall(L, cpfinalize, NULL, NULL) != 0); + 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 = 0; + L1->stacksize = 0; + 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 */ + lua_assert(iswhite(obj2gco(L1))); + return L1; +} + +void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L) +{ + lua_assert(L != mainthread(g)); + lj_func_closeuv(L, L->stack); + lua_assert(gcref(L->openupval) == NULL); + lj_mem_freevec(g, L->stack, L->stacksize, TValue); + lj_mem_freet(g, L); +} + -- cgit v1.2.3-55-g6feb