mikepaul-LuaJIT/src/lj_state.c

280 lines
8.3 KiB
C
Raw Normal View History

2009-12-08 18:46:35 +00:00
/*
** State and stack handling.
2010-01-09 13:28:11 +00:00
** Copyright (C) 2005-2010 Mike Pall. See Copyright Notice in luajit.h
2009-12-08 18:46:35 +00:00
**
** 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"
#if LJ_HASJIT
#include "lj_mcode.h"
#endif
2009-12-08 18:46:35 +00:00
#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 function header. This can safely resize the stack or raise
** an error. Thus we need some extra slots beyond the current stack limit.
2009-12-08 18:46:35 +00:00
**
** 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 *st, *oldst = L->stack;
2009-12-08 18:46:35 +00:00
ptrdiff_t delta;
MSize oldsize = L->stacksize;
2009-12-08 18:46:35 +00:00
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);
st = L->stack;
delta = (char *)st - (char *)oldst;
L->maxstack = st + n;
while (oldsize < realsize) /* Clear new slots. */
setnilV(st + oldsize++);
2009-12-08 18:46:35 +00:00
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))
setmref(gco2uv(up)->v, (TValue *)((char *)uvval(gco2uv(up)) + delta));
2009-12-08 18:46:35 +00:00
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_FASTCALL lj_state_growstack(lua_State *L, MSize need)
2009-12-08 18:46:35 +00:00
{
2010-03-01 04:51:04 +00:00
MSize n;
if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */
2009-12-08 18:46:35 +00:00
lj_err_throw(L, LUA_ERRERR);
2010-03-01 04:51:04 +00:00
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);
2009-12-08 18:46:35 +00:00
}
void LJ_FASTCALL lj_state_growstack1(lua_State *L)
2009-12-08 18:46:35 +00:00
{
lj_state_growstack(L, 1);
}
/* Allocate basic stack for new state. */
static void stack_init(lua_State *L1, lua_State *L)
{
TValue *st, *stend;
L1->stack = st = lj_mem_newvec(L, LJ_STACK_START + LJ_STACK_EXTRA, TValue);
2009-12-08 18:46:35 +00:00
L1->stacksize = LJ_STACK_START + LJ_STACK_EXTRA;
stend = st + L1->stacksize;
L1->maxstack = stend - LJ_STACK_EXTRA - 1;
L1->base = L1->top = st+1;
setthreadV(L1, st, L1); /* Needed for curr_funcisL() on empty stack. */
while (st < stend) /* Clear new slots. */
setnilV(st++);
2009-12-08 18:46:35 +00:00
}
/* -- 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;
lj_trace_initstate(g);
2009-12-08 18:46:35 +00:00
return NULL;
}
static void close_state(lua_State *L)
{
global_State *g = G(L);
#ifndef LUAJIT_USE_SYSMALLOC
if (g->allocf == lj_alloc_f) {
#if LJ_HASJIT
lj_mcode_free(G2J(g));
#endif
2009-12-08 18:46:35 +00:00
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, GCRef);
2009-12-08 18:46:35 +00:00
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);
2009-12-08 18:46:35 +00:00
}
}
#if LJ_64
lua_State *lj_state_newstate(lua_Alloc f, void *ud)
#else
2009-12-08 18:46:35 +00:00
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
#endif
2009-12-08 18:46:35 +00:00
{
GG_State *GG = cast(GG_State *, f(ud, NULL, 0, sizeof(GG_State)));
2009-12-08 18:46:35 +00:00
lua_State *L = &GG->L;
global_State *g = &GG->g;
if (GG == NULL || !checkptr32(GG)) return NULL;
2009-12-08 18:46:35 +00:00
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;
2010-07-21 20:53:27 +00:00
g->strempty.marked = LJ_GC_WHITE0;
g->strempty.gct = ~LJ_TSTR;
2009-12-08 18:46:35 +00:00
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);
setmref(g->nilnode.freetop, &g->nilnode);
2009-12-08 18:46:35 +00:00
lj_str_initbuf(L, &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);
2009-12-08 18:46:35 +00:00
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) {
2009-12-08 18:46:35 +00:00
/* 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, NULL, NULL, cpfinalize) != 0);
2009-12-08 18:46:35 +00:00
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);
}