diff options
-rw-r--r-- | lfunc.c | 16 | ||||
-rw-r--r-- | lfunc.h | 6 | ||||
-rw-r--r-- | lgc.c | 45 | ||||
-rw-r--r-- | lstate.c | 4 | ||||
-rw-r--r-- | lstate.h | 4 |
5 files changed, 58 insertions, 17 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.c,v 2.39 2014/02/13 12:11:34 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.40 2014/02/15 13:12:01 roberto Exp roberto $ |
3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -35,7 +35,9 @@ Closure *luaF_newLclosure (lua_State *L, int n) { | |||
35 | return c; | 35 | return c; |
36 | } | 36 | } |
37 | 37 | ||
38 | 38 | /* | |
39 | ** fill a closure with new closed upvalues | ||
40 | */ | ||
39 | void luaF_initupvals (lua_State *L, LClosure *cl) { | 41 | void luaF_initupvals (lua_State *L, LClosure *cl) { |
40 | int i; | 42 | int i; |
41 | for (i = 0; i < cl->nupvalues; i++) { | 43 | for (i = 0; i < cl->nupvalues; i++) { |
@@ -52,18 +54,24 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
52 | UpVal **pp = &L->openupval; | 54 | UpVal **pp = &L->openupval; |
53 | UpVal *p; | 55 | UpVal *p; |
54 | UpVal *uv; | 56 | UpVal *uv; |
57 | lua_assert(isintwups(L) || L->openupval == NULL); | ||
55 | while (*pp != NULL && (p = *pp)->v >= level) { | 58 | while (*pp != NULL && (p = *pp)->v >= level) { |
56 | lua_assert(upisopen(p)); | 59 | lua_assert(upisopen(p)); |
57 | if (p->v == level) /* found a corresponding upvalue? */ | 60 | if (p->v == level) /* found a corresponding upvalue? */ |
58 | return p; /* return it */ | 61 | return p; /* return it */ |
59 | pp = &p->u.open.next; | 62 | pp = &p->u.open.next; |
60 | } | 63 | } |
61 | /* not found: create a new one */ | 64 | /* not found: create a new upvalue */ |
62 | uv = luaM_new(L, UpVal); | 65 | uv = luaM_new(L, UpVal); |
63 | uv->refcount = 0; | 66 | uv->refcount = 0; |
64 | uv->u.open.next = *pp; | 67 | uv->u.open.next = *pp; /* link it to list of open upvalues */ |
68 | uv->u.open.touched = 1; | ||
65 | *pp = uv; | 69 | *pp = uv; |
66 | uv->v = level; /* current value lives in the stack */ | 70 | uv->v = level; /* current value lives in the stack */ |
71 | if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ | ||
72 | L->twups = G(L)->twups; /* link it to the list */ | ||
73 | G(L)->twups = L; | ||
74 | } | ||
67 | return uv; | 75 | return uv; |
68 | } | 76 | } |
69 | 77 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.h,v 2.11 2013/09/11 15:17:00 roberto Exp roberto $ | 2 | ** $Id: lfunc.h,v 2.12 2014/02/15 13:12:01 roberto Exp roberto $ |
3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -18,6 +18,10 @@ | |||
18 | cast(int, sizeof(TValue *)*((n)-1))) | 18 | cast(int, sizeof(TValue *)*((n)-1))) |
19 | 19 | ||
20 | 20 | ||
21 | /* test whether thread is in 'twups' list */ | ||
22 | #define isintwups(L) (L->twups != L) | ||
23 | |||
24 | |||
21 | /* | 25 | /* |
22 | ** Upvalues for Lua closures | 26 | ** Upvalues for Lua closures |
23 | */ | 27 | */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.174 2014/02/14 16:43:14 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.175 2014/02/15 13:12:01 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 | */ |
@@ -23,6 +23,11 @@ | |||
23 | #include "ltm.h" | 23 | #include "ltm.h" |
24 | 24 | ||
25 | 25 | ||
26 | /* | ||
27 | ** internal state for collector while inside the atomic phase. The | ||
28 | ** collector should never be in this state while running regular code. | ||
29 | */ | ||
30 | #define GCSinsideatomic (GCSpause + 1) | ||
26 | 31 | ||
27 | /* | 32 | /* |
28 | ** cost of sweeping one element (the size of a small object divided | 33 | ** cost of sweeping one element (the size of a small object divided |
@@ -288,15 +293,21 @@ static void markbeingfnz (global_State *g) { | |||
288 | /* | 293 | /* |
289 | ** Mark all values stored in marked open upvalues from non-marked threads. | 294 | ** Mark all values stored in marked open upvalues from non-marked threads. |
290 | ** (Values from marked threads were already marked when traversing the | 295 | ** (Values from marked threads were already marked when traversing the |
291 | ** thread.) | 296 | ** thread.) Remove from the list threads that no longer have upvalues and |
297 | ** not-marked threads. | ||
292 | */ | 298 | */ |
293 | static void remarkupvals (global_State *g) { | 299 | static void remarkupvals (global_State *g) { |
294 | GCObject *thread = g->mainthread->next; | 300 | lua_State *thread; |
295 | for (; thread != NULL; thread = gch(thread)->next) { | 301 | lua_State **p = &g->twups; |
296 | lua_assert(!isblack(thread)); /* threads are never black */ | 302 | while ((thread = *p) != NULL) { |
297 | if (!isgray(thread)) { /* dead thread? */ | 303 | lua_assert(!isblack(obj2gco(thread))); /* threads are never black */ |
298 | UpVal *uv = gco2th(thread)->openupval; | 304 | if (isgray(obj2gco(thread)) && thread->openupval != NULL) |
299 | for (; uv != NULL; uv = uv->u.open.next) { | 305 | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
306 | else { /* thread is not marked or without upvalues */ | ||
307 | UpVal *uv; | ||
308 | *p = thread->twups; /* remove thread from the list */ | ||
309 | thread->twups = thread; /* mark that it is out of list */ | ||
310 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | ||
300 | if (uv->u.open.touched) { | 311 | if (uv->u.open.touched) { |
301 | markvalue(g, uv->v); /* remark upvalue's value */ | 312 | markvalue(g, uv->v); /* remark upvalue's value */ |
302 | uv->u.open.touched = 0; | 313 | uv->u.open.touched = 0; |
@@ -459,13 +470,19 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
459 | return sizeCclosure(cl->nupvalues); | 470 | return sizeCclosure(cl->nupvalues); |
460 | } | 471 | } |
461 | 472 | ||
473 | /* | ||
474 | ** open upvalues point to values in a thread, so those values should | ||
475 | ** be marked when the thread is traversed except in the atomic phase | ||
476 | ** (because then the value cannot be changed by the thread and the | ||
477 | ** thread may not be traversed again) | ||
478 | */ | ||
462 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 479 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
463 | int i; | 480 | int i; |
464 | markobject(g, cl->p); /* mark its prototype */ | 481 | markobject(g, cl->p); /* mark its prototype */ |
465 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ | 482 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ |
466 | UpVal *uv = cl->upvals[i]; | 483 | UpVal *uv = cl->upvals[i]; |
467 | if (uv != NULL) { | 484 | if (uv != NULL) { |
468 | if (upisopen(uv)) | 485 | if (upisopen(uv) && g->gcstate != GCSinsideatomic) |
469 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ | 486 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ |
470 | else | 487 | else |
471 | markvalue(g, uv->v); | 488 | markvalue(g, uv->v); |
@@ -480,12 +497,19 @@ static lu_mem traversestack (global_State *g, lua_State *th) { | |||
480 | StkId o = th->stack; | 497 | StkId o = th->stack; |
481 | if (o == NULL) | 498 | if (o == NULL) |
482 | return 1; /* stack not completely built yet */ | 499 | return 1; /* stack not completely built yet */ |
500 | lua_assert(g->gcstate == GCSinsideatomic || | ||
501 | th->openupval == NULL || isintwups(th)); | ||
483 | for (; o < th->top; o++) /* mark live elements in the stack */ | 502 | for (; o < th->top; o++) /* mark live elements in the stack */ |
484 | markvalue(g, o); | 503 | markvalue(g, o); |
485 | if (g->gcstate == GCSatomic) { /* final traversal? */ | 504 | if (g->gcstate == GCSinsideatomic) { /* final traversal? */ |
486 | StkId lim = th->stack + th->stacksize; /* real end of stack */ | 505 | StkId lim = th->stack + th->stacksize; /* real end of stack */ |
487 | for (; o < lim; o++) /* clear not-marked stack slice */ | 506 | for (; o < lim; o++) /* clear not-marked stack slice */ |
488 | setnilvalue(o); | 507 | setnilvalue(o); |
508 | /* 'remarkupvals' may have removed thread from 'twups' list */ | ||
509 | if (!isintwups(th) && th->openupval != NULL) { | ||
510 | th->twups = g->twups; /* link it back to the list */ | ||
511 | g->twups = th; | ||
512 | } | ||
489 | } | 513 | } |
490 | else { | 514 | else { |
491 | CallInfo *ci; | 515 | CallInfo *ci; |
@@ -941,6 +965,7 @@ static l_mem atomic (lua_State *L) { | |||
941 | l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ | 965 | l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ |
942 | GCObject *origweak, *origall; | 966 | GCObject *origweak, *origall; |
943 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 967 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
968 | g->gcstate = GCSinsideatomic; | ||
944 | markobject(g, L); /* mark running thread */ | 969 | markobject(g, L); /* mark running thread */ |
945 | /* registry and global metatables may be changed by API */ | 970 | /* registry and global metatables may be changed by API */ |
946 | markvalue(g, &g->l_registry); | 971 | markvalue(g, &g->l_registry); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.118 2014/02/13 12:11:34 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.119 2014/02/13 14:46:38 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 | */ |
@@ -222,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
222 | L->stack = NULL; | 222 | L->stack = NULL; |
223 | L->ci = NULL; | 223 | L->ci = NULL; |
224 | L->stacksize = 0; | 224 | L->stacksize = 0; |
225 | L->twups = L; /* thread has no upvalues */ | ||
225 | L->errorJmp = NULL; | 226 | L->errorJmp = NULL; |
226 | L->nCcalls = 0; | 227 | L->nCcalls = 0; |
227 | L->hook = NULL; | 228 | L->hook = NULL; |
@@ -317,6 +318,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
317 | g->sweepgc = NULL; | 318 | g->sweepgc = NULL; |
318 | g->gray = g->grayagain = NULL; | 319 | g->gray = g->grayagain = NULL; |
319 | g->weak = g->ephemeron = g->allweak = NULL; | 320 | g->weak = g->ephemeron = g->allweak = NULL; |
321 | g->twups = NULL; | ||
320 | g->totalbytes = sizeof(LG); | 322 | g->totalbytes = sizeof(LG); |
321 | g->GCdebt = 0; | 323 | g->GCdebt = 0; |
322 | g->gcfinnum = 0; | 324 | g->gcfinnum = 0; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.99 2014/02/13 12:11:34 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.100 2014/02/13 14:46:38 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 | */ |
@@ -124,6 +124,7 @@ typedef struct global_State { | |||
124 | GCObject *allweak; /* list of all-weak tables */ | 124 | GCObject *allweak; /* list of all-weak tables */ |
125 | GCObject *tobefnz; /* list of userdata to be GC */ | 125 | GCObject *tobefnz; /* list of userdata to be GC */ |
126 | GCObject *fixedgc; /* list of objects not to be collected */ | 126 | GCObject *fixedgc; /* list of objects not to be collected */ |
127 | struct lua_State *twups; /* list of threads with open upvalues */ | ||
127 | Mbuffer buff; /* temporary buffer for string concatenation */ | 128 | Mbuffer buff; /* temporary buffer for string concatenation */ |
128 | unsigned int gcfinnum; /* number of finalizers to call in each GC step */ | 129 | unsigned int gcfinnum; /* number of finalizers to call in each GC step */ |
129 | int gcpause; /* size of pause between successive GCs */ | 130 | int gcpause; /* size of pause between successive GCs */ |
@@ -159,6 +160,7 @@ struct lua_State { | |||
159 | lua_Hook hook; | 160 | lua_Hook hook; |
160 | UpVal *openupval; /* list of open upvalues in this stack */ | 161 | UpVal *openupval; /* list of open upvalues in this stack */ |
161 | GCObject *gclist; | 162 | GCObject *gclist; |
163 | struct lua_State *twups; /* list of threads with open upvalues */ | ||
162 | struct lua_longjmp *errorJmp; /* current error recover point */ | 164 | struct lua_longjmp *errorJmp; /* current error recover point */ |
163 | ptrdiff_t errfunc; /* current error handling function (stack index) */ | 165 | ptrdiff_t errfunc; /* current error handling function (stack index) */ |
164 | CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ | 166 | CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ |