diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-12-05 18:15:18 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2001-12-05 18:15:18 -0200 |
commit | 592a309177edc52847b1196969ad6d49ba21f4fb (patch) | |
tree | 06add977885c012ee22cc4f105785c435b6af353 /lgc.c | |
parent | 413fc7334bf8ceaea71417d73edef15c99d3a793 (diff) | |
download | lua-592a309177edc52847b1196969ad6d49ba21f4fb.tar.gz lua-592a309177edc52847b1196969ad6d49ba21f4fb.tar.bz2 lua-592a309177edc52847b1196969ad6d49ba21f4fb.zip |
tag system replaced by event tables
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 121 |
1 files changed, 61 insertions, 60 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.116 2001/11/06 21:41:53 roberto Exp $ | 2 | ** $Id: lgc.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -30,6 +30,15 @@ typedef struct GCState { | |||
30 | #define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} | 30 | #define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} |
31 | 31 | ||
32 | 32 | ||
33 | /* mark tricks for userdata */ | ||
34 | #define isudmarked(u) (u->uv.len & 1) | ||
35 | #define markud(u) (u->uv.len |= 1) | ||
36 | #define unmarkud(u) (u->uv.len--) | ||
37 | |||
38 | |||
39 | /* mark tricks for upvalues (assume that open upvalues are always marked) */ | ||
40 | #define isupvalmarked(uv) ((uv)->v != &(uv)->value) | ||
41 | |||
33 | 42 | ||
34 | static void markobject (GCState *st, TObject *o); | 43 | static void markobject (GCState *st, TObject *o); |
35 | 44 | ||
@@ -66,9 +75,9 @@ static void markclosure (GCState *st, Closure *cl) { | |||
66 | protomark(cl->l.p); | 75 | protomark(cl->l.p); |
67 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ | 76 | for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ |
68 | UpVal *u = cl->l.upvals[i]; | 77 | UpVal *u = cl->l.upvals[i]; |
69 | if (!u->mark) { | 78 | if (!isupvalmarked(u)) { |
70 | u->mark = 1; | 79 | markobject(st, &u->value); |
71 | markobject(st, u->v); | 80 | u->v = NULL; /* mark it! */ |
72 | } | 81 | } |
73 | } | 82 | } |
74 | } | 83 | } |
@@ -90,8 +99,8 @@ static void markobject (GCState *st, TObject *o) { | |||
90 | strmark(tsvalue(o)); | 99 | strmark(tsvalue(o)); |
91 | break; | 100 | break; |
92 | case LUA_TUSERDATA: | 101 | case LUA_TUSERDATA: |
93 | if (!ismarkedudata(uvalue(o))) | 102 | if (!isudmarked(uvalue(o))) |
94 | switchudatamark(uvalue(o)); | 103 | markud(uvalue(o)); |
95 | break; | 104 | break; |
96 | case LUA_TFUNCTION: | 105 | case LUA_TFUNCTION: |
97 | markclosure(st, clvalue(o)); | 106 | markclosure(st, clvalue(o)); |
@@ -112,7 +121,6 @@ static void markstacks (lua_State *L, GCState *st) { | |||
112 | lua_State *L1 = L; | 121 | lua_State *L1 = L; |
113 | do { /* for each thread */ | 122 | do { /* for each thread */ |
114 | StkId o, lim; | 123 | StkId o, lim; |
115 | markobject(st, &L1->gt); /* mark table of globals */ | ||
116 | for (o=L1->stack; o<L1->top; o++) | 124 | for (o=L1->stack; o<L1->top; o++) |
117 | markobject(st, o); | 125 | markobject(st, o); |
118 | lim = (L1->stack_last - L1->ci->base > MAXSTACK) ? L1->ci->base+MAXSTACK | 126 | lim = (L1->stack_last - L1->ci->base > MAXSTACK) ? L1->ci->base+MAXSTACK |
@@ -124,17 +132,10 @@ static void markstacks (lua_State *L, GCState *st) { | |||
124 | } | 132 | } |
125 | 133 | ||
126 | 134 | ||
127 | static void marktagmethods (global_State *G, GCState *st) { | 135 | static void markudet (lua_State *L, GCState *st) { |
128 | int t; | 136 | Udata *u; |
129 | for (t=0; t<G->ntag; t++) { | 137 | for (u = G(L)->rootudata; u; u = u->uv.next) |
130 | struct TM *tm = &G->TMtable[t]; | 138 | marktable(st, u->uv.eventtable); |
131 | int e; | ||
132 | if (tm->name) strmark(tm->name); | ||
133 | for (e=0; e<TM_N; e++) { | ||
134 | Closure *cl = tm->method[e]; | ||
135 | if (cl) markclosure(st, cl); | ||
136 | } | ||
137 | } | ||
138 | } | 139 | } |
139 | 140 | ||
140 | 141 | ||
@@ -152,6 +153,7 @@ static void traversetable (GCState *st, Table *h) { | |||
152 | h->mark = st->toclear; /* put in the appropriate list */ | 153 | h->mark = st->toclear; /* put in the appropriate list */ |
153 | st->toclear = h; | 154 | st->toclear = h; |
154 | } | 155 | } |
156 | marktable(st, h->eventtable); | ||
155 | if (!(mode & LUA_WEAK_VALUE)) { | 157 | if (!(mode & LUA_WEAK_VALUE)) { |
156 | i = sizearray(h); | 158 | i = sizearray(h); |
157 | while (i--) | 159 | while (i--) |
@@ -172,11 +174,9 @@ static void traversetable (GCState *st, Table *h) { | |||
172 | 174 | ||
173 | 175 | ||
174 | static void markall (lua_State *L, GCState *st) { | 176 | static void markall (lua_State *L, GCState *st) { |
175 | marktagmethods(G(L), st); /* mark tag methods */ | ||
176 | markstacks(L, st); /* mark all stacks */ | 177 | markstacks(L, st); /* mark all stacks */ |
177 | marktable(st, G(L)->type2tag); | 178 | markudet(L, st); /* mark userdata's event tables */ |
178 | markobject(st, &G(L)->registry); | 179 | while (st->tmark) { /* traverse marked tables */ |
179 | while (st->tmark) { /* mark tables */ | ||
180 | Table *h = st->tmark; /* get first table from list */ | 180 | Table *h = st->tmark; /* get first table from list */ |
181 | st->tmark = h->mark; /* remove it from list */ | 181 | st->tmark = h->mark; /* remove it from list */ |
182 | traversetable(st, h); | 182 | traversetable(st, h); |
@@ -189,7 +189,7 @@ static int hasmark (const TObject *o) { | |||
189 | case LUA_TSTRING: | 189 | case LUA_TSTRING: |
190 | return tsvalue(o)->tsv.marked; | 190 | return tsvalue(o)->tsv.marked; |
191 | case LUA_TUSERDATA: | 191 | case LUA_TUSERDATA: |
192 | return ismarkedudata(uvalue(o)); | 192 | return isudmarked(uvalue(o)); |
193 | case LUA_TTABLE: | 193 | case LUA_TTABLE: |
194 | return ismarked(hvalue(o)); | 194 | return ismarked(hvalue(o)); |
195 | case LUA_TFUNCTION: | 195 | case LUA_TFUNCTION: |
@@ -261,8 +261,9 @@ static void collectupval (lua_State *L) { | |||
261 | UpVal **v = &G(L)->rootupval; | 261 | UpVal **v = &G(L)->rootupval; |
262 | UpVal *curr; | 262 | UpVal *curr; |
263 | while ((curr = *v) != NULL) { | 263 | while ((curr = *v) != NULL) { |
264 | if (curr->mark) { | 264 | if (isupvalmarked(curr)) { |
265 | curr->mark = 0; | 265 | lua_assert(curr->v == NULL); |
266 | curr->v = &curr->value; /* unmark */ | ||
266 | v = &curr->next; /* next */ | 267 | v = &curr->next; /* next */ |
267 | } | 268 | } |
268 | else { | 269 | else { |
@@ -289,26 +290,27 @@ static void collecttable (lua_State *L) { | |||
289 | } | 290 | } |
290 | 291 | ||
291 | 292 | ||
292 | static void collectudata (lua_State *L, int keep) { | 293 | static Udata *collectudata (lua_State *L, int keep) { |
293 | Udata **p = &G(L)->rootudata; | 294 | Udata **p = &G(L)->rootudata; |
294 | Udata *curr; | 295 | Udata *curr; |
296 | Udata *collected = NULL; | ||
295 | while ((curr = *p) != NULL) { | 297 | while ((curr = *p) != NULL) { |
296 | if (ismarkedudata(curr)) { | 298 | if (isudmarked(curr)) { |
297 | switchudatamark(curr); /* unmark */ | 299 | unmarkud(curr); |
298 | p = &curr->uv.next; | 300 | p = &curr->uv.next; |
299 | } | 301 | } |
300 | else { /* collect */ | 302 | else { /* collect */ |
301 | int tag = curr->uv.tag; | 303 | const TObject *tm = fasttm(L, curr->uv.eventtable, TM_GC); |
302 | *p = curr->uv.next; | 304 | *p = curr->uv.next; |
303 | if (keep || /* must keep all of them (to close state)? */ | 305 | if (keep || tm != NULL) { |
304 | luaT_gettm(G(L), tag, TM_GC)) { /* or is there a GC tag method? */ | 306 | curr->uv.next = collected; |
305 | curr->uv.next = G(L)->TMtable[tag].collected; /* chain udata ... */ | 307 | collected = curr; |
306 | G(L)->TMtable[tag].collected = curr; /* ... to call its TM later */ | ||
307 | } | 308 | } |
308 | else /* no tag method; delete udata */ | 309 | else /* no gc action; delete udata */ |
309 | luaM_free(L, curr, sizeudata(curr->uv.len)); | 310 | luaM_free(L, curr, sizeudata(curr->uv.len)); |
310 | } | 311 | } |
311 | } | 312 | } |
313 | return collected; | ||
312 | } | 314 | } |
313 | 315 | ||
314 | 316 | ||
@@ -347,14 +349,14 @@ static void checkMbuffer (lua_State *L) { | |||
347 | } | 349 | } |
348 | 350 | ||
349 | 351 | ||
350 | static void callgcTM (lua_State *L, const TObject *obj) { | 352 | static void callgcTM (lua_State *L, Udata *udata) { |
351 | Closure *tm = luaT_gettmbyObj(G(L), obj, TM_GC); | 353 | const TObject *tm = fasttm(L, udata->uv.eventtable, TM_GC); |
352 | if (tm != NULL) { | 354 | if (tm != NULL && ttype(tm) == LUA_TFUNCTION) { |
353 | int oldah = L->allowhooks; | 355 | int oldah = L->allowhooks; |
354 | StkId top = L->top; | 356 | StkId top = L->top; |
355 | L->allowhooks = 0; /* stop debug hooks during GC tag methods */ | 357 | L->allowhooks = 0; /* stop debug hooks during GC tag methods */ |
356 | setclvalue(top, tm); | 358 | setobj(top, tm); |
357 | setobj(top+1, obj); | 359 | setuvalue(top+1, udata); |
358 | L->top += 2; | 360 | L->top += 2; |
359 | luaD_call(L, top); | 361 | luaD_call(L, top); |
360 | L->top = top; /* restore top */ | 362 | L->top = top; /* restore top */ |
@@ -363,53 +365,52 @@ static void callgcTM (lua_State *L, const TObject *obj) { | |||
363 | } | 365 | } |
364 | 366 | ||
365 | 367 | ||
366 | static void callgcTMudata (lua_State *L) { | 368 | static void callgcTMudata (lua_State *L, Udata *c) { |
367 | int tag; | ||
368 | luaD_checkstack(L, 3); | 369 | luaD_checkstack(L, 3); |
369 | for (tag=G(L)->ntag-1; tag>=0; tag--) { /* for each tag (in reverse order) */ | 370 | L->top++; /* reserve space to keep udata while runs its gc method */ |
370 | Udata *udata; | 371 | while (c != NULL) { |
371 | while ((udata = G(L)->TMtable[tag].collected) != NULL) { | 372 | Udata *udata = c; |
372 | G(L)->TMtable[tag].collected = udata->uv.next; /* remove it from list */ | 373 | c = udata->uv.next; /* remove udata from list */ |
373 | udata->uv.next = G(L)->rootudata; /* resurect it */ | 374 | udata->uv.next = G(L)->rootudata; /* resurect it */ |
374 | G(L)->rootudata = udata; | 375 | G(L)->rootudata = udata; |
375 | setuvalue(L->top, udata); | 376 | setuvalue(L->top - 1, udata); |
376 | L->top++; /* keep it in stack to avoid being (recursively) collected */ | 377 | callgcTM(L, udata); |
377 | callgcTM(L, L->top-1); | 378 | /* mark udata as finalized (default event table) */ |
378 | uvalue(L->top-1)->uv.tag = 0; /* default tag (udata is `finalized') */ | 379 | uvalue(L->top-1)->uv.eventtable = hvalue(defaultet(L)); |
379 | L->top--; | ||
380 | } | ||
381 | } | 380 | } |
381 | L->top--; | ||
382 | } | 382 | } |
383 | 383 | ||
384 | 384 | ||
385 | void luaC_callallgcTM (lua_State *L) { | 385 | void luaC_callallgcTM (lua_State *L) { |
386 | if (G(L)->rootudata) { /* avoid problems with incomplete states */ | 386 | if (G(L)->rootudata) { /* avoid problems with incomplete states */ |
387 | collectudata(L, 1); /* collect all udata into tag lists */ | 387 | Udata *c = collectudata(L, 1); /* collect all udata */ |
388 | callgcTMudata(L); /* call their GC tag methods */ | 388 | callgcTMudata(L, c); /* call their GC tag methods */ |
389 | } | 389 | } |
390 | } | 390 | } |
391 | 391 | ||
392 | 392 | ||
393 | void luaC_collect (lua_State *L, int all) { | 393 | Udata *luaC_collect (lua_State *L, int all) { |
394 | collectudata(L, 0); | 394 | Udata *c = collectudata(L, 0); |
395 | collectstrings(L, all); | 395 | collectstrings(L, all); |
396 | collecttable(L); | 396 | collecttable(L); |
397 | collectproto(L); | 397 | collectproto(L); |
398 | collectupval(L); | 398 | collectupval(L); |
399 | collectclosures(L); | 399 | collectclosures(L); |
400 | return c; | ||
400 | } | 401 | } |
401 | 402 | ||
402 | 403 | ||
403 | void luaC_collectgarbage (lua_State *L) { | 404 | void luaC_collectgarbage (lua_State *L) { |
405 | Udata *c; | ||
404 | GCState st; | 406 | GCState st; |
405 | st.tmark = NULL; | 407 | st.tmark = NULL; |
406 | st.toclear = NULL; | 408 | st.toclear = NULL; |
407 | markall(L, &st); | 409 | markall(L, &st); |
408 | cleartables(st.toclear); | 410 | cleartables(st.toclear); |
409 | luaC_collect(L, 0); | 411 | c = luaC_collect(L, 0); |
410 | checkMbuffer(L); | 412 | checkMbuffer(L); |
411 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ | 413 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ |
412 | callgcTMudata(L); | 414 | callgcTMudata(L, c); |
413 | callgcTM(L, &luaO_nilobject); | ||
414 | } | 415 | } |
415 | 416 | ||