diff options
-rw-r--r-- | lfunc.c | 34 | ||||
-rw-r--r-- | lfunc.h | 3 | ||||
-rw-r--r-- | lgc.c | 25 | ||||
-rw-r--r-- | lobject.h | 10 | ||||
-rw-r--r-- | lstate.c | 8 | ||||
-rw-r--r-- | lstate.h | 20 | ||||
-rw-r--r-- | ltests.c | 19 |
7 files changed, 47 insertions, 72 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 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 | */ |
@@ -38,7 +38,7 @@ Closure *luaF_newLclosure (lua_State *L, int n) { | |||
38 | 38 | ||
39 | UpVal *luaF_newupval (lua_State *L) { | 39 | UpVal *luaF_newupval (lua_State *L) { |
40 | UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; | 40 | UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; |
41 | uv->v = &uv->u.value; | 41 | uv->v = &uv->value; |
42 | setnilvalue(uv->v); | 42 | setnilvalue(uv->v); |
43 | return uv; | 43 | return uv; |
44 | } | 44 | } |
@@ -51,7 +51,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
51 | UpVal *uv; | 51 | UpVal *uv; |
52 | while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { | 52 | while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { |
53 | GCObject *o = obj2gco(p); | 53 | GCObject *o = obj2gco(p); |
54 | lua_assert(p->v != &p->u.value); | 54 | lua_assert(p->v != &p->value); |
55 | if (p->v == level) { /* found a corresponding upvalue? */ | 55 | if (p->v == level) { /* found a corresponding upvalue? */ |
56 | if (isdead(g, o)) /* is it dead? */ | 56 | if (isdead(g, o)) /* is it dead? */ |
57 | changewhite(o); /* resurrect it */ | 57 | changewhite(o); /* resurrect it */ |
@@ -62,42 +62,22 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
62 | /* not found: create a new one */ | 62 | /* not found: create a new one */ |
63 | uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; | 63 | uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; |
64 | uv->v = level; /* current value lives in the stack */ | 64 | uv->v = level; /* current value lives in the stack */ |
65 | uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ | ||
66 | uv->u.l.next = g->uvhead.u.l.next; | ||
67 | uv->u.l.next->u.l.prev = uv; | ||
68 | g->uvhead.u.l.next = uv; | ||
69 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
70 | return uv; | 65 | return uv; |
71 | } | 66 | } |
72 | 67 | ||
73 | 68 | ||
74 | static void unlinkupval (UpVal *uv) { | ||
75 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
76 | uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ | ||
77 | uv->u.l.prev->u.l.next = uv->u.l.next; | ||
78 | } | ||
79 | |||
80 | |||
81 | void luaF_freeupval (lua_State *L, UpVal *uv) { | ||
82 | if (uv->v != &uv->u.value) /* is it open? */ | ||
83 | unlinkupval(uv); /* remove from open list */ | ||
84 | luaM_free(L, uv); /* free upvalue */ | ||
85 | } | ||
86 | |||
87 | |||
88 | void luaF_close (lua_State *L, StkId level) { | 69 | void luaF_close (lua_State *L, StkId level) { |
89 | UpVal *uv; | 70 | UpVal *uv; |
90 | global_State *g = G(L); | 71 | global_State *g = G(L); |
91 | while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { | 72 | while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { |
92 | GCObject *o = obj2gco(uv); | 73 | GCObject *o = obj2gco(uv); |
93 | lua_assert(!isblack(o) && uv->v != &uv->u.value); | 74 | lua_assert(!isblack(o) && uv->v != &uv->value); |
94 | L->openupval = uv->next; /* remove from `open' list */ | 75 | L->openupval = uv->next; /* remove from `open' list */ |
95 | if (isdead(g, o)) | 76 | if (isdead(g, o)) |
96 | luaF_freeupval(L, uv); /* free upvalue */ | 77 | luaM_free(L, uv); /* free upvalue */ |
97 | else { | 78 | else { |
98 | unlinkupval(uv); /* remove upvalue from 'uvhead' list */ | 79 | setobj(L, &uv->value, uv->v); /* move value to upvalue slot */ |
99 | setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ | 80 | uv->v = &uv->value; /* now current value lives here */ |
100 | uv->v = &uv->u.value; /* now current value lives here */ | ||
101 | gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ | 81 | gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ |
102 | g->allgc = o; | 82 | g->allgc = o; |
103 | luaC_checkupvalcolor(g, uv); | 83 | luaC_checkupvalcolor(g, uv); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.h,v 2.7 2012/01/20 22:05:50 roberto Exp roberto $ | 2 | ** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 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 | */ |
@@ -25,7 +25,6 @@ LUAI_FUNC UpVal *luaF_newupval (lua_State *L); | |||
25 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); | 25 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |
26 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); | 26 | LUAI_FUNC void luaF_close (lua_State *L, StkId level); |
27 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); | 27 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |
28 | LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); | ||
29 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, | 28 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, |
30 | int pc); | 29 | int pc); |
31 | 30 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.141 2013/04/26 18:26:49 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.142 2013/08/05 16:58:28 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 | */ |
@@ -258,7 +258,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
258 | case LUA_TUPVAL: { | 258 | case LUA_TUPVAL: { |
259 | UpVal *uv = gco2uv(o); | 259 | UpVal *uv = gco2uv(o); |
260 | markvalue(g, uv->v); | 260 | markvalue(g, uv->v); |
261 | if (uv->v != &uv->u.value) /* open? */ | 261 | if (uv->v != &uv->value) /* open? */ |
262 | return; /* open upvalues remain gray */ | 262 | return; /* open upvalues remain gray */ |
263 | size = sizeof(UpVal); | 263 | size = sizeof(UpVal); |
264 | break; | 264 | break; |
@@ -317,14 +317,21 @@ static void markbeingfnz (global_State *g) { | |||
317 | 317 | ||
318 | 318 | ||
319 | /* | 319 | /* |
320 | ** mark all values stored in marked open upvalues. (See comment in | 320 | ** Mark all values stored in marked open upvalues from non-marked threads. |
321 | ** 'lstate.h'.) | 321 | ** (Values from marked threads were already marked when traversing the |
322 | ** thread.) | ||
322 | */ | 323 | */ |
323 | static void remarkupvals (global_State *g) { | 324 | static void remarkupvals (global_State *g) { |
324 | UpVal *uv; | 325 | GCObject *thread = hvalue(&g->l_registry)->next; |
325 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | 326 | for (; thread != NULL; thread = gch(thread)->next) { |
326 | if (isgray(obj2gco(uv))) | 327 | lua_assert(!isblack(thread)); /* threads are never black */ |
327 | markvalue(g, uv->v); | 328 | if (!isgray(thread)) { /* dead thread? */ |
329 | GCObject *uv = gco2th(thread)->openupval; | ||
330 | for (; uv != NULL; uv = gch(uv)->next) { | ||
331 | if (isgray(uv)) /* marked? */ | ||
332 | markvalue(g, gco2uv(uv)->v); /* remark upvalue's value */ | ||
333 | } | ||
334 | } | ||
328 | } | 335 | } |
329 | } | 336 | } |
330 | 337 | ||
@@ -669,7 +676,7 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
669 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); | 676 | luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); |
670 | break; | 677 | break; |
671 | } | 678 | } |
672 | case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; | 679 | case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; |
673 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; | 680 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; |
674 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; | 681 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; |
675 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; | 682 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 2.77 2013/05/06 17:17:09 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.78 2013/05/14 15:59:04 roberto Exp roberto $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -395,13 +395,7 @@ typedef struct Proto { | |||
395 | typedef struct UpVal { | 395 | typedef struct UpVal { |
396 | CommonHeader; | 396 | CommonHeader; |
397 | TValue *v; /* points to stack or to its own value */ | 397 | TValue *v; /* points to stack or to its own value */ |
398 | union { | 398 | TValue value; /* the value (when closed) */ |
399 | TValue value; /* the value (when closed) */ | ||
400 | struct { /* double linked list (when open) */ | ||
401 | struct UpVal *prev; | ||
402 | struct UpVal *next; | ||
403 | } l; | ||
404 | } u; | ||
405 | } UpVal; | 399 | } UpVal; |
406 | 400 | ||
407 | 401 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 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 | */ |
@@ -230,7 +230,9 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |||
230 | lua_State *L1; | 230 | lua_State *L1; |
231 | lua_lock(L); | 231 | lua_lock(L); |
232 | luaC_checkGC(L); | 232 | luaC_checkGC(L); |
233 | L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; | 233 | /* create new thread, linked after 'l_registry' */ |
234 | L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), | ||
235 | &hvalue(&G(L)->l_registry)->next, offsetof(LX, l))->th; | ||
234 | setthvalue(L, L->top, L1); | 236 | setthvalue(L, L->top, L1); |
235 | api_incr_top(L); | 237 | api_incr_top(L); |
236 | preinit_state(L1, G(L)); | 238 | preinit_state(L1, G(L)); |
@@ -273,8 +275,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
273 | g->ud = ud; | 275 | g->ud = ud; |
274 | g->mainthread = L; | 276 | g->mainthread = L; |
275 | g->seed = makeseed(L); | 277 | g->seed = makeseed(L); |
276 | g->uvhead.u.l.prev = &g->uvhead; | ||
277 | g->uvhead.u.l.next = &g->uvhead; | ||
278 | g->gcrunning = 0; /* no GC while building state */ | 278 | g->gcrunning = 0; /* no GC while building state */ |
279 | g->GCestimate = 0; | 279 | g->GCestimate = 0; |
280 | g->strt.size = 0; | 280 | g->strt.size = 0; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.83 2013/08/05 16:58:28 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 | */ |
@@ -20,17 +20,18 @@ | |||
20 | ** be kept somehow accessible until being freed. | 20 | ** be kept somehow accessible until being freed. |
21 | ** | 21 | ** |
22 | ** Lua keeps most objects linked in list g->allgc. The link uses field | 22 | ** Lua keeps most objects linked in list g->allgc. The link uses field |
23 | ** 'next' of the CommonHeader. | 23 | ** 'next' of the CommonHeader. Threads (except the main one) ar kept |
24 | ** at the end of the 'allgc' list, after the 'l_registry' (which is | ||
25 | ** the first object to be added to the list). | ||
24 | ** | 26 | ** |
25 | ** Strings are kept in several lists headed by the array g->strt.hash. | 27 | ** Short strings are kept in several lists headed by the array g->strt.hash. |
26 | ** | 28 | ** |
27 | ** Open upvalues are not subject to independent garbage collection. They | 29 | ** Open upvalues are not subject to independent garbage collection. They |
28 | ** are collected together with their respective threads. Lua keeps a | 30 | ** are collected together with their respective threads. (They are |
29 | ** double-linked list with all open upvalues (g->uvhead) so that it can | 31 | ** always gray, so they must be remarked in the atomic step. Usually |
30 | ** mark objects referred by them. (They are always gray, so they must | 32 | ** their contents would be marked when traversing the respective |
31 | ** be remarked in the atomic step. Usually their contents would be marked | 33 | ** threads, but the thread may already be dead, while the upvalue is |
32 | ** when traversing the respective threads, but the thread may already be | 34 | ** still accessible through closures.) |
33 | ** dead, while the upvalue is still accessible through closures.) | ||
34 | ** | 35 | ** |
35 | ** Objects with finalizers are kept in the list g->finobj. | 36 | ** Objects with finalizers are kept in the list g->finobj. |
36 | ** | 37 | ** |
@@ -133,7 +134,6 @@ typedef struct global_State { | |||
133 | GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ | 134 | GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ |
134 | GCObject *allweak; /* list of all-weak tables */ | 135 | GCObject *allweak; /* list of all-weak tables */ |
135 | GCObject *tobefnz; /* list of userdata to be GC */ | 136 | GCObject *tobefnz; /* list of userdata to be GC */ |
136 | UpVal uvhead; /* head of double-linked list of all open upvalues */ | ||
137 | Mbuffer buff; /* temporary buffer for string concatenation */ | 137 | Mbuffer buff; /* temporary buffer for string concatenation */ |
138 | int gcpause; /* size of pause between successive GCs */ | 138 | int gcpause; /* size of pause between successive GCs */ |
139 | int gcstepmul; /* GC `granularity' */ | 139 | int gcstepmul; /* GC `granularity' */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.139 2013/06/20 21:59:13 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $ |
3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -310,7 +310,7 @@ static void checkstack (global_State *g, lua_State *L1) { | |||
310 | lua_assert(!isdead(g, obj2gco(L1))); | 310 | lua_assert(!isdead(g, obj2gco(L1))); |
311 | for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { | 311 | for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) { |
312 | UpVal *uv = gco2uv(uvo); | 312 | UpVal *uv = gco2uv(uvo); |
313 | lua_assert(uv->v != &uv->u.value); /* must be open */ | 313 | lua_assert(uv->v != &uv->value); /* must be open */ |
314 | lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ | 314 | lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ |
315 | } | 315 | } |
316 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { | 316 | for (ci = L1->ci; ci != NULL; ci = ci->previous) { |
@@ -334,7 +334,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { | |||
334 | switch (gch(o)->tt) { | 334 | switch (gch(o)->tt) { |
335 | case LUA_TUPVAL: { | 335 | case LUA_TUPVAL: { |
336 | UpVal *uv = gco2uv(o); | 336 | UpVal *uv = gco2uv(o); |
337 | lua_assert(uv->v == &uv->u.value); /* must be closed */ | 337 | lua_assert(uv->v == &uv->value); /* must be closed */ |
338 | lua_assert(!isgray(o)); /* closed upvalues are never gray */ | 338 | lua_assert(!isgray(o)); /* closed upvalues are never gray */ |
339 | checkvalref(g, o, uv->v); | 339 | checkvalref(g, o, uv->v); |
340 | break; | 340 | break; |
@@ -419,8 +419,8 @@ static void checkgray (global_State *g, GCObject *o) { | |||
419 | int lua_checkmemory (lua_State *L) { | 419 | int lua_checkmemory (lua_State *L) { |
420 | global_State *g = G(L); | 420 | global_State *g = G(L); |
421 | GCObject *o; | 421 | GCObject *o; |
422 | UpVal *uv; | ||
423 | int maybedead; | 422 | int maybedead; |
423 | int isthread; | ||
424 | if (keepinvariant(g)) { | 424 | if (keepinvariant(g)) { |
425 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 425 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
426 | lua_assert(!iswhite(gcvalue(&g->l_registry))); | 426 | lua_assert(!iswhite(gcvalue(&g->l_registry))); |
@@ -433,9 +433,12 @@ int lua_checkmemory (lua_State *L) { | |||
433 | checkgray(g, g->allgc); | 433 | checkgray(g, g->allgc); |
434 | lua_assert(g->sweepgc == NULL || issweepphase(g)); | 434 | lua_assert(g->sweepgc == NULL || issweepphase(g)); |
435 | maybedead = 0; | 435 | maybedead = 0; |
436 | isthread = 0; /* not traversing threads (yet) */ | ||
436 | for (o = g->allgc; o != NULL; o = gch(o)->next) { | 437 | for (o = g->allgc; o != NULL; o = gch(o)->next) { |
437 | if (g->sweepgc && o == *g->sweepgc) | 438 | if (g->sweepgc && o == *g->sweepgc) |
438 | maybedead = 1; /* part of the list not yet swept */ | 439 | maybedead = 1; /* part of the list not yet swept */ |
440 | if (gch(o)->tt == LUA_TTHREAD) isthread = 1; /* now travesing threads... */ | ||
441 | else lua_assert(!isthread); /* ... and only threads */ | ||
439 | checkobject(g, o, maybedead); | 442 | checkobject(g, o, maybedead); |
440 | lua_assert(!testbit(o->gch.marked, SEPARATED)); | 443 | lua_assert(!testbit(o->gch.marked, SEPARATED)); |
441 | } | 444 | } |
@@ -455,14 +458,6 @@ int lua_checkmemory (lua_State *L) { | |||
455 | lua_assert(gch(o)->tt == LUA_TUSERDATA || | 458 | lua_assert(gch(o)->tt == LUA_TUSERDATA || |
456 | gch(o)->tt == LUA_TTABLE); | 459 | gch(o)->tt == LUA_TTABLE); |
457 | } | 460 | } |
458 | /* check 'uvhead' list */ | ||
459 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | ||
460 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
461 | lua_assert(uv->v != &uv->u.value); /* must be open */ | ||
462 | lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */ | ||
463 | if (!isdead(g, obj2gco(uv))) | ||
464 | checkvalref(g, obj2gco(uv), uv->v); | ||
465 | } | ||
466 | return 0; | 461 | return 0; |
467 | } | 462 | } |
468 | 463 | ||