diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:33 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:33 -0300 |
commit | a4e1230f95223f2106cf0e118426ba91f1017d89 (patch) | |
tree | bc6b67ae14a3381498a203e715d48e8d059b6fef | |
parent | 9804467eeb9836bc147adffee411b21e6257da6b (diff) | |
download | lua-a4e1230f95223f2106cf0e118426ba91f1017d89.tar.gz lua-a4e1230f95223f2106cf0e118426ba91f1017d89.tar.bz2 lua-a4e1230f95223f2106cf0e118426ba91f1017d89.zip |
better way to control open upvalues
-rw-r--r-- | lfunc.c | 22 | ||||
-rw-r--r-- | lgc.c | 236 | ||||
-rw-r--r-- | lgc.h | 5 | ||||
-rw-r--r-- | lobject.h | 3 | ||||
-rw-r--r-- | lstate.c | 27 |
5 files changed, 159 insertions, 134 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lfunc.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.2 2004/02/16 19:09:52 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 | */ |
@@ -34,6 +34,7 @@ Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { | |||
34 | c->l.isC = 0; | 34 | c->l.isC = 0; |
35 | c->l.g = *e; | 35 | c->l.g = *e; |
36 | c->l.nupvalues = cast(lu_byte, nelems); | 36 | c->l.nupvalues = cast(lu_byte, nelems); |
37 | while (nelems--) c->l.upvals[nelems] = NULL; | ||
37 | return c; | 38 | return c; |
38 | } | 39 | } |
39 | 40 | ||
@@ -67,17 +68,18 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
67 | 68 | ||
68 | void luaF_close (lua_State *L, StkId level) { | 69 | void luaF_close (lua_State *L, StkId level) { |
69 | UpVal *uv; | 70 | UpVal *uv; |
71 | global_State *g = G(L); | ||
70 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { | 72 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { |
71 | lu_byte mark = uv->marked; | 73 | GCObject *o = obj2gco(uv); |
72 | lua_assert(!isblack(obj2gco(uv))); | 74 | lua_assert(!isblack(o)); |
73 | setobj(L, &uv->value, uv->v); | ||
74 | luaC_barrier(L, uv, uv->v); | ||
75 | uv->v = &uv->value; /* now current value lives here */ | ||
76 | L->openupval = uv->next; /* remove from `open' list */ | 75 | L->openupval = uv->next; /* remove from `open' list */ |
77 | luaC_link(L, obj2gco(uv), LUA_TUPVAL); | 76 | if (isdead(g, o)) |
78 | if (G(L)->gcstate == GCSpropagate) | 77 | luaM_freelem(L, uv); /* free upvalue */ |
79 | uv->marked = mark; /* preserve previous mark */ | 78 | else { |
80 | lua_assert(!isdead(G(L), obj2gco(uv))); | 79 | setobj(L, &uv->value, uv->v); |
80 | uv->v = &uv->value; /* now current value lives here */ | ||
81 | luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ | ||
82 | } | ||
81 | } | 83 | } |
82 | } | 84 | } |
83 | 85 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.4 2004/03/09 17:34:35 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 | */ |
@@ -27,15 +27,16 @@ | |||
27 | #define GCSWEEPCOST sizeof(TValue) | 27 | #define GCSWEEPCOST sizeof(TValue) |
28 | 28 | ||
29 | 29 | ||
30 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) | 30 | #define FIXEDMASK bitmask(FIXEDBIT) |
31 | 31 | ||
32 | #define maskmarks \ | 32 | #define maskmarks \ |
33 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) | 33 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) |
34 | |||
34 | #define makewhite(g,x) \ | 35 | #define makewhite(g,x) \ |
35 | ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) | 36 | ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) |
36 | 37 | ||
37 | #define isgray(x) (!isblack(x) && !iswhite(x)) | ||
38 | #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | 38 | #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |
39 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) | ||
39 | #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) | 40 | #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) |
40 | 41 | ||
41 | #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) | 42 | #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) |
@@ -58,47 +59,10 @@ | |||
58 | 59 | ||
59 | 60 | ||
60 | 61 | ||
61 | 62 | static void removeentry (Node *n) { | |
62 | /* | 63 | setnilvalue(gval(n)); /* remove corresponding value ... */ |
63 | ** computes the size of a collectible object | 64 | if (iscollectable(gkey(n))) |
64 | */ | 65 | setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ |
65 | static size_t objsize (GCObject *o) { | ||
66 | switch (o->gch.tt) { | ||
67 | case LUA_TSTRING: { | ||
68 | TString *ts = rawgco2ts(o); | ||
69 | return sizestring(ts->tsv.len); | ||
70 | } | ||
71 | case LUA_TUSERDATA: { | ||
72 | Udata *u = rawgco2u(o); | ||
73 | return sizeudata(u->uv.len); | ||
74 | } | ||
75 | case LUA_TTABLE: { | ||
76 | Table *h = gco2h(o); | ||
77 | return sizeof(Table) + sizeof(TValue) * h->sizearray + | ||
78 | sizeof(Node) * sizenode(h); | ||
79 | } | ||
80 | case LUA_TUPVAL: | ||
81 | return sizeof(UpVal); | ||
82 | case LUA_TFUNCTION: { | ||
83 | Closure *cl = gco2cl(o); | ||
84 | return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | ||
85 | sizeLclosure(cl->l.nupvalues); | ||
86 | } | ||
87 | case LUA_TTHREAD: { | ||
88 | lua_State *th = gco2th(o); | ||
89 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
90 | sizeof(CallInfo) * th->size_ci; | ||
91 | } | ||
92 | case LUA_TPROTO: { | ||
93 | Proto *p = gco2p(o); | ||
94 | return sizeof(Proto) + sizeof(Instruction) * p->sizecode + | ||
95 | sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + | ||
96 | sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + | ||
97 | sizeof(TString *) * p->sizeupvalues; | ||
98 | } | ||
99 | } | ||
100 | lua_assert(0); | ||
101 | return 0; /* to avoid warnings */ | ||
102 | } | 66 | } |
103 | 67 | ||
104 | 68 | ||
@@ -115,29 +79,36 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
115 | if (mt) markobject(g, mt); | 79 | if (mt) markobject(g, mt); |
116 | return; | 80 | return; |
117 | } | 81 | } |
82 | case LUA_TUPVAL: { | ||
83 | UpVal *uv = gco2uv(o); | ||
84 | if (uv->v == &uv->value) { /* closed? */ | ||
85 | markvalue(g, uv->v); | ||
86 | gray2black(o); | ||
87 | } | ||
88 | return; | ||
89 | } | ||
118 | case LUA_TFUNCTION: { | 90 | case LUA_TFUNCTION: { |
119 | gco2cl(o)->c.gclist = g->gray; | 91 | gco2cl(o)->c.gclist = g->gray; |
92 | g->gray = o; | ||
120 | break; | 93 | break; |
121 | } | 94 | } |
122 | case LUA_TTABLE: { | 95 | case LUA_TTABLE: { |
123 | gco2h(o)->gclist = g->gray; | 96 | gco2h(o)->gclist = g->gray; |
97 | g->gray = o; | ||
124 | break; | 98 | break; |
125 | } | 99 | } |
126 | case LUA_TTHREAD: { | 100 | case LUA_TTHREAD: { |
127 | gco2th(o)->gclist = g->gray; | 101 | gco2th(o)->gclist = g->gray; |
102 | g->gray = o; | ||
128 | break; | 103 | break; |
129 | } | 104 | } |
130 | case LUA_TPROTO: { | 105 | case LUA_TPROTO: { |
131 | gco2p(o)->gclist = g->gray; | 106 | gco2p(o)->gclist = g->gray; |
132 | break; | 107 | g->gray = o; |
133 | } | ||
134 | case LUA_TUPVAL: { | ||
135 | gco2uv(o)->gclist = g->gray; | ||
136 | break; | 108 | break; |
137 | } | 109 | } |
138 | default: lua_assert(0); | 110 | default: lua_assert(0); |
139 | } | 111 | } |
140 | g->gray = o; /* finish list linking */ | ||
141 | } | 112 | } |
142 | 113 | ||
143 | 114 | ||
@@ -157,8 +128,7 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
157 | GCObject *curr; | 128 | GCObject *curr; |
158 | GCObject *collected = NULL; /* to collect udata with gc event */ | 129 | GCObject *collected = NULL; /* to collect udata with gc event */ |
159 | GCObject **lastcollected = &collected; | 130 | GCObject **lastcollected = &collected; |
160 | while ((curr = *p) != NULL) { | 131 | while ((curr = *p)->gch.tt == LUA_TUSERDATA) { |
161 | lua_assert(curr->gch.tt == LUA_TUSERDATA); | ||
162 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) | 132 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) |
163 | p = &curr->gch.next; /* don't bother with them */ | 133 | p = &curr->gch.next; /* don't bother with them */ |
164 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | 134 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { |
@@ -174,6 +144,7 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
174 | lastcollected = &curr->gch.next; | 144 | lastcollected = &curr->gch.next; |
175 | } | 145 | } |
176 | } | 146 | } |
147 | lua_assert(curr == obj2gco(G(L)->mainthread)); | ||
177 | /* insert collected udata with gc event into `tmudata' list */ | 148 | /* insert collected udata with gc event into `tmudata' list */ |
178 | *lastcollected = G(L)->tmudata; | 149 | *lastcollected = G(L)->tmudata; |
179 | G(L)->tmudata = collected; | 150 | G(L)->tmudata = collected; |
@@ -210,7 +181,9 @@ static int traversetable (global_State *g, Table *h) { | |||
210 | i = sizenode(h); | 181 | i = sizenode(h); |
211 | while (i--) { | 182 | while (i--) { |
212 | Node *n = gnode(h, i); | 183 | Node *n = gnode(h, i); |
213 | if (!ttisnil(gval(n))) { | 184 | if (ttisnil(gval(n))) |
185 | removeentry(n); /* remove empty entries */ | ||
186 | else { | ||
214 | lua_assert(!ttisnil(gkey(n))); | 187 | lua_assert(!ttisnil(gkey(n))); |
215 | if (!weakkey) markvalue(g, gkey(n)); | 188 | if (!weakkey) markvalue(g, gkey(n)); |
216 | if (!weakvalue) markvalue(g, gval(n)); | 189 | if (!weakvalue) markvalue(g, gval(n)); |
@@ -274,20 +247,20 @@ static void checkstacksizes (lua_State *L, StkId max) { | |||
274 | } | 247 | } |
275 | 248 | ||
276 | 249 | ||
277 | static void traversestack (global_State *g, lua_State *L1) { | 250 | static void traversestack (global_State *g, lua_State *l) { |
278 | StkId o, lim; | 251 | StkId o, lim; |
279 | CallInfo *ci; | 252 | CallInfo *ci; |
280 | markvalue(g, gt(L1)); | 253 | markvalue(g, gt(l)); |
281 | lim = L1->top; | 254 | lim = l->top; |
282 | for (ci = L1->base_ci; ci <= L1->ci; ci++) { | 255 | for (ci = l->base_ci; ci <= l->ci; ci++) { |
283 | lua_assert(ci->top <= L1->stack_last); | 256 | lua_assert(ci->top <= l->stack_last); |
284 | if (lim < ci->top) lim = ci->top; | 257 | if (lim < ci->top) lim = ci->top; |
285 | } | 258 | } |
286 | for (o = L1->stack; o < L1->top; o++) | 259 | for (o = l->stack; o < l->top; o++) |
287 | markvalue(g, o); | 260 | markvalue(g, o); |
288 | for (; o <= lim; o++) | 261 | for (; o <= lim; o++) |
289 | setnilvalue(o); | 262 | setnilvalue(o); |
290 | checkstacksizes(L1, lim); | 263 | checkstacksizes(l, lim); |
291 | } | 264 | } |
292 | 265 | ||
293 | 266 | ||
@@ -306,12 +279,16 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
306 | g->gray = h->gclist; | 279 | g->gray = h->gclist; |
307 | if (traversetable(g, h)) /* table is weak? */ | 280 | if (traversetable(g, h)) /* table is weak? */ |
308 | black2gray(o); /* keep it gray */ | 281 | black2gray(o); /* keep it gray */ |
282 | lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + | ||
283 | sizeof(Node) * sizenode(h); | ||
309 | break; | 284 | break; |
310 | } | 285 | } |
311 | case LUA_TFUNCTION: { | 286 | case LUA_TFUNCTION: { |
312 | Closure *cl = gco2cl(o); | 287 | Closure *cl = gco2cl(o); |
313 | g->gray = cl->c.gclist; | 288 | g->gray = cl->c.gclist; |
314 | traverseclosure(g, cl); | 289 | traverseclosure(g, cl); |
290 | lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | ||
291 | sizeLclosure(cl->l.nupvalues); | ||
315 | break; | 292 | break; |
316 | } | 293 | } |
317 | case LUA_TTHREAD: { | 294 | case LUA_TTHREAD: { |
@@ -321,29 +298,24 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
321 | g->grayagain = o; | 298 | g->grayagain = o; |
322 | black2gray(o); | 299 | black2gray(o); |
323 | traversestack(g, th); | 300 | traversestack(g, th); |
301 | lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
302 | sizeof(CallInfo) * th->size_ci; | ||
324 | break; | 303 | break; |
325 | } | 304 | } |
326 | case LUA_TPROTO: { | 305 | case LUA_TPROTO: { |
327 | Proto *p = gco2p(o); | 306 | Proto *p = gco2p(o); |
328 | g->gray = p->gclist; | 307 | g->gray = p->gclist; |
329 | traverseproto(g, p); | 308 | traverseproto(g, p); |
330 | break; | 309 | lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode + |
331 | } | 310 | sizeof(Proto *) * p->sizep + |
332 | case LUA_TUPVAL: { | 311 | sizeof(TValue) * p->sizek + |
333 | UpVal *uv = gco2uv(o); | 312 | sizeof(int) * p->sizelineinfo + |
334 | g->gray = uv->gclist; | 313 | sizeof(LocVar) * p->sizelocvars + |
335 | if (uv->v != &uv->value) { /* open? */ | 314 | sizeof(TString *) * p->sizeupvalues; |
336 | uv->gclist = g->grayagain; | ||
337 | g->grayagain = o; | ||
338 | black2gray(o); | ||
339 | } | ||
340 | else | ||
341 | markvalue(g, &uv->value); | ||
342 | break; | 315 | break; |
343 | } | 316 | } |
344 | default: lua_assert(0); | 317 | default: lua_assert(0); |
345 | } | 318 | } |
346 | lim -= objsize(o); | ||
347 | if (lim <= 0) return lim; | 319 | if (lim <= 0) return lim; |
348 | } | 320 | } |
349 | return lim; | 321 | return lim; |
@@ -368,13 +340,6 @@ static int iscleared (const TValue *o, int iskey) { | |||
368 | } | 340 | } |
369 | 341 | ||
370 | 342 | ||
371 | static void removekey (Node *n) { | ||
372 | setnilvalue(gval(n)); /* remove corresponding value ... */ | ||
373 | if (iscollectable(gkey(n))) | ||
374 | setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ | ||
375 | } | ||
376 | |||
377 | |||
378 | /* | 343 | /* |
379 | ** clear collected entries from weaktables | 344 | ** clear collected entries from weaktables |
380 | */ | 345 | */ |
@@ -396,7 +361,7 @@ static void cleartable (GCObject *l) { | |||
396 | Node *n = gnode(h, i); | 361 | Node *n = gnode(h, i); |
397 | if (!ttisnil(gval(n)) && /* non-empty entry? */ | 362 | if (!ttisnil(gval(n)) && /* non-empty entry? */ |
398 | (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) | 363 | (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) |
399 | removekey(n); /* remove entry from table */ | 364 | removeentry(n); /* remove entry from table */ |
400 | } | 365 | } |
401 | l = h->gclist; | 366 | l = h->gclist; |
402 | } | 367 | } |
@@ -427,22 +392,28 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
427 | } | 392 | } |
428 | 393 | ||
429 | 394 | ||
430 | static void sweepupvalues (global_State *g, lua_State *L1) { | 395 | static void sweepupvalues (global_State *g, lua_State *l) { |
431 | GCObject *curr; | 396 | GCObject *curr; |
432 | for (curr = L1->openupval; curr != NULL; curr = curr->gch.next) | 397 | for (curr = l->openupval; curr != NULL; curr = curr->gch.next) |
433 | makewhite(g, curr); | 398 | makewhite(g, curr); |
434 | } | 399 | } |
435 | 400 | ||
436 | 401 | ||
437 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | 402 | /* |
403 | ** macros to test dead bit and optionally the fix bit | ||
404 | */ | ||
405 | #define makedeadmask(g,kf) (otherwhite(g) | ((kf) ? FIXEDMASK : 0)) | ||
406 | #define notdead(mark,mask) ((((mark) ^ FIXEDMASK) & mask) != mask) | ||
407 | |||
408 | |||
409 | static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, | ||
438 | l_mem *plim) { | 410 | l_mem *plim) { |
439 | GCObject *curr; | 411 | GCObject *curr; |
440 | global_State *g = G(L); | 412 | global_State *g = G(L); |
441 | l_mem lim = *plim; | 413 | l_mem lim = *plim; |
442 | int dead = otherwhite(g); | 414 | int deadmask = makedeadmask(g, keepfixed); |
443 | while ((curr = *p) != NULL) { | 415 | while ((curr = *p) != NULL) { |
444 | int mark = curr->gch.marked; | 416 | if (notdead(curr->gch.marked, deadmask)) { |
445 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | ||
446 | makewhite(g, curr); | 417 | makewhite(g, curr); |
447 | if (curr->gch.tt == LUA_TTHREAD) | 418 | if (curr->gch.tt == LUA_TTHREAD) |
448 | sweepupvalues(g, gco2th(curr)); | 419 | sweepupvalues(g, gco2th(curr)); |
@@ -450,6 +421,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
450 | lim -= GCSWEEPCOST; | 421 | lim -= GCSWEEPCOST; |
451 | } | 422 | } |
452 | else { | 423 | else { |
424 | lua_assert(iswhite(curr)); | ||
453 | *p = curr->gch.next; | 425 | *p = curr->gch.next; |
454 | if (curr == g->rootgc) /* is the first element of the list? */ | 426 | if (curr == g->rootgc) /* is the first element of the list? */ |
455 | g->rootgc = curr->gch.next; /* adjust first */ | 427 | g->rootgc = curr->gch.next; /* adjust first */ |
@@ -463,22 +435,22 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
463 | } | 435 | } |
464 | 436 | ||
465 | 437 | ||
466 | static l_mem sweepstrings (lua_State *L, int all, l_mem lim) { | 438 | static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { |
467 | int i; | 439 | int i; |
468 | global_State *g = G(L); | 440 | global_State *g = G(L); |
469 | int dead = otherwhite(g); | 441 | int deadmask = makedeadmask(g, keepfixed); |
470 | for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ | 442 | for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ |
471 | GCObject *curr; | 443 | GCObject *curr; |
472 | GCObject **p = &G(L)->strt.hash[i]; | 444 | GCObject **p = &G(L)->strt.hash[i]; |
473 | while ((curr = *p) != NULL) { | 445 | while ((curr = *p) != NULL) { |
474 | int mark = curr->gch.marked; | ||
475 | lu_mem size = sizestring(gco2ts(curr)->len); | 446 | lu_mem size = sizestring(gco2ts(curr)->len); |
476 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 447 | if (notdead(curr->gch.marked, deadmask)) { |
477 | makewhite(g, curr); | 448 | makewhite(g, curr); |
478 | lua_assert(iswhite(curr) && !isdead(g, curr)); | 449 | lua_assert(iswhite(curr) && !isdead(g, curr)); |
479 | p = &curr->gch.next; | 450 | p = &curr->gch.next; |
480 | } | 451 | } |
481 | else { | 452 | else { |
453 | lua_assert(iswhite(curr)); | ||
482 | g->strt.nuse--; | 454 | g->strt.nuse--; |
483 | *p = curr->gch.next; | 455 | *p = curr->gch.next; |
484 | luaM_free(L, curr, size); | 456 | luaM_free(L, curr, size); |
@@ -538,10 +510,19 @@ void luaC_callGCTM (lua_State *L) { | |||
538 | 510 | ||
539 | 511 | ||
540 | void luaC_sweepall (lua_State *L) { | 512 | void luaC_sweepall (lua_State *L) { |
513 | global_State *g = G(L); | ||
541 | l_mem dummy = MAXLMEM; | 514 | l_mem dummy = MAXLMEM; |
542 | G(L)->sweepstrgc = 0; | 515 | /* finish (occasional) current sweep */ |
543 | sweepstrings(L, 1, dummy); | 516 | markobject(g, g->mainthread); /* cannot collect main thread */ |
544 | sweeplist(L, &G(L)->rootgc, 1, &dummy); | 517 | sweepstrings(L, 0, MAXLMEM); |
518 | sweeplist(L, &g->rootgc, 0, &dummy); | ||
519 | /* do a whole new sweep */ | ||
520 | markobject(g, g->mainthread); /* cannot collect main thread */ | ||
521 | g->currentwhite = otherwhite(g); | ||
522 | g->sweepgc = &g->rootgc; | ||
523 | g->sweepstrgc = 0; | ||
524 | sweepstrings(L, 0, MAXLMEM); | ||
525 | sweeplist(L, &g->rootgc, 0, &dummy); | ||
545 | } | 526 | } |
546 | 527 | ||
547 | 528 | ||
@@ -559,12 +540,30 @@ static void markroot (lua_State *L) { | |||
559 | } | 540 | } |
560 | 541 | ||
561 | 542 | ||
543 | static void remarkupvals (global_State *g) { | ||
544 | GCObject *o; | ||
545 | for (o = obj2gco(g->mainthread); o; o = o->gch.next) { | ||
546 | if (iswhite(o)) { | ||
547 | GCObject *curr; | ||
548 | for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { | ||
549 | if (isgray(curr)) | ||
550 | markvalue(g, gco2uv(curr)->v); | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | |||
562 | static void atomic (lua_State *L) { | 557 | static void atomic (lua_State *L) { |
563 | global_State *g = G(L); | 558 | global_State *g = G(L); |
564 | lua_assert(g->gray == NULL); | 559 | lua_assert(g->gray == NULL); |
560 | /* remark occasional upvalues of (maybe) dead threads */ | ||
561 | remarkupvals(g); | ||
565 | /* remark weak tables */ | 562 | /* remark weak tables */ |
566 | g->gray = g->weak; | 563 | g->gray = g->weak; |
567 | g->weak = NULL; | 564 | g->weak = NULL; |
565 | lua_assert(!iswhite(obj2gco(g->mainthread))); | ||
566 | markobject(g, L); /* mark running thread */ | ||
568 | propagatemarks(g, MAXLMEM); | 567 | propagatemarks(g, MAXLMEM); |
569 | /* remark gray again */ | 568 | /* remark gray again */ |
570 | g->gray = g->grayagain; | 569 | g->gray = g->grayagain; |
@@ -576,8 +575,6 @@ static void atomic (lua_State *L) { | |||
576 | cleartable(g->weak); /* remove collected objects from weak tables */ | 575 | cleartable(g->weak); /* remove collected objects from weak tables */ |
577 | /* flip current white */ | 576 | /* flip current white */ |
578 | g->currentwhite = otherwhite(g); | 577 | g->currentwhite = otherwhite(g); |
579 | g->sweepgc = &g->rootgc; | ||
580 | g->sweepstrgc = 0; | ||
581 | g->gcstate = GCSsweepstring; | 578 | g->gcstate = GCSsweepstring; |
582 | } | 579 | } |
583 | 580 | ||
@@ -587,38 +584,41 @@ static l_mem singlestep (lua_State *L, l_mem lim) { | |||
587 | switch (g->gcstate) { | 584 | switch (g->gcstate) { |
588 | case GCSpropagate: { | 585 | case GCSpropagate: { |
589 | if (g->gray) | 586 | if (g->gray) |
590 | return propagatemarks(g, lim); | 587 | lim = propagatemarks(g, lim); |
591 | else { /* no more `gray' objects */ | 588 | else { /* no more `gray' objects */ |
592 | atomic(L); /* finish mark phase */ | 589 | atomic(L); /* finish mark phase */ |
593 | return 0; | 590 | lim = 0; |
594 | } | 591 | } |
592 | break; | ||
595 | } | 593 | } |
596 | case GCSsweepstring: { | 594 | case GCSsweepstring: { |
597 | lim = sweepstrings(L, 0, lim); | 595 | lim = sweepstrings(L, 1, lim); |
598 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ | 596 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ |
599 | g->sweepstrgc = 0; | 597 | g->sweepstrgc = 0; |
600 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 598 | g->gcstate = GCSsweep; /* end sweep-string phase */ |
601 | } | 599 | } |
602 | return lim; | 600 | break; |
603 | } | 601 | } |
604 | case GCSsweep: { | 602 | case GCSsweep: { |
605 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); | 603 | g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim); |
606 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 604 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
607 | checkSizes(L); | 605 | checkSizes(L); |
608 | sweepupvalues(g, g->mainthread); | 606 | g->sweepgc = &g->rootgc; |
609 | g->gcstate = GCSfinalize; /* end sweep phase */ | 607 | g->gcstate = GCSfinalize; /* end sweep phase */ |
610 | } | 608 | } |
611 | return lim; | 609 | break; |
612 | } | 610 | } |
613 | case GCSfinalize: { | 611 | case GCSfinalize: { |
614 | if (g->tmudata) | 612 | if (g->tmudata) |
615 | GCTM(L); | 613 | GCTM(L); |
616 | else /* no more `udata' to finalize */ | 614 | else /* no more `udata' to finalize */ |
617 | markroot(L); /* may restart collection */ | 615 | markroot(L); /* may restart collection */ |
618 | return 0; | 616 | lim = 0; |
617 | break; | ||
619 | } | 618 | } |
620 | default: lua_assert(0); return 0; /* to avoid warnings */ | 619 | default: lua_assert(0); |
621 | } | 620 | } |
621 | return lim; | ||
622 | } | 622 | } |
623 | 623 | ||
624 | 624 | ||
@@ -635,11 +635,15 @@ void luaC_step (lua_State *L) { | |||
635 | 635 | ||
636 | void luaC_fullgc (lua_State *L) { | 636 | void luaC_fullgc (lua_State *L) { |
637 | global_State *g = G(L); | 637 | global_State *g = G(L); |
638 | while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM); | 638 | while (g->gcstate != GCSfinalize) { |
639 | singlestep(L, MAXLMEM); | ||
640 | } | ||
639 | markroot(L); | 641 | markroot(L); |
640 | while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM); | 642 | while (g->gcstate != GCSfinalize) { |
641 | luaC_callGCTM(L); /* call finalizers */ | 643 | singlestep(L, MAXLMEM); |
644 | } | ||
642 | g->GCthreshold = g->nblocks + GCSTEPSIZE; | 645 | g->GCthreshold = g->nblocks + GCSTEPSIZE; |
646 | luaC_callGCTM(L); /* call finalizers */ | ||
643 | } | 647 | } |
644 | 648 | ||
645 | 649 | ||
@@ -662,3 +666,21 @@ void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | |||
662 | o->gch.tt = tt; | 666 | o->gch.tt = tt; |
663 | } | 667 | } |
664 | 668 | ||
669 | |||
670 | void luaC_linkupval (lua_State *L, UpVal *uv) { | ||
671 | global_State *g = G(L); | ||
672 | GCObject *o = obj2gco(uv); | ||
673 | o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ | ||
674 | g->rootgc = o; | ||
675 | if (isgray(o)) { | ||
676 | if (g->gcstate == GCSpropagate) { | ||
677 | gray2black(o); /* closed upvalues need barrier */ | ||
678 | luaC_barrier(L, uv, uv->v); | ||
679 | } | ||
680 | else { /* sweep phase: sweep it (turning it into white) */ | ||
681 | makewhite(g, o); | ||
682 | lua_assert(g->gcstate != GCSfinalize); | ||
683 | } | ||
684 | } | ||
685 | } | ||
686 | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.h,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.4 2004/03/09 17:34:35 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 | */ |
@@ -58,7 +58,7 @@ | |||
58 | 58 | ||
59 | #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | 59 | #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |
60 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) | 60 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) |
61 | 61 | #define isgray(x) (!isblack(x) && !iswhite(x)) | |
62 | 62 | ||
63 | #define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) | 63 | #define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) |
64 | #define isdead(g,v) ((v)->gch.marked & otherwhite(g)) | 64 | #define isdead(g,v) ((v)->gch.marked & otherwhite(g)) |
@@ -87,6 +87,7 @@ void luaC_sweepall (lua_State *L); | |||
87 | void luaC_step (lua_State *L); | 87 | void luaC_step (lua_State *L); |
88 | void luaC_fullgc (lua_State *L); | 88 | void luaC_fullgc (lua_State *L); |
89 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); | 89 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); |
90 | void luaC_linkupval (lua_State *L, UpVal *uv); | ||
90 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); | 91 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); |
91 | 92 | ||
92 | 93 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 2.2 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.3 2004/02/20 16:01:05 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 | */ |
@@ -263,7 +263,6 @@ typedef struct LocVar { | |||
263 | 263 | ||
264 | typedef struct UpVal { | 264 | typedef struct UpVal { |
265 | CommonHeader; | 265 | CommonHeader; |
266 | GCObject *gclist; | ||
267 | TValue *v; /* points to stack or to its own value */ | 266 | TValue *v; /* points to stack or to its own value */ |
268 | TValue value; /* the value (when closed) */ | 267 | TValue value; /* the value (when closed) */ |
269 | } UpVal; | 268 | } UpVal; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.3 2004/02/16 19:09:52 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 | */ |
@@ -93,7 +93,10 @@ static void f_luaopen (lua_State *L, void *ud) { | |||
93 | } | 93 | } |
94 | 94 | ||
95 | 95 | ||
96 | static void preinit_state (lua_State *L) { | 96 | static void preinit_state (lua_State *L, global_State *g) { |
97 | L->l_G = g; | ||
98 | L->tt = LUA_TTHREAD; | ||
99 | L->marked = luaC_white(g); | ||
97 | L->stack = NULL; | 100 | L->stack = NULL; |
98 | L->stacksize = 0; | 101 | L->stacksize = 0; |
99 | L->errorJmp = NULL; | 102 | L->errorJmp = NULL; |
@@ -116,7 +119,7 @@ static void close_state (lua_State *L) { | |||
116 | global_State *g = G(L); | 119 | global_State *g = G(L); |
117 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | 120 | luaF_close(L, L->stack); /* close all upvalues for this thread */ |
118 | luaC_sweepall(L); /* collect all elements */ | 121 | luaC_sweepall(L); /* collect all elements */ |
119 | lua_assert(g->rootgc == NULL); | 122 | lua_assert(g->rootgc == obj2gco(L)); |
120 | luaS_freeall(L); | 123 | luaS_freeall(L); |
121 | luaZ_freebuffer(L, &g->buff); | 124 | luaZ_freebuffer(L, &g->buff); |
122 | freestack(L, L); | 125 | freestack(L, L); |
@@ -127,9 +130,9 @@ static void close_state (lua_State *L) { | |||
127 | 130 | ||
128 | lua_State *luaE_newthread (lua_State *L) { | 131 | lua_State *luaE_newthread (lua_State *L) { |
129 | lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); | 132 | lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); |
130 | luaC_link(L, obj2gco(L1), LUA_TTHREAD); | 133 | L1->next = L->next; /* link new thread after `L' */ |
131 | preinit_state(L1); | 134 | L->next = obj2gco(L1); |
132 | L1->l_G = L->l_G; | 135 | preinit_state(L1, G(L)); |
133 | stack_init(L1, L); /* init stack */ | 136 | stack_init(L1, L); /* init stack */ |
134 | setobj2n(L, gt(L1), gt(L)); /* share table of globals */ | 137 | setobj2n(L, gt(L1), gt(L)); /* share table of globals */ |
135 | lua_assert(iswhite(obj2gco(L1))); | 138 | lua_assert(iswhite(obj2gco(L1))); |
@@ -152,11 +155,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
152 | if (l == NULL) return NULL; | 155 | if (l == NULL) return NULL; |
153 | L = tostate(l); | 156 | L = tostate(l); |
154 | g = &((LG *)L)->g; | 157 | g = &((LG *)L)->g; |
155 | L->tt = LUA_TTHREAD; | 158 | L->next = NULL; |
156 | L->marked = 0; | 159 | g->currentwhite = bitmask(WHITE0BIT); |
157 | L->next = L->gclist = NULL; | 160 | preinit_state(L, g); |
158 | preinit_state(L); | ||
159 | L->l_G = g; | ||
160 | g->realloc = f; | 161 | g->realloc = f; |
161 | g->ud = ud; | 162 | g->ud = ud; |
162 | g->mainthread = L; | 163 | g->mainthread = L; |
@@ -168,9 +169,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
168 | luaZ_initbuffer(L, &g->buff); | 169 | luaZ_initbuffer(L, &g->buff); |
169 | g->panic = NULL; | 170 | g->panic = NULL; |
170 | g->gcstate = GCSfinalize; | 171 | g->gcstate = GCSfinalize; |
171 | g->rootgc = NULL; | 172 | g->rootgc = obj2gco(L); |
172 | g->sweepstrgc = 0; | 173 | g->sweepstrgc = 0; |
173 | g->currentwhite = bitmask(WHITE0BIT); | 174 | g->sweepgc = &g->rootgc; |
174 | g->firstudata = NULL; | 175 | g->firstudata = NULL; |
175 | g->gray = NULL; | 176 | g->gray = NULL; |
176 | g->grayagain = NULL; | 177 | g->grayagain = NULL; |