aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lgc.c106
-rw-r--r--lgc.h30
-rw-r--r--lstate.c8
-rw-r--r--lstate.h31
-rw-r--r--ltests.c14
5 files changed, 89 insertions, 100 deletions
diff --git a/lgc.c b/lgc.c
index 0d0579d0..598fc9d4 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.45 2008/06/23 16:51:28 roberto Exp roberto $ 2** $Id: lgc.c,v 2.46 2008/06/23 22:07:44 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*/
@@ -79,7 +79,7 @@ static void removeentry (Node *n) {
79** The next function tells whether a key or value can be cleared from 79** The next function tells whether a key or value can be cleared from
80** a weak table. Non-collectable objects are never removed from weak 80** a weak table. Non-collectable objects are never removed from weak
81** tables. Strings behave as `values', so are never removed too. for 81** tables. Strings behave as `values', so are never removed too. for
82** other objects: if really collected, cannot keep them; for userdata 82** other objects: if really collected, cannot keep them; for objects
83** being finalized, keep them in keys, but not in values 83** being finalized, keep them in keys, but not in values
84*/ 84*/
85static int iscleared (const TValue *o, int iskey) { 85static int iscleared (const TValue *o, int iskey) {
@@ -205,14 +205,11 @@ static void markmt (global_State *g) {
205 205
206 206
207static void markbeingfnz (global_State *g) { 207static void markbeingfnz (global_State *g) {
208 GCObject *u = g->tobefnz; 208 GCObject *o;
209 if (u) { 209 for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
210 do { 210 lua_assert(testbit(gch(o)->marked, SEPARATED));
211 u = gch(u)->next; 211 makewhite(g, o);
212 lua_assert(testbit(gch(u)->marked, SEPARATED)); 212 reallymarkobject(g, o);
213 makewhite(g, u);
214 reallymarkobject(g, u);
215 } while (u != g->tobefnz);
216 } 213 }
217} 214}
218 215
@@ -228,7 +225,7 @@ static void markroot (lua_State *L) {
228 markvalue(g, gt(g->mainthread)); 225 markvalue(g, gt(g->mainthread));
229 markvalue(g, registry(L)); 226 markvalue(g, registry(L));
230 markmt(g); 227 markmt(g);
231 markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ 228 markbeingfnz(g); /* mark any finalizing object left from previous cycle */
232 g->gcstate = GCSpropagate; 229 g->gcstate = GCSpropagate;
233} 230}
234 231
@@ -573,17 +570,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
573 return p; 570 return p;
574} 571}
575 572
576
577/* sweep list where all objects are alive (dead udata were removed
578 when separated from this list) */
579static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) {
580 for (; *p != NULL && count-- > 0; p = &gch(*p)->next) {
581 lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p));
582 makewhite(g, *p);
583 }
584 return p;
585}
586
587/* }====================================================== */ 573/* }====================================================== */
588 574
589 575
@@ -602,18 +588,14 @@ static void checkSizes (lua_State *L) {
602 588
603 589
604static Udata *udata2finalize (global_State *g) { 590static Udata *udata2finalize (global_State *g) {
605 GCObject *o = gch(g->tobefnz)->next; /* get first element */ 591 GCObject *o = g->tobefnz; /* get first element */
606 Udata *udata = rawgco2u(o); 592 g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
607 /* remove udata from `tobefnz' */ 593 gch(o)->next = g->rootgc; /* return it to `root' list */
608 if (o == g->tobefnz) /* last element? */ 594 g->rootgc = o;
609 g->tobefnz = NULL; 595 lua_assert(isfinalized(gch(o)));
610 else 596 resetbit(gch(o)->marked, SEPARATED); /* mark it as such */
611 gch(g->tobefnz)->next = udata->uv.next;
612 udata->uv.next = g->mainthread->next; /* return it to `root' list */
613 g->mainthread->next = o;
614 resetbit(udata->uv.marked, SEPARATED); /* mark it as such */
615 makewhite(g, o); 597 makewhite(g, o);
616 return udata; 598 return rawgco2u(o);
617} 599}
618 600
619 601
@@ -639,28 +621,21 @@ static void GCTM (lua_State *L) {
639/* 621/*
640** Call all GC tag methods 622** Call all GC tag methods
641*/ 623*/
642void luaC_callGCTM (lua_State *L) { 624void luaC_callAllGCTM (lua_State *L) {
643 global_State *g = G(L); 625 while (G(L)->tobefnz) GCTM(L);
644 GCObject *last = g->tobefnz;
645 GCObject *curr;
646 if (last == NULL) return; /* empty list? */
647 do {
648 curr = gch(g->tobefnz)->next; /* element to be collected */
649 GCTM(L);
650 } while (curr != last); /* go only until original last */
651 /* do not finalize new udata created during previous finalizations */
652 while (g->tobefnz)
653 udata2finalize(g); /* simply remove them from list */
654} 626}
655 627
656 628
657/* move 'dead' udata that need finalization to list 'tobefnz' */ 629/* move 'dead' udata that need finalization to list 'tobefnz' */
658size_t luaC_separateudata (lua_State *L, int all) { 630size_t luaC_separateudata (lua_State *L, int all) {
659 global_State *g = G(L); 631 global_State *g = G(L);
660 size_t deadmem = 0; 632 size_t deadmem = 0; /* total size of all objects to be finalized */
661 GCObject **p = &g->tmudata; 633 GCObject **p = &g->mainthread->next;
662 GCObject *curr; 634 GCObject *curr;
663 while ((curr = *p) != NULL) { 635 GCObject **lastnext = &g->tobefnz;
636 /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */
637 while (*lastnext != NULL) lastnext = &gch(*lastnext)->next;
638 while ((curr = *p) != NULL) { /* traverse all finalizable objects */
664 lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); 639 lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr)));
665 lua_assert(testbit(gch(curr)->marked, SEPARATED)); 640 lua_assert(testbit(gch(curr)->marked, SEPARATED));
666 if (!(all || iswhite(curr))) /* not being collected? */ 641 if (!(all || iswhite(curr))) /* not being collected? */
@@ -668,15 +643,11 @@ size_t luaC_separateudata (lua_State *L, int all) {
668 else { 643 else {
669 l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ 644 l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
670 deadmem += sizeudata(gco2u(curr)); 645 deadmem += sizeudata(gco2u(curr));
671 *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ 646 *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */
672 /* link 'curr' at the end of 'tobefnz' list */ 647 /* link 'curr' at the end of 'tobefnz' list */
673 if (g->tobefnz == NULL) /* list is empty? */ 648 gch(curr)->next = *lastnext;
674 g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ 649 *lastnext = curr;
675 else { 650 lastnext = &gch(curr)->next;
676 gch(curr)->next = gch(g->tobefnz)->next;
677 gch(g->tobefnz)->next = curr;
678 g->tobefnz = curr;
679 }
680 } 651 }
681 } 652 }
682 return deadmem; 653 return deadmem;
@@ -689,13 +660,13 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) {
689 isfinalized(&u->uv) || /* ... or is finalized... */ 660 isfinalized(&u->uv) || /* ... or is finalized... */
690 gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ 661 gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
691 return; /* nothing to be done */ 662 return; /* nothing to be done */
692 else { /* move 'u' from root list to 'tmudata' list */ 663 else { /* move 'u' to 2nd part of root list */
693 GCObject **p; 664 GCObject **p;
694 for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) 665 for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
695 lua_assert(*p != NULL); /* 'u' must be in this list */ 666 lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */
696 *p = u->uv.next; /* remove 'u' from root list */ 667 *p = u->uv.next; /* remove 'u' from root list */
697 u->uv.next = g->tmudata; /* link it in 'tmudata' list */ 668 u->uv.next = g->mainthread->next; /* re-link it in list */
698 g->tmudata = obj2gco(u); 669 g->mainthread->next = obj2gco(u);
699 l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ 670 l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
700 } 671 }
701} 672}
@@ -716,9 +687,8 @@ void luaC_freeall (lua_State *L) {
716 /* mask to collect all elements */ 687 /* mask to collect all elements */
717 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); 688 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
718 sweepwholelist(L, &g->rootgc); 689 sweepwholelist(L, &g->rootgc);
719 lua_assert(g->rootgc == obj2gco(L)); 690 lua_assert(g->rootgc == obj2gco(g->mainthread));
720 sweepwholelist(L, &g->tmudata); 691 lua_assert(g->mainthread->next == NULL);
721 lua_assert(g->tmudata == NULL);
722 for (i = 0; i < g->strt.size; i++) /* free all string lists */ 692 for (i = 0; i < g->strt.size; i++) /* free all string lists */
723 sweepwholelist(L, &g->strt.hash[i]); 693 sweepwholelist(L, &g->strt.hash[i]);
724 lua_assert(g->strt.nuse == 0); 694 lua_assert(g->strt.nuse == 0);
@@ -781,18 +751,10 @@ static l_mem singlestep (lua_State *L) {
781 case GCSsweepstring: { 751 case GCSsweepstring: {
782 correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); 752 correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]));
783 if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ 753 if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */
784 g->sweepgc = &g->tmudata;
785 g->gcstate = GCSsweeptmu; /* end sweep-string phase */
786 }
787 return GCSWEEPCOST;
788 }
789 case GCSsweeptmu: {
790 g->sweepgc = unmarklist(g, g->sweepgc, GCSWEEPMAX);
791 if (*g->sweepgc == NULL) { /* nothing more to sweep? */
792 g->sweepgc = &g->rootgc; 754 g->sweepgc = &g->rootgc;
793 g->gcstate = GCSsweep; /* sweep all other objects */ 755 g->gcstate = GCSsweep; /* sweep all other objects */
794 } 756 }
795 return GCSWEEPMAX*GCSWEEPCOST; 757 return GCSWEEPCOST;
796 } 758 }
797 case GCSsweep: { 759 case GCSsweep: {
798 correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); 760 correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX));
diff --git a/lgc.h b/lgc.h
index 6697ec26..1f6ba08e 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.h,v 2.17 2007/10/29 16:51:20 roberto Exp roberto $ 2** $Id: lgc.h,v 2.18 2008/02/19 18:55:09 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*/
@@ -17,26 +17,24 @@
17#define GCSpause 0 17#define GCSpause 0
18#define GCSpropagate 1 18#define GCSpropagate 1
19#define GCSsweepstring 2 19#define GCSsweepstring 2
20#define GCSsweeptmu 3 20#define GCSsweep 3
21#define GCSsweep 4 21#define GCSfinalize 4
22#define GCSfinalize 5
23 22
24 23
25#define issweep(g) \ 24#define issweep(g) (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
26 (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
27 25
28 26
29/* 27/*
30** some userful bit tricks 28** some userful bit tricks
31*/ 29*/
32#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) 30#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
33#define setbits(x,m) ((x) |= (m)) 31#define setbits(x,m) ((x) |= (m))
34#define testbits(x,m) ((x) & (m)) 32#define testbits(x,m) ((x) & (m))
35#define bitmask(b) (1<<(b)) 33#define bitmask(b) (1<<(b))
36#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) 34#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
37#define l_setbit(x,b) setbits(x, bitmask(b)) 35#define l_setbit(x,b) setbits(x, bitmask(b))
38#define resetbit(x,b) resetbits(x, bitmask(b)) 36#define resetbit(x,b) resetbits(x, bitmask(b))
39#define testbit(x,b) testbits(x, bitmask(b)) 37#define testbit(x,b) testbits(x, bitmask(b))
40#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) 38#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2)))
41#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) 39#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2)))
42 40
@@ -48,7 +46,7 @@
48** bit 1 - object is white (type 1) 46** bit 1 - object is white (type 1)
49** bit 2 - object is black 47** bit 2 - object is black
50** bit 3 - for userdata: has been finalized 48** bit 3 - for userdata: has been finalized
51** bit 4 - for userdata: it's not in rootgc list (it's in tmudata or tobefnz) 49** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz
52** bit 5 - object is fixed (should not be collected) 50** bit 5 - object is fixed (should not be collected)
53** bit 6 - object is "super" fixed (only the main thread) 51** bit 6 - object is "super" fixed (only the main thread)
54*/ 52*/
@@ -99,7 +97,7 @@
99 { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } 97 { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
100 98
101LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); 99LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
102LUAI_FUNC void luaC_callGCTM (lua_State *L); 100LUAI_FUNC void luaC_callAllGCTM (lua_State *L);
103LUAI_FUNC void luaC_freeall (lua_State *L); 101LUAI_FUNC void luaC_freeall (lua_State *L);
104LUAI_FUNC void luaC_step (lua_State *L); 102LUAI_FUNC void luaC_step (lua_State *L);
105LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); 103LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
diff --git a/lstate.c b/lstate.c
index a7e1e540..8a672eb8 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.43 2008/02/11 15:45:30 roberto Exp roberto $ 2** $Id: lstate.c,v 2.44 2008/02/19 18:55:09 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*/
@@ -181,7 +181,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
181 g->gray = NULL; 181 g->gray = NULL;
182 g->grayagain = NULL; 182 g->grayagain = NULL;
183 g->weak = g->ephemeron = g->allweak = NULL; 183 g->weak = g->ephemeron = g->allweak = NULL;
184 g->tmudata = g->tobefnz = NULL; 184 g->tobefnz = NULL;
185 g->totalbytes = sizeof(LG); 185 g->totalbytes = sizeof(LG);
186 g->gcpause = LUAI_GCPAUSE; 186 g->gcpause = LUAI_GCPAUSE;
187 g->gcstepmul = LUAI_GCMUL; 187 g->gcstepmul = LUAI_GCMUL;
@@ -200,7 +200,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
200 200
201static void callallgcTM (lua_State *L, void *ud) { 201static void callallgcTM (lua_State *L, void *ud) {
202 UNUSED(ud); 202 UNUSED(ud);
203 luaC_callGCTM(L); /* call GC metamethods for all udata */ 203 luaC_callAllGCTM(L); /* call GC metamethods for all udata */
204} 204}
205 205
206 206
@@ -209,7 +209,7 @@ LUA_API void lua_close (lua_State *L) {
209 lua_lock(L); 209 lua_lock(L);
210 luaF_close(L, L->stack); /* close all upvalues for this thread */ 210 luaF_close(L, L->stack); /* close all upvalues for this thread */
211 luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ 211 luaC_separateudata(L, 1); /* separate all udata with GC metamethods */
212 lua_assert(G(L)->tmudata == NULL); 212 lua_assert(L->next == NULL);
213 L->errfunc = 0; /* no error function during GC metamethods */ 213 L->errfunc = 0; /* no error function during GC metamethods */
214 do { /* repeat until no more errors */ 214 do { /* repeat until no more errors */
215 L->ci = L->base_ci; 215 L->ci = L->base_ci;
diff --git a/lstate.h b/lstate.h
index 20eb8804..dec27d24 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.32 2008/02/19 18:55:09 roberto Exp roberto $ 2** $Id: lstate.h,v 2.33 2008/06/23 16:51:08 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*/
@@ -14,6 +14,32 @@
14#include "lzio.h" 14#include "lzio.h"
15 15
16 16
17/*
18
19** Some notes about garbage-collected objects: All objects in Lua must
20** be kept somehow accessible until being freed.
21**
22** Lua keeps most objects linked in list g->rootgc. The link uses field
23** 'next' of the CommonHeader.
24**
25** Strings are kept in several lists headed by the array g->strt.hash.
26**
27** Open upvalues are not subject to independent garbage collection. They
28** are collected together with their respective threads. Lua keeps a
29** double-linked list with all open upvalues (g->uvhead) so that it can
30** mark objects referred by them. (They are always gray, so they must
31** be remarked in the atomic step. Usually their contents would be marked
32** when traversing the respective threads, but the thread may already be
33** dead, while the upvalue is still accessible through closures.)
34**
35** Userdata with finalizers are kept in the list g->rootgc, but after
36** the mainthread, which should be otherwise the last element in the
37** list, as it was the first one inserted there.
38**
39** The list g->tobefnz links all userdata being finalized.
40
41*/
42
17 43
18struct lua_longjmp; /* defined in ldo.c */ 44struct lua_longjmp; /* defined in ldo.c */
19 45
@@ -86,8 +112,7 @@ typedef struct global_State {
86 GCObject *weak; /* list of tables with weak values */ 112 GCObject *weak; /* list of tables with weak values */
87 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ 113 GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
88 GCObject *allweak; /* list of all-weak tables */ 114 GCObject *allweak; /* list of all-weak tables */
89 GCObject *tmudata; /* list of userdata with finalizers */ 115 GCObject *tobefnz; /* list of userdata to be GC */
90 GCObject *tobefnz; /* last element of list of userdata to be GC */
91 Mbuffer buff; /* temporary buffer for string concatentation */ 116 Mbuffer buff; /* temporary buffer for string concatentation */
92 lu_mem GCthreshold; 117 lu_mem GCthreshold;
93 lu_mem totalbytes; /* number of bytes currently allocated */ 118 lu_mem totalbytes; /* number of bytes currently allocated */
diff --git a/ltests.c b/ltests.c
index 3826d424..a7882ed9 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 2.51 2008/06/13 17:07:10 roberto Exp roberto $ 2** $Id: ltests.c,v 2.52 2008/06/23 16:50:34 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*/
@@ -365,10 +365,15 @@ int lua_checkmemory (lua_State *L) {
365 GCObject *o; 365 GCObject *o;
366 UpVal *uv; 366 UpVal *uv;
367 checkstack(g, g->mainthread); 367 checkstack(g, g->mainthread);
368 for (o = g->rootgc; o != NULL; o = gch(o)->next) 368 for (o = g->rootgc; o != obj2gco(g->mainthread); o = gch(o)->next) {
369 lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT)));
369 checkobject(g, o); 370 checkobject(g, o);
370 for (o = g->tmudata; o != NULL; o = gch(o)->next) { 371 }
371 lua_assert(!isdead(g, o)); 372 lua_assert(testbit(o->gch.marked, SFIXEDBIT));
373 for (o = gch(o)->next; o != NULL; o = gch(o)->next) {
374 lua_assert(gch(o)->tt == LUA_TUSERDATA &&
375 !isdead(g, o) &&
376 testbit(o->gch.marked, SEPARATED));
372 checkobject(g, o); 377 checkobject(g, o);
373 } 378 }
374 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { 379 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
@@ -535,7 +540,6 @@ static int gcstate (lua_State *L) {
535 switch(G(L)->gcstate) { 540 switch(G(L)->gcstate) {
536 case GCSpropagate: lua_pushstring(L, "propagate"); break; 541 case GCSpropagate: lua_pushstring(L, "propagate"); break;
537 case GCSsweepstring: lua_pushstring(L, "sweep strings"); break; 542 case GCSsweepstring: lua_pushstring(L, "sweep strings"); break;
538 case GCSsweeptmu: lua_pushstring(L, "sweep udata with __gc"); break;
539 case GCSsweep: lua_pushstring(L, "sweep"); break; 543 case GCSsweep: lua_pushstring(L, "sweep"); break;
540 case GCSfinalize: lua_pushstring(L, "finalize"); break; 544 case GCSfinalize: lua_pushstring(L, "finalize"); break;
541 default: lua_assert(0); 545 default: lua_assert(0);