diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-04-28 16:04:36 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-04-28 16:04:36 -0300 |
| commit | e091a254dfe4521d837469d3ae7cc329e2df3376 (patch) | |
| tree | 7ee2f1c83a9a07500b6826bb55f0f1e977785d02 | |
| parent | 58c3aa8b5f51194980a9abf463a2648bb1413925 (diff) | |
| download | lua-e091a254dfe4521d837469d3ae7cc329e2df3376.tar.gz lua-e091a254dfe4521d837469d3ae7cc329e2df3376.tar.bz2 lua-e091a254dfe4521d837469d3ae7cc329e2df3376.zip | |
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.
| -rw-r--r-- | ldo.c | 26 | ||||
| -rw-r--r-- | lgc.c | 70 | ||||
| -rw-r--r-- | lgc.h | 9 | ||||
| -rw-r--r-- | lstate.c | 5 |
4 files changed, 63 insertions, 47 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.61 2009/04/17 22:00:01 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.62 2009/04/26 21:55:35 roberto Exp roberto $ |
| 3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -131,9 +131,12 @@ static void correctstack (lua_State *L, TValue *oldstack) { | |||
| 131 | 131 | ||
| 132 | void luaD_reallocstack (lua_State *L, int newsize) { | 132 | void luaD_reallocstack (lua_State *L, int newsize) { |
| 133 | TValue *oldstack = L->stack; | 133 | TValue *oldstack = L->stack; |
| 134 | int lim = L->stacksize; | ||
| 134 | int realsize = newsize + 1 + EXTRA_STACK; | 135 | int realsize = newsize + 1 + EXTRA_STACK; |
| 135 | lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); | 136 | lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); |
| 136 | luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); | 137 | luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); |
| 138 | for (; lim < realsize; lim++) | ||
| 139 | setnilvalue(L->stack + lim); /* erase new segment */ | ||
| 137 | L->stacksize = realsize; | 140 | L->stacksize = realsize; |
| 138 | L->stack_last = L->stack+newsize; | 141 | L->stack_last = L->stack+newsize; |
| 139 | correctstack(L, oldstack); | 142 | correctstack(L, oldstack); |
| @@ -182,14 +185,13 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { | |||
| 182 | int i; | 185 | int i; |
| 183 | int nfixargs = p->numparams; | 186 | int nfixargs = p->numparams; |
| 184 | StkId base, fixed; | 187 | StkId base, fixed; |
| 185 | for (; actual < nfixargs; ++actual) | 188 | lua_assert(actual >= nfixargs); |
| 186 | setnilvalue(L->top++); | ||
| 187 | /* move fixed parameters to final position */ | 189 | /* move fixed parameters to final position */ |
| 188 | fixed = L->top - actual; /* first fixed argument */ | 190 | fixed = L->top - actual; /* first fixed argument */ |
| 189 | base = L->top; /* final position of first argument */ | 191 | base = L->top; /* final position of first argument */ |
| 190 | for (i=0; i<nfixargs; i++) { | 192 | for (i=0; i<nfixargs; i++) { |
| 191 | setobjs2s(L, L->top++, fixed+i); | 193 | setobjs2s(L, L->top++, fixed + i); |
| 192 | setnilvalue(fixed+i); | 194 | setnilvalue(fixed + i); |
| 193 | } | 195 | } |
| 194 | return base; | 196 | return base; |
| 195 | } | 197 | } |
| @@ -227,17 +229,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 227 | L->ci->nresults = nresults; | 229 | L->ci->nresults = nresults; |
| 228 | if (!cl->isC) { /* Lua function? prepare its call */ | 230 | if (!cl->isC) { /* Lua function? prepare its call */ |
| 229 | CallInfo *ci; | 231 | CallInfo *ci; |
| 230 | StkId st, base; | 232 | int nparams, nargs; |
| 233 | StkId base; | ||
| 231 | Proto *p = cl->p; | 234 | Proto *p = cl->p; |
| 232 | luaD_checkstack(L, p->maxstacksize); | 235 | luaD_checkstack(L, p->maxstacksize); |
| 233 | func = restorestack(L, funcr); | 236 | func = restorestack(L, funcr); |
| 237 | nargs = cast_int(L->top - func) - 1; /* number of real arguments */ | ||
| 238 | nparams = p->numparams; /* number of expected parameters */ | ||
| 239 | for (; nargs < nparams; nargs++) | ||
| 240 | setnilvalue(L->top++); /* complete missing arguments */ | ||
| 234 | if (!p->is_vararg) /* no varargs? */ | 241 | if (!p->is_vararg) /* no varargs? */ |
| 235 | base = func + 1; | 242 | base = func + 1; |
| 236 | else { /* vararg function */ | 243 | else /* vararg function */ |
| 237 | int nargs = cast_int(L->top - func) - 1; | ||
| 238 | base = adjust_varargs(L, p, nargs); | 244 | base = adjust_varargs(L, p, nargs); |
| 239 | func = restorestack(L, funcr); /* previous call may change the stack */ | ||
| 240 | } | ||
| 241 | ci = next_ci(L); /* now 'enter' new function */ | 245 | ci = next_ci(L); /* now 'enter' new function */ |
| 242 | ci->func = func; | 246 | ci->func = func; |
| 243 | L->base = ci->base = base; | 247 | L->base = ci->base = base; |
| @@ -246,8 +250,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 246 | ci->u.l.savedpc = p->code; /* starting point */ | 250 | ci->u.l.savedpc = p->code; /* starting point */ |
| 247 | ci->u.l.tailcalls = 0; | 251 | ci->u.l.tailcalls = 0; |
| 248 | ci->callstatus = CIST_LUA; | 252 | ci->callstatus = CIST_LUA; |
| 249 | for (st = L->top; st < ci->top; st++) | ||
| 250 | setnilvalue(st); | ||
| 251 | L->top = ci->top; | 253 | L->top = ci->top; |
| 252 | if (L->hookmask & LUA_MASKCALL) { | 254 | if (L->hookmask & LUA_MASKCALL) { |
| 253 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ | 255 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.49 2009/03/10 17:14:37 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.50 2009/04/17 14:28:06 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -379,34 +379,17 @@ static void traverseclosure (global_State *g, Closure *cl) { | |||
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | 381 | ||
| 382 | static void checkstacksize (lua_State *L, StkId max) { | ||
| 383 | /* should not change the stack during an emergency gc cycle */ | ||
| 384 | if (G(L)->gckind == KGC_EMERGENCY) | ||
| 385 | return; /* do not touch the stack */ | ||
| 386 | else { | ||
| 387 | int s_used = cast_int(max - L->stack) + 1; /* part of stack in use */ | ||
| 388 | if (2*s_used < (L->stacksize - EXTRA_STACK)) | ||
| 389 | luaD_reallocstack(L, 2*s_used); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | |||
| 394 | static void traversestack (global_State *g, lua_State *L) { | 382 | static void traversestack (global_State *g, lua_State *L) { |
| 395 | StkId o, lim; | 383 | StkId o; |
| 396 | CallInfo *ci; | ||
| 397 | if (L->stack == NULL) | 384 | if (L->stack == NULL) |
| 398 | return; /* stack not completely built yet */ | 385 | return; /* stack not completely built yet */ |
| 399 | markvalue(g, gt(L)); | 386 | markvalue(g, gt(L)); /* mark global table */ |
| 400 | lim = L->top; | ||
| 401 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | ||
| 402 | lua_assert(ci->top <= L->stack_last); | ||
| 403 | if (lim < ci->top) lim = ci->top; | ||
| 404 | } | ||
| 405 | for (o = L->stack; o < L->top; o++) | 387 | for (o = L->stack; o < L->top; o++) |
| 406 | markvalue(g, o); | 388 | markvalue(g, o); |
| 407 | for (; o <= lim; o++) | 389 | if (g->gcstate == GCSatomic) { /* final traversal? */ |
| 408 | setnilvalue(o); | 390 | for (; o <= L->stack_last; o++) /* clear not-marked stack slice */ |
| 409 | checkstacksize(L, lim); | 391 | setnilvalue(o); |
| 392 | } | ||
| 410 | } | 393 | } |
| 411 | 394 | ||
| 412 | 395 | ||
| @@ -542,7 +525,35 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 542 | } | 525 | } |
| 543 | 526 | ||
| 544 | 527 | ||
| 528 | static int stackinuse (lua_State *L) { | ||
| 529 | CallInfo *ci; | ||
| 530 | StkId lim = L->top; | ||
| 531 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | ||
| 532 | lua_assert(ci->top <= L->stack_last); | ||
| 533 | if (lim < ci->top) lim = ci->top; | ||
| 534 | } | ||
| 535 | return cast_int(lim - L->stack) + 1; /* part of stack in use */ | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 545 | #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) | 539 | #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) |
| 540 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); | ||
| 541 | |||
| 542 | |||
| 543 | static void sweepthread (lua_State *L, lua_State *L1, int alive) { | ||
| 544 | if (L1->stack == NULL) return; /* stack not completely built yet */ | ||
| 545 | sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ | ||
| 546 | if (L1->nci < LUAI_MAXCALLS) /* not handling stack overflow? */ | ||
| 547 | luaE_freeCI(L1); /* free extra CallInfo slots */ | ||
| 548 | /* should not change the stack during an emergency gc cycle */ | ||
| 549 | if (alive && G(L)->gckind != KGC_EMERGENCY) { | ||
| 550 | int goodsize = 5 * stackinuse(L1) / 4 + LUA_MINSTACK; | ||
| 551 | if ((L1->stacksize - EXTRA_STACK) > goodsize) | ||
| 552 | luaD_reallocstack(L1, goodsize); | ||
| 553 | else | ||
| 554 | condhardstacktests(luaD_reallocstack(L, L1->stacksize - EXTRA_STACK - 1)); | ||
| 555 | } | ||
| 556 | } | ||
| 546 | 557 | ||
| 547 | 558 | ||
| 548 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | 559 | 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) { | |||
| 550 | global_State *g = G(L); | 561 | global_State *g = G(L); |
| 551 | int deadmask = otherwhite(g); | 562 | int deadmask = otherwhite(g); |
| 552 | while ((curr = *p) != NULL && count-- > 0) { | 563 | while ((curr = *p) != NULL && count-- > 0) { |
| 553 | if (ttisthread(gch(curr))) { | 564 | int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; |
| 554 | lua_State *L1 = gco2th(curr); | 565 | if (ttisthread(gch(curr))) |
| 555 | sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ | 566 | sweepthread(L, gco2th(curr), alive); |
| 556 | luaE_freeCI(L1); /* free extra CallInfo slots */ | 567 | if (alive) { |
| 557 | } | ||
| 558 | if ((gch(curr)->marked ^ WHITEBITS) & deadmask) { /* not dead? */ | ||
| 559 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); | 568 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); |
| 560 | makewhite(g, curr); /* make it white (for next cycle) */ | 569 | makewhite(g, curr); /* make it white (for next cycle) */ |
| 561 | p = &gch(curr)->next; | 570 | p = &gch(curr)->next; |
| @@ -704,6 +713,7 @@ static void atomic (lua_State *L) { | |||
| 704 | global_State *g = G(L); | 713 | global_State *g = G(L); |
| 705 | size_t udsize; /* total size of userdata to be finalized */ | 714 | size_t udsize; /* total size of userdata to be finalized */ |
| 706 | /* remark occasional upvalues of (maybe) dead threads */ | 715 | /* remark occasional upvalues of (maybe) dead threads */ |
| 716 | g->gcstate = GCSatomic; | ||
| 707 | remarkupvals(g); | 717 | remarkupvals(g); |
| 708 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ | 718 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ |
| 709 | propagateall(g); | 719 | propagateall(g); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.18 2008/02/19 18:55:09 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.19 2008/06/26 19:42:45 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -16,9 +16,10 @@ | |||
| 16 | */ | 16 | */ |
| 17 | #define GCSpause 0 | 17 | #define GCSpause 0 |
| 18 | #define GCSpropagate 1 | 18 | #define GCSpropagate 1 |
| 19 | #define GCSsweepstring 2 | 19 | #define GCSatomic 2 |
| 20 | #define GCSsweep 3 | 20 | #define GCSsweepstring 3 |
| 21 | #define GCSfinalize 4 | 21 | #define GCSsweep 4 |
| 22 | #define GCSfinalize 5 | ||
| 22 | 23 | ||
| 23 | 24 | ||
| 24 | #define issweep(g) (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) | 25 | #define issweep(g) (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.52 2009/04/17 14:40:13 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.53 2009/04/17 22:00:01 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -75,9 +75,12 @@ void luaE_freeCI (lua_State *L) { | |||
| 75 | 75 | ||
| 76 | 76 | ||
| 77 | static void stack_init (lua_State *L1, lua_State *L) { | 77 | static void stack_init (lua_State *L1, lua_State *L) { |
| 78 | int i; | ||
| 78 | /* initialize stack array */ | 79 | /* initialize stack array */ |
| 79 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); | 80 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); |
| 80 | L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; | 81 | L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; |
| 82 | for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) | ||
| 83 | setnilvalue(L1->stack + i); /* erase new stack */ | ||
| 81 | L1->top = L1->stack; | 84 | L1->top = L1->stack; |
| 82 | L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; | 85 | L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; |
| 83 | /* initialize first ci */ | 86 | /* initialize first ci */ |
