klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

kgc.c (27848B)


      1 /*
      2 ** kgc.c
      3 ** Garbage Collector
      4 ** See Copyright Notice in klisp.h
      5 */
      6 
      7 /*
      8 ** SOURCE NOTE: This is almost textually from lua.
      9 ** Parts that don't apply, or don't apply yet to klisp are in comments.
     10 */
     11 
     12 /* 
     13 ** LOCK: no locks are explicitly acquired here.
     14 ** Whoever calls the GC needs to have already acquired the GIL.
     15 */
     16 
     17 #include <string.h>
     18 
     19 #include "kgc.h"
     20 #include "kobject.h"
     21 #include "kstate.h"
     22 #include "kmem.h"
     23 #include "kport.h"
     24 #include "imath.h"
     25 #include "imrat.h"
     26 #include "ktable.h"
     27 #include "kstring.h"
     28 #include "kbytevector.h"
     29 #include "kvector.h"
     30 #include "kmutex.h"
     31 #include "kcondvar.h"
     32 #include "kerror.h"
     33 
     34 #define GCSTEPSIZE	1024u
     35 #define GCSWEEPMAX	40
     36 #define GCSWEEPCOST	10
     37 #define GCFINALIZECOST	100 /* klisp: NOT USED YET */
     38 
     39 
     40 
     41 #define maskmarks	cast(uint16_t, ~(bitmask(BLACKBIT)|WHITEBITS))
     42 
     43 #define makewhite(g,x)                                                  \
     44     ((x)->gch.gct = cast(uint16_t,                                      \
     45                          ((x)->gch.gct & maskmarks) | klispC_white(g)))
     46 
     47 #define white2gray(x)	reset2bits((x)->gch.gct, WHITE0BIT, WHITE1BIT)
     48 #define black2gray(x)	resetbit((x)->gch.gct, BLACKBIT)
     49 
     50 /* NOTE: klisp strings, unlike the lua counterparts are not values,
     51    so they are marked as other objects */
     52 
     53 /* klisp: NOT USED YET */
     54 #define isfinalized(u)		testbit((u)->gct, FINALIZEDBIT)
     55 #define markfinalized(u)	k_setbit((u)->gct, FINALIZEDBIT)
     56 
     57 /* klisp: NOT USED YET */
     58 #define KEYWEAK            bitmask(KEYWEAKBIT)
     59 #define VALUEWEAK          bitmask(VALUEWEAKBIT)
     60 
     61 /* this one is klisp specific */
     62 #define markvaluearray(g, a, s) ({                              \
     63             TValue *array_ = (a);                               \
     64             int32_t size_ = (s);                                \
     65             for(int32_t i_ = 0; i_ < size_; i_++, array_++) {	\
     66                 TValue mva_obj_ = *array_;                      \
     67                 markvalue(g, mva_obj_);                         \
     68             }})
     69 
     70 #define markvalue(k,o) { checkconsistency(o);		    \
     71         if (iscollectable(o) && iswhite(gcvalue(o)))    \
     72             reallymarkobject(k,gcvalue(o)); }
     73 
     74 #define markobject(k,t) { if (iswhite(obj2gco(t)))	\
     75             reallymarkobject(k, obj2gco(t)); }
     76 
     77 
     78 #define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause)
     79 
     80 static void removeentry (Node *n) {
     81     klisp_assert(ttisfree(gval(n)));
     82     if (iscollectable(gkey(n)->this))/* dead key; remove it */
     83         gkey(n)->this = gc2deadkey(gcvalue(gkey(n)->this));
     84 }
     85 
     86 static void reallymarkobject (global_State *g, GCObject *o) 
     87 {
     88     klisp_assert(iswhite(o) && !isdead(g, o));
     89     white2gray(o);
     90     /* klisp: most of klisp have the same structure, but conserve the switch
     91        just in case. */
     92     uint8_t type = o->gch.tt;
     93     switch (type) {
     94 /* klisp: keep this around just in case we add it later */
     95 #if 0
     96     case LUA_TUSERDATA: {
     97         Table *mt = gco2u(o)->metatable;
     98         gray2black(o);  /* udata are never gray */
     99         if (mt) markobject(g, mt);
    100         markobject(g, gco2u(o)->env);
    101         return;
    102     }
    103 #endif
    104     case K_TBIGRAT: /* the n & d are copied in the bigrat, not pointed to */
    105     case K_TBIGINT:
    106         gray2black(o);  /* bigint & bigrats are never gray */
    107         break;
    108     case K_TPAIR:
    109     case K_TSYMBOL:
    110     case K_TKEYWORD:
    111     case K_TSTRING:
    112     case K_TENVIRONMENT:
    113     case K_TCONTINUATION:
    114     case K_TOPERATIVE:
    115     case K_TAPPLICATIVE:
    116     case K_TENCAPSULATION:
    117     case K_TPROMISE:
    118     case K_TTABLE:
    119     case K_TERROR:
    120     case K_TBYTEVECTOR:
    121     case K_TVECTOR:
    122     case K_TFPORT:
    123     case K_TMPORT:
    124     case K_TLIBRARY:
    125     case K_TTHREAD:
    126     case K_TMUTEX:
    127     case K_TCONDVAR:
    128         o->gch.gclist = g->gray;
    129         g->gray = o;
    130         break;
    131     default:
    132         /* shouldn't happen */
    133         fprintf(stderr, "Unknown GCObject type (in GC mark): %d\n", type);
    134         abort();
    135     }
    136 }
    137 
    138 
    139 /* klisp: keep this around just in case we add it later */
    140 #if 0
    141 static void marktmu (global_State *g) {
    142     GCObject *u = g->tmudata;
    143     if (u) {
    144         do {
    145             u = u->gch.next;
    146             makewhite(g, u);  /* may be marked, if left from previous GC */
    147             reallymarkobject(g, u);
    148         } while (u != g->tmudata);
    149     }
    150 }
    151 
    152 /* move `dead' udata that need finalization to list `tmudata' */
    153 size_t klispC_separateudata (lua_State *L, int all) {
    154     global_State *g = G(L);
    155     size_t deadmem = 0;
    156     GCObject **p = &g->mainthread->next;
    157     GCObject *curr;
    158     while ((curr = *p) != NULL) {
    159         if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
    160             p = &curr->gch.next;  /* don't bother with them */
    161         else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
    162             markfinalized(gco2u(curr));  /* don't need finalization */
    163             p = &curr->gch.next;
    164         }
    165         else {  /* must call its gc method */
    166             deadmem += sizeudata(gco2u(curr));
    167             markfinalized(gco2u(curr));
    168             *p = curr->gch.next;
    169             /* link `curr' at the end of `tmudata' list */
    170             if (g->tmudata == NULL)  /* list is empty? */
    171                 /* creates a circular list */
    172                 g->tmudata = curr->gch.next = curr;  
    173             else {
    174                 curr->gch.next = g->tmudata->gch.next;
    175                 g->tmudata->gch.next = curr;
    176                 g->tmudata = curr;
    177             }
    178         }
    179     }
    180     return deadmem;
    181 }
    182 
    183 #endif
    184 
    185 static int32_t traversetable (global_State *g, Table *h) {
    186     int32_t i;
    187     TValue tv = gc2table(h);
    188     int32_t weakkey = ktable_has_weak_keys(tv)? 1 : 0;
    189     int32_t weakvalue = ktable_has_weak_values(tv)? 1 : 0;
    190 
    191     if (weakkey || weakvalue) {  /* is really weak? */
    192         h->gct &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
    193         h->gct |= cast(uint16_t, (weakkey << KEYWEAKBIT) |
    194                        (weakvalue << VALUEWEAKBIT));
    195         h->gclist = g->weak;  /* must be cleared after GC, ... */
    196         g->weak = obj2gco(h);  /* ... so put in the appropriate list */
    197     }
    198     if (weakkey && weakvalue) return 1;
    199     if (!weakvalue) {
    200         i = h->sizearray;
    201         while (i--)
    202             markvalue(g, h->array[i]);
    203     }
    204     i = sizenode(h);
    205     while (i--) {
    206         Node *n = gnode(h, i);
    207         klisp_assert(ttype(gkey(n)->this) != K_TDEADKEY || 
    208                      ttisfree(gval(n)));
    209         if (ttisfree(gval(n)))
    210             removeentry(n);  /* remove empty entries */
    211         else {
    212             klisp_assert(!ttisfree(gkey(n)->this));
    213             if (!weakkey) markvalue(g, gkey(n)->this);
    214             if (!weakvalue) markvalue(g, gval(n));
    215         }
    216     }
    217     return weakkey || weakvalue;
    218 }
    219 
    220 #if 0
    221 /*
    222 ** All marks are conditional because a GC may happen while the
    223 ** prototype is still being created
    224 */
    225 static void traverseproto (global_State *g, Proto *f) {
    226     int i;
    227     if (f->source) stringmark(f->source);
    228     for (i=0; i<f->sizek; i++)  /* mark literals */
    229         markvalue(g, &f->k[i]);
    230     for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */
    231         if (f->upvalues[i])
    232             stringmark(f->upvalues[i]);
    233     }
    234     for (i=0; i<f->sizep; i++) {  /* mark nested protos */
    235         if (f->p[i])
    236             markobject(g, f->p[i]);
    237     }
    238     for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */
    239         if (f->locvars[i].varname)
    240             stringmark(f->locvars[i].varname);
    241     }
    242 }
    243 
    244 #endif
    245 
    246 /*
    247 ** traverse one gray object, turning it to black.
    248 ** Returns `quantity' traversed.
    249 */
    250 static int32_t propagatemark (global_State *g) {
    251     GCObject *o = g->gray;
    252     g->gray = o->gch.gclist;
    253     klisp_assert(isgray(o));
    254     gray2black(o);
    255     /* all types have si pointers */
    256     if (o->gch.si != NULL) {
    257         markobject(g, o->gch.si);
    258     }
    259     uint8_t type = o->gch.tt;
    260 
    261     switch (type) {
    262 /*    case K_TBIGRAT: 
    263       case K_TBIGINT: bigints & bigrats are never gray */
    264     case K_TPAIR: {
    265         Pair *p = cast(Pair *, o);
    266         markvalue(g, p->mark);
    267         markvalue(g, p->car);
    268         markvalue(g, p->cdr);
    269         return sizeof(Pair);
    270     }
    271     case K_TSYMBOL: {
    272         Symbol *s = cast(Symbol *, o);
    273         markvalue(g, s->str);
    274         return sizeof(Symbol);
    275     }
    276     case K_TKEYWORD: {
    277         Keyword *k = cast(Keyword *, o);
    278         markvalue(g, k->str);
    279         return sizeof(Keyword);
    280     }
    281     case K_TSTRING: {
    282         String *s = cast(String *, o);
    283         markvalue(g, s->mark); 
    284         return sizeof(String) + (s->size + 1 * sizeof(char));
    285     }
    286     case K_TENVIRONMENT: {
    287         Environment *e = cast(Environment *, o);
    288         markvalue(g, e->mark); 
    289         markvalue(g, e->parents); 
    290         markvalue(g, e->bindings); 
    291         markvalue(g, e->keyed_node); 
    292         markvalue(g, e->keyed_parents); 
    293         return sizeof(Environment);
    294     }
    295     case K_TCONTINUATION: {
    296         Continuation *c = cast(Continuation *, o);
    297         markvalue(g, c->mark);
    298         markvalue(g, c->parent);
    299         markvalue(g, c->comb);
    300         markvaluearray(g, c->extra, c->extra_size);
    301         return sizeof(Continuation) + sizeof(TValue) * c->extra_size;
    302     }
    303     case K_TOPERATIVE: {
    304         Operative *op = cast(Operative *, o);
    305         markvaluearray(g, op->extra, op->extra_size);
    306         return sizeof(Operative) + sizeof(TValue) * op->extra_size;
    307     }
    308     case K_TAPPLICATIVE: {
    309         Applicative *a = cast(Applicative *, o);
    310         markvalue(g, a->underlying);
    311         return sizeof(Applicative);
    312     }
    313     case K_TENCAPSULATION: {
    314         Encapsulation *e = cast(Encapsulation *, o);
    315         markvalue(g, e->key);
    316         markvalue(g, e->value);
    317         return sizeof(Encapsulation);
    318     }
    319     case K_TPROMISE: {
    320         Promise *p = cast(Promise *, o);
    321         markvalue(g, p->node);
    322         return sizeof(Promise);
    323     }
    324     case K_TTABLE: {
    325         Table *h = cast(Table *, o);
    326         if (traversetable(g, h))  /* table is weak? */
    327             black2gray(o);  /* keep it gray */
    328         return sizeof(Table) + sizeof(TValue) * h->sizearray +
    329             sizeof(Node) * sizenode(h);
    330     }
    331     case K_TERROR: {
    332         Error *e = cast(Error *, o);
    333         markvalue(g, e->who);
    334         markvalue(g, e->cont);
    335         markvalue(g, e->msg);
    336         markvalue(g, e->irritants);
    337         return sizeof(Error);
    338     }
    339     case K_TBYTEVECTOR: {
    340         Bytevector *b = cast(Bytevector *, o);
    341         markvalue(g, b->mark); 
    342         return sizeof(Bytevector) + b->size * sizeof(uint8_t);
    343     }
    344     case K_TFPORT: {
    345         FPort *p = cast(FPort *, o);
    346         markvalue(g, p->filename);
    347         return sizeof(FPort);
    348     }
    349     case K_TMPORT: {
    350         MPort *p = cast(MPort *, o);
    351         markvalue(g, p->filename);
    352         markvalue(g, p->buf);
    353         return sizeof(MPort);
    354     }
    355     case K_TVECTOR: {
    356         Vector *v = cast(Vector *, o);
    357         markvalue(g, v->mark);
    358         markvaluearray(g, v->array, v->sizearray);
    359         return sizeof(Vector) + v->sizearray * sizeof(TValue);
    360     }
    361     case K_TLIBRARY: {
    362         Library *l = cast(Library *, o);
    363         markvalue(g, l->env);
    364         markvalue(g, l->exp_list);
    365         return sizeof(Library);
    366     }
    367     case K_TTHREAD: {
    368         klisp_State *K = cast(klisp_State *, o);
    369 
    370         markvalue(g, K->curr_cont);
    371         markvalue(g, K->next_obj);
    372         markvalue(g, K->next_value);
    373         markvalue(g, K->next_env);
    374         markvalue(g, K->next_si);
    375         /* NOTE: next_x_params is protected by next_obj */
    376 
    377         markvalue(g, K->shared_dict);
    378         markvalue(g, K->curr_port);
    379 
    380         /* Mark all objects in the auxiliary stack,
    381            (all valid indexes are below top) and all the objects in
    382            the two protected areas */
    383         markvaluearray(g, K->sbuf, K->stop);
    384         markvaluearray(g, K->rooted_tvs_buf, K->rooted_tvs_top);
    385         /* the area protecting variables is an array of type TValue *[] */
    386         TValue **ptr = K->rooted_vars_buf;
    387         for (int i = 0, top = K->rooted_vars_top; i < top; i++, ptr++) {
    388             markvalue(g, **ptr);
    389         }
    390         return sizeof(klisp_State) + (sizeof(TValue) * K->stop);
    391     }
    392     case K_TMUTEX: {
    393         Mutex *m = cast(Mutex *, o);
    394 
    395         markvalue(g, m->owner);
    396         return sizeof(Mutex);
    397     }
    398     case K_TCONDVAR: {
    399         Condvar *c = cast(Condvar *, o);
    400 
    401         markvalue(g, c->mutex);
    402         return sizeof(Condvar);
    403     }
    404     default: 
    405         fprintf(stderr, "Unknown GCObject type (in GC propagate): %d\n", 
    406                 type);
    407         abort();
    408     }
    409 }
    410 
    411 
    412 static size_t propagateall (global_State *g) {
    413     size_t m = 0;
    414     while (g->gray) m += propagatemark(g);
    415     return m;
    416 }
    417 
    418 /*
    419 ** The next function tells whether a key or value can be cleared from
    420 ** a weak table. Non-collectable objects are never removed from weak
    421 ** tables. Strings behave as `values', so are never removed too. for
    422 ** other objects: if really collected, cannot keep them; for userdata
    423 ** being finalized, keep them in keys, but not in values
    424 */
    425 /* XXX what the hell is this, I should reread this part of the lua
    426    source Andres Navarro */
    427 static int32_t iscleared (TValue o, int iskey) {
    428     if (!iscollectable(o)) return 0;
    429 #if 0 /* klisp: strings may be mutable... */
    430     if (ttisstring(o)) {
    431         stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */
    432         return 0;
    433     }
    434 #endif
    435     return iswhite(gcvalue(o));
    436 
    437 /* klisp: keep around for later
    438    || (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
    439 */
    440 }
    441 
    442 
    443 /*
    444 ** clear collected entries from weaktables
    445 */
    446 static void cleartable (GCObject *l) {
    447     while (l) {
    448         Table *h = (Table *) (l);
    449         int32_t i = h->sizearray;
    450         klisp_assert(testbit(h->gct, VALUEWEAKBIT) ||
    451                      testbit(h->gct, KEYWEAKBIT));
    452         if (testbit(h->gct, VALUEWEAKBIT)) {
    453             while (i--) {
    454                 TValue *o = &h->array[i];
    455                 if (iscleared(*o, 0))  /* value was collected? */
    456                     *o = KFREE;  /* remove value */
    457             }
    458         }
    459         i = sizenode(h);
    460         while (i--) {
    461             Node *n = gnode(h, i);
    462             if (!ttisfree(gval(n)) &&  /* non-empty entry? */
    463                 (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
    464                 gval(n) = KFREE;  /* remove value ... */
    465                 removeentry(n);  /* remove entry from table */
    466             }
    467         }
    468         l = h->gclist;
    469     }
    470 }
    471 
    472 static void freeobj (klisp_State *K, GCObject *o) {
    473     /* TODO use specific functions like in bigint, bigrat & table */
    474     uint8_t type = o->gch.tt;
    475     switch (type) {
    476     case K_TBIGINT: {
    477         mp_int_free(K, (Bigint *)o);
    478         break;
    479     }
    480     case K_TBIGRAT: {
    481         mp_rat_free(K, (Bigrat *)o);
    482         break;
    483     }
    484     case K_TPAIR:
    485         klispM_free(K, (Pair *)o);
    486         break;
    487     case K_TSYMBOL:
    488         /* symbols are in the string/symbol table */
    489         /* The string will be freed before/after */
    490         /* symbols with no source info are in the string/symbol table */
    491         if (ttisnil(ktry_get_si(K, gc2sym(o))))
    492             G(K)->strt.nuse--;
    493         klispM_free(K, (Symbol *)o);
    494         break;
    495     case K_TKEYWORD:
    496         /* keywords are in the string table */
    497         /* The string will be freed before/after */
    498         G(K)->strt.nuse--;
    499         klispM_free(K, (Keyword *)o);
    500         break;
    501     case K_TSTRING:
    502         /* immutable strings are in the string/symbol table */
    503         if (kstring_immutablep(gc2str(o)))
    504             G(K)->strt.nuse--;
    505         klispM_freemem(K, o, sizeof(String)+o->str.size+1);
    506         break;
    507     case K_TENVIRONMENT:
    508         klispM_free(K, (Environment *)o);
    509         break;
    510     case K_TCONTINUATION:
    511         klispM_freemem(K, o, sizeof(Continuation) + 
    512                        o->cont.extra_size * sizeof(TValue));
    513         break;
    514     case K_TOPERATIVE:
    515         klispM_freemem(K, o, sizeof(Operative) + 
    516                        o->op.extra_size * sizeof(TValue));
    517         break;
    518     case K_TAPPLICATIVE:
    519         klispM_free(K, (Applicative *)o);
    520         break;
    521     case K_TENCAPSULATION:
    522         klispM_free(K, (Encapsulation *)o);
    523         break;
    524     case K_TPROMISE:
    525         klispM_free(K, (Promise *)o);
    526         break;
    527     case K_TTABLE:
    528         klispH_free(K, (Table *)o);
    529         break;
    530     case K_TERROR:
    531         klispE_free(K, (Error *)o);
    532         break;
    533     case K_TBYTEVECTOR:
    534         /* immutable bytevectors are in the string/symbol table */
    535         if (kbytevector_immutablep(gc2str(o)))
    536             G(K)->strt.nuse--;
    537         klispM_freemem(K, o, sizeof(Bytevector)+o->bytevector.size);
    538         break;
    539     case K_TFPORT:
    540         /* first close the port to free the FILE structure.
    541            This works even if the port was already closed,
    542            it is important that this don't throw errors, because
    543            the mechanism used in error handling would crash at this
    544            point */
    545         kclose_port(K, gc2fport(o));
    546         klispM_free(K, (FPort *)o);
    547         break;
    548     case K_TMPORT:
    549         /* memory ports (string & bytevector) don't need to be closed
    550            explicitly */
    551         klispM_free(K, (MPort *)o);
    552         break;
    553     case K_TVECTOR:
    554         klispM_freemem(K, o, sizeof(Vector) + sizeof(TValue) * o->vector.sizearray);
    555         break;
    556     case K_TLIBRARY:
    557         klispM_free(K, (Library *)o);
    558         break;
    559     case K_TTHREAD: {
    560         klisp_State *K2 = (klisp_State *) o;
    561 
    562         klisp_assert(K2 != G(K)->mainthread);
    563         klisp_assert(K2 != K);
    564         /* threads are always created detached, so there's no 
    565            need to do a join here */
    566         klispT_freethread(K, K2);
    567         break;
    568     }
    569     case K_TMUTEX:
    570         klispX_free(K, (Mutex *) o);
    571         break;
    572     case K_TCONDVAR:
    573         klispV_free(K, (Condvar *) o);
    574         break;
    575     default:
    576         /* shouldn't happen */
    577         fprintf(stderr, "Unknown GCObject type (in GC free): %d\n", 
    578                 type);
    579         abort();
    580     }
    581 }
    582 
    583 
    584 /* klisp can't have more than 4gb */
    585 #define sweepwholelist(K,p)	sweeplist(K,p,UINT32_MAX)
    586 
    587 
    588 static GCObject **sweeplist (klisp_State *K, GCObject **p, uint32_t count) 
    589 {
    590     GCObject *curr;
    591     global_State *g = G(K);
    592     int deadmask = otherwhite(g);
    593     while ((curr = *p) != NULL && count-- > 0) {
    594         if ((curr->gch.gct ^ WHITEBITS) & deadmask) {  /* not dead? */
    595             klisp_assert(!isdead(g, curr) || testbit(curr->gch.gct, FIXEDBIT));
    596             makewhite(g, curr);  /* make it white (for next cycle) */
    597             p = &curr->gch.next;
    598         } else {  /* must erase `curr' */
    599             klisp_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
    600             *p = curr->gch.next;
    601             if (curr == g->rootgc)  /* is the first element of the list? */
    602                 g->rootgc = curr->gch.next;  /* adjust first */
    603             freeobj(K, curr);
    604         }
    605     }
    606     return p;
    607 }
    608 
    609 static void checkSizes (klisp_State *K) {
    610     global_State *g = G(K);
    611     /* check size of string/symbol hash */
    612     if (g->strt.nuse < cast(uint32_t , g->strt.size/4) &&
    613 	    g->strt.size > MINSTRTABSIZE*2)
    614         klispS_resize(K, g->strt.size/2);  /* table is too big */
    615 #if 0 /* not used in klisp */
    616     /* check size of buffer */
    617     if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
    618         size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
    619         luaZ_resizebuffer(L, &g->buff, newsize);
    620     }
    621 #endif
    622 }
    623 
    624 #if 0 /* klisp: keep this around */
    625 static void GCTM (lua_State *L) {
    626     global_State *g = G(L);
    627     GCObject *o = g->tmudata->gch.next;  /* get first element */
    628     Udata *udata = rawgco2u(o);
    629     const TValue *tm;
    630     /* remove udata from `tmudata' */
    631     if (o == g->tmudata)  /* last element? */
    632         g->tmudata = NULL;
    633     else
    634         g->tmudata->gch.next = udata->uv.next;
    635     udata->uv.next = g->mainthread->next;  /* return it to `root' list */
    636     g->mainthread->next = o;
    637     makewhite(g, o);
    638     tm = fasttm(L, udata->uv.metatable, TM_GC);
    639     if (tm != NULL) {
    640         lu_byte oldah = L->allowhook;
    641         lu_mem oldt = g->GCthreshold;
    642         L->allowhook = 0;  /* stop debug hooks during GC tag method */
    643         g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */
    644         setobj2s(L, L->top, tm);
    645         setuvalue(L, L->top+1, udata);
    646         L->top += 2;
    647         luaD_call(L, L->top - 2, 0);
    648         L->allowhook = oldah;  /* restore hooks */
    649         g->GCthreshold = oldt;  /* restore threshold */
    650     }
    651 }
    652 
    653 
    654 /*
    655 ** Call all GC tag methods
    656 */
    657 void klispC_callGCTM (lua_State *L) {
    658     while (G(L)->tmudata)
    659         GCTM(L);
    660 }
    661 #endif
    662 
    663 /* This still leaves allocated objs in K, namely the 
    664    arrays that aren't TValues */
    665 void klispC_freeall (klisp_State *K) {
    666     global_State *g = G(K);
    667     /* mask to collect all elements */
    668     g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
    669     sweepwholelist(K, &g->rootgc);
    670     /* free all keyword/symbol/string/bytevectors lists */
    671     for (int32_t i = 0; i < g->strt.size; i++)  
    672         sweepwholelist(K, &g->strt.hash[i]);
    673 }
    674 
    675 /* mark root set */
    676 static void markroot (klisp_State *K) {
    677     global_State *g = G(K);
    678     g->gray = NULL;
    679     g->grayagain = NULL; 
    680     g->weak = NULL; 
    681 
    682     markobject(g, g->mainthread); /* this is also in the thread table */
    683 
    684     markvalue(g, g->name_table);
    685     markvalue(g, g->cont_name_table);
    686     markvalue(g, g->thread_table);
    687 
    688     markvalue(g, g->eval_op);
    689     markvalue(g, g->list_app);
    690     markvalue(g, g->memoize_app);
    691     markvalue(g, g->ground_env);
    692     markvalue(g, g->module_params_sym);
    693     markvalue(g, g->root_cont);
    694     markvalue(g, g->error_cont);
    695     markvalue(g, g->system_error_cont);
    696 
    697     markvalue(g, g->kd_in_port_key);
    698     markvalue(g, g->kd_out_port_key);
    699     markvalue(g, g->kd_error_port_key);
    700     markvalue(g, g->kd_strict_arith_key);
    701     markvalue(g, g->empty_string);
    702     markvalue(g, g->empty_bytevector);
    703     markvalue(g, g->empty_vector);
    704 
    705     markvalue(g, g->ktok_lparen);
    706     markvalue(g, g->ktok_rparen);
    707     markvalue(g, g->ktok_dot);
    708     markvalue(g, g->ktok_sexp_comment);
    709 
    710     markvalue(g, g->require_path);
    711     markvalue(g, g->require_table);
    712 
    713     markvalue(g, g->libraries_registry);    
    714 
    715     g->gcstate = GCSpropagate;
    716 }
    717 
    718 static void atomic (klisp_State *K) {
    719     global_State *g = G(K);
    720     size_t udsize;  /* total size of userdata to be finalized */
    721     /* traverse objects caught by write barrier */
    722     propagateall(g);
    723 
    724     /* remark weak tables */
    725     g->gray = g->weak; 
    726     g->weak = NULL;
    727     propagateall(g);
    728 
    729     /* remark gray again */
    730     g->gray = g->grayagain;
    731     g->grayagain = NULL;
    732     propagateall(g);
    733 
    734     udsize = 0; /* to init var 'till we add user data */
    735 #if 0 /* keep around */
    736     udsize = klispC_separateudata(L, 0);  /* separate userdata to be finalized */
    737     marktmu(g);  /* mark `preserved' userdata */
    738     udsize += propagateall(g);  /* remark, to propagate `preserveness' */
    739 #endif
    740     cleartable(g->weak);  /* remove collected objects from weak tables */
    741 
    742     /* flip current white */
    743     g->currentwhite = cast(uint16_t, otherwhite(g));
    744     g->sweepstrgc = 0;
    745     g->sweepgc = &g->rootgc;
    746     g->gcstate = GCSsweepstring;
    747     g->estimate = g->totalbytes - udsize;  /* first estimate */
    748 }
    749 
    750 
    751 static int32_t singlestep (klisp_State *K) {
    752     global_State *g = G(K);
    753     switch (g->gcstate) {
    754     case GCSpause: {
    755         markroot(K);  /* start a new collection */
    756         return 0;
    757     }
    758     case GCSpropagate: {
    759         if (g->gray)
    760             return propagatemark(g);
    761         else {  /* no more `gray' objects */
    762             atomic(K);  /* finish mark phase */
    763             return 0;
    764         }
    765     }
    766     case GCSsweepstring: {
    767         uint32_t old = g->totalbytes;
    768         sweepwholelist(K, &g->strt.hash[g->sweepstrgc++]);
    769         if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
    770             g->gcstate = GCSsweep;  /* end sweep-string phase */
    771         klisp_assert(old >= g->totalbytes);
    772         g->estimate -= old - g->totalbytes;
    773         return GCSWEEPCOST;
    774     }
    775     case GCSsweep: {
    776         uint32_t old = g->totalbytes;
    777         g->sweepgc = sweeplist(K, g->sweepgc, GCSWEEPMAX);
    778         if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
    779             checkSizes(K);
    780             g->gcstate = GCSfinalize;  /* end sweep phase */
    781         }
    782         klisp_assert(old >= g->totalbytes);
    783         g->estimate -= old - g->totalbytes;
    784         return GCSWEEPMAX*GCSWEEPCOST;
    785     }
    786     case GCSfinalize: {
    787 #if 0 /* keep around */
    788         if (g->tmudata) {
    789             GCTM(L);
    790             if (g->estimate > GCFINALIZECOST)
    791                 g->estimate -= GCFINALIZECOST;
    792             return GCFINALIZECOST;
    793         }
    794         else {
    795 #endif
    796             g->gcstate = GCSpause;  /* end collection */
    797             g->gcdept = 0;
    798             return 0;
    799 #if 0
    800         }
    801 #endif
    802     }
    803     default: klisp_assert(0); return 0;
    804     }
    805 }
    806 
    807 
    808 void klispC_step (klisp_State *K) {
    809     global_State *g = G(K);
    810     int32_t lim = (GCSTEPSIZE/100) * g->gcstepmul;
    811 
    812     if (lim == 0)
    813         lim = (UINT32_MAX-1)/2;  /* no limit */
    814 
    815     g->gcdept += g->totalbytes - g->GCthreshold;
    816 
    817     do {
    818         lim -= singlestep(K);
    819         if (g->gcstate == GCSpause)
    820             break;
    821     } while (lim > 0);
    822 
    823     if (g->gcstate != GCSpause) {
    824         if (g->gcdept < GCSTEPSIZE) {
    825             g->GCthreshold = g->totalbytes + GCSTEPSIZE; 
    826             /* - lim/g->gcstepmul;*/        
    827         } else {
    828             g->gcdept -= GCSTEPSIZE;
    829             g->GCthreshold = g->totalbytes;
    830         }
    831     } else {
    832         klisp_assert(g->totalbytes >= g->estimate);
    833         setthreshold(g);
    834     }
    835 }
    836 
    837 void klispC_fullgc (klisp_State *K) {
    838     global_State *g = G(K);
    839     if (g->gcstate <= GCSpropagate) {
    840         /* reset sweep marks to sweep all elements (returning them to white) */
    841         g->sweepstrgc = 0;
    842         g->sweepgc = &g->rootgc;
    843         /* reset other collector lists */
    844         g->gray = NULL;
    845         g->grayagain = NULL;
    846         g->weak = NULL;
    847         g->gcstate = GCSsweepstring;
    848     }
    849     klisp_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
    850     /* finish any pending sweep phase */
    851     while (g->gcstate != GCSfinalize) {
    852         klisp_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
    853         singlestep(K);
    854     }
    855     markroot(K);
    856     while (g->gcstate != GCSpause) {
    857         singlestep(K);
    858     }
    859     setthreshold(g);
    860 }
    861 
    862 /* TODO: make all code using mutation to call these,
    863    this is actually the only thing that is missing for an incremental 
    864    garbage collector!
    865    IMPORTANT: a call to maybe a different but similar function should be
    866    made before assigning to a GC guarded variable, or pushed in a GC
    867    guarded stack! */
    868 void klispC_barrierf (klisp_State *K, GCObject *o, GCObject *v) {
    869     global_State *g = G(K);
    870     klisp_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
    871     klisp_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
    872     klisp_assert(o->gch.tt != K_TTABLE);
    873     /* must keep invariant? */
    874     if (g->gcstate == GCSpropagate)
    875         reallymarkobject(g, v);  /* restore invariant */
    876     else  /* don't mind */
    877         makewhite(g, o);  /* mark as white just to avoid other barriers */
    878 }
    879 
    880 void klispC_barrierback (klisp_State *K, Table *t) {
    881     global_State *g = G(K);
    882     GCObject *o = obj2gco(t);
    883     klisp_assert(isblack(o) && !isdead(g, o));
    884     klisp_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
    885     black2gray(o);  /* make table gray (again) */
    886     t->gclist = g->grayagain;
    887     g->grayagain = o;
    888 }
    889 
    890 /* NOTE: kflags is added for klisp */
    891 /* NOTE: symbols, keywords, immutable strings and immutable bytevectors do 
    892    this "by hand", they don't call this */
    893 void klispC_link (klisp_State *K, GCObject *o, uint8_t tt, uint8_t kflags) {
    894     global_State *g = G(K);
    895     o->gch.next = g->rootgc;
    896     g->rootgc = o;
    897     o->gch.gct = klispC_white(g);
    898     o->gch.tt = tt;
    899     o->gch.kflags = kflags;
    900     o->gch.si = NULL;
    901     /* NOTE that o->gch.gclist doesn't need to be setted */
    902 }
    903