فهرست منبع

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.

Roberto Ierusalimschy 16 سال پیش
والد
کامیت
e091a254df
4فایلهای تغییر یافته به همراه63 افزوده شده و 47 حذف شده
  1. 14 12
      ldo.c
  2. 40 30
      lgc.c
  3. 5 4
      lgc.h
  4. 4 1
      lstate.c

+ 14 - 12
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 */

+ 40 - 30
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);

+ 5 - 4
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)

+ 4 - 1
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 */