lua

A copy of the Lua development repository
Log | Files | Refs | README

commit e091a254dfe4521d837469d3ae7cc329e2df3376
parent 58c3aa8b5f51194980a9abf463a2648bb1413925
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Tue, 28 Apr 2009 16:04:12 -0300

new way to GC stacks: the entire stack must be correct all the times;
the 'dead' part of a stack (after the top) must have only nil's, so
that 'top' may go up without cleaning the stack.

Diffstat:
Mldo.c | 26++++++++++++++------------
Mlgc.c | 70++++++++++++++++++++++++++++++++++++++++------------------------------
Mlgc.h | 9+++++----
Mlstate.c | 5++++-
4 files changed, 63 insertions(+), 47 deletions(-)

diff --git a/ldo.c b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.61 2009/04/17 22:00:01 roberto Exp roberto $ +** $Id: ldo.c,v 2.62 2009/04/26 21:55:35 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -131,9 +131,12 @@ static void correctstack (lua_State *L, TValue *oldstack) { void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; + int lim = L->stacksize; int realsize = newsize + 1 + EXTRA_STACK; lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + for (; lim < realsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ L->stacksize = realsize; L->stack_last = L->stack+newsize; correctstack(L, oldstack); @@ -182,14 +185,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; StkId base, fixed; - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); + lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; i<nfixargs; i++) { - setobjs2s(L, L->top++, fixed+i); - setnilvalue(fixed+i); + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); } return base; } @@ -227,17 +229,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { L->ci->nresults = nresults; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; - StkId st, base; + int nparams, nargs; + StkId base; Proto *p = cl->p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); + nargs = cast_int(L->top - func) - 1; /* number of real arguments */ + nparams = p->numparams; /* number of expected parameters */ + for (; nargs < nparams; nargs++) + setnilvalue(L->top++); /* complete missing arguments */ if (!p->is_vararg) /* no varargs? */ base = func + 1; - else { /* vararg function */ - int nargs = cast_int(L->top - func) - 1; + else /* vararg function */ base = adjust_varargs(L, p, nargs); - func = restorestack(L, funcr); /* previous call may change the stack */ - } ci = next_ci(L); /* now 'enter' new function */ ci->func = func; L->base = ci->base = base; @@ -246,8 +250,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.tailcalls = 0; ci->callstatus = CIST_LUA; - for (st = L->top; st < ci->top; st++) - setnilvalue(st); L->top = ci->top; if (L->hookmask & LUA_MASKCALL) { ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ diff --git a/lgc.c b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.49 2009/03/10 17:14:37 roberto Exp roberto $ +** $Id: lgc.c,v 2.50 2009/04/17 14:28:06 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -379,34 +379,17 @@ static void traverseclosure (global_State *g, Closure *cl) { } -static void checkstacksize (lua_State *L, StkId max) { - /* should not change the stack during an emergency gc cycle */ - if (G(L)->gckind == KGC_EMERGENCY) - return; /* do not touch the stack */ - else { - int s_used = cast_int(max - L->stack) + 1; /* part of stack in use */ - if (2*s_used < (L->stacksize - EXTRA_STACK)) - luaD_reallocstack(L, 2*s_used); - } -} - - static void traversestack (global_State *g, lua_State *L) { - StkId o, lim; - CallInfo *ci; + StkId o; if (L->stack == NULL) return; /* stack not completely built yet */ - markvalue(g, gt(L)); - lim = L->top; - for (ci = L->ci; ci != NULL; ci = ci->previous) { - lua_assert(ci->top <= L->stack_last); - if (lim < ci->top) lim = ci->top; - } + markvalue(g, gt(L)); /* mark global table */ for (o = L->stack; o < L->top; o++) markvalue(g, o); - for (; o <= lim; o++) - setnilvalue(o); - checkstacksize(L, lim); + if (g->gcstate == GCSatomic) { /* final traversal? */ + for (; o <= L->stack_last; o++) /* clear not-marked stack slice */ + setnilvalue(o); + } } @@ -542,7 +525,35 @@ static void freeobj (lua_State *L, GCObject *o) { } +static int stackinuse (lua_State *L) { + CallInfo *ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + lua_assert(ci->top <= L->stack_last); + if (lim < ci->top) lim = ci->top; + } + return cast_int(lim - L->stack) + 1; /* part of stack in use */ +} + + #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); + + +static void sweepthread (lua_State *L, lua_State *L1, int alive) { + if (L1->stack == NULL) return; /* stack not completely built yet */ + sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ + if (L1->nci < LUAI_MAXCALLS) /* not handling stack overflow? */ + luaE_freeCI(L1); /* free extra CallInfo slots */ + /* should not change the stack during an emergency gc cycle */ + if (alive && G(L)->gckind != KGC_EMERGENCY) { + int goodsize = 5 * stackinuse(L1) / 4 + LUA_MINSTACK; + if ((L1->stacksize - EXTRA_STACK) > goodsize) + luaD_reallocstack(L1, goodsize); + else + condhardstacktests(luaD_reallocstack(L, L1->stacksize - EXTRA_STACK - 1)); + } +} static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { @@ -550,12 +561,10 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { - if (ttisthread(gch(curr))) { - lua_State *L1 = gco2th(curr); - sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ - luaE_freeCI(L1); /* free extra CallInfo slots */ - } - if ((gch(curr)->marked ^ WHITEBITS) & deadmask) { /* not dead? */ + int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; + if (ttisthread(gch(curr))) + sweepthread(L, gco2th(curr), alive); + if (alive) { lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = &gch(curr)->next; @@ -704,6 +713,7 @@ static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ /* remark occasional upvalues of (maybe) dead threads */ + g->gcstate = GCSatomic; remarkupvals(g); /* traverse objects cautch by write barrier and by 'remarkupvals' */ propagateall(g); diff --git a/lgc.h b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.18 2008/02/19 18:55:09 roberto Exp roberto $ +** $Id: lgc.h,v 2.19 2008/06/26 19:42:45 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -16,9 +16,10 @@ */ #define GCSpause 0 #define GCSpropagate 1 -#define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSatomic 2 +#define GCSsweepstring 3 +#define GCSsweep 4 +#define GCSfinalize 5 #define issweep(g) (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) diff --git a/lstate.c b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.52 2009/04/17 14:40:13 roberto Exp roberto $ +** $Id: lstate.c,v 2.53 2009/04/17 22:00:01 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -75,9 +75,12 @@ void luaE_freeCI (lua_State *L) { static void stack_init (lua_State *L1, lua_State *L) { + int i; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) + setnilvalue(L1->stack + i); /* erase new stack */ L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; /* initialize first ci */