void gc_keep_cells(PTuple *closure) { PObject **objs = PSEQUENCE_OBJECTS(closure); uint32_t nobjs = PSEQUENCE_ELEMENTS(closure); GC_MARK(closure);//mark: closure must not be gc'ed as a normal tuple, no "objects" inside while (nobjs--) { PObject *obj = objs[nobjs]; if (obj) { debug("keeping cell %x => %x\n", obj, PCELL_ARG(obj)); obj = PCELL_ARG(obj); GC_KEEP(obj);//PCELL_ARG(obj) is a freevar tuple, keep it } } }
bool bch_bucket_add_unused(struct cache *ca, struct bucket *b) { BUG_ON(GC_MARK(b) || GC_SECTORS_USED(b)); if (CACHE_REPLACEMENT(&ca->sb) == CACHE_REPLACEMENT_FIFO) { unsigned i; for (i = 0; i < RESERVE_NONE; i++) if (!fifo_full(&ca->free[i])) goto add; return false; } add: b->prio = 0; if (can_inc_bucket_gen(b) && fifo_push(&ca->unused, b - ca->buckets)) { atomic_inc(&b->pin); return true; } return false; }
static bool can_invalidate_bucket(struct cache *ca, struct bucket *b) { return GC_MARK(b) == GC_MARK_RECLAIMABLE && !atomic_read(&b->pin) && can_inc_bucket_gen(b); }
/** * Marks a LuciLibFuncObj as reachable * * @param in LuciLibFuncObj */ void LuciLibFunc_mark(LuciObject *in) { GC_MARK(in); }
/** * Marks a LuciFileObj as reachable * * @param in LuciFileObj */ void LuciFile_mark(LuciObject *in) { GC_MARK(in); }
//TODO: remove the stack and make a list of used/marked via header!! phead vs ptail void gc_mark() { int i; PObject *obj; debug( "\n\n>>>>>>>MARK started %x\n", _phead); gc_trace(); gc_keep_root(); while (_phead) { obj = _phead; _phead = GCH_NEXT(obj); int tt = PTYPE(obj); switch (tt) { case PBYTEARRAY: case PSHORTARRAY: if (_PMS(obj)->seq) GC_MARK( _PMS(obj)->seq); break; case PLIST: case PTUPLE: { i = PSEQUENCE_ELEMENTS(obj); PObject **objs = PSEQUENCE_OBJECTS(obj); if (objs) { GC_KEEP_MANY(objs, i); if (PSEQUENCE_BUFFER(obj)) { GC_MARK(PSEQUENCE_BUFFER(obj)); } } } break; case PFSET: case PSET: case PDICT: { PDict *tmp = (PDict *)obj; int e = 0; HashEntry *ee; while ( (ee = phash_getentry(tmp, e++)) != NULL ) { GC_KEEP_NOTNULL(ee->key); if (tt == PDICT) GC_KEEP_NOTNULL(ee->value); } if (tmp->entry) GC_MARK(tmp->entry); } break; case PFUNCTION: { PFunction *tmp = (PFunction *)obj; if (tmp->defargs) GC_KEEP_MANY(tmp->storage, tmp->defargs); //TODO: the following can be optimized by avoiding the check on names... //and use macros to access function fields for portability... if (tmp->defkwargs) GC_KEEP_MANY(tmp->storage + tmp->defargs, 2 * tmp->defkwargs); if (PCODE_CELLVARS(PCODE_MAKE(tmp->codeobj))) { obj = (PObject *)PFUNCTION_GET_CLOSURE(tmp); GC_KEEP(obj); //if (obj) // gc_keep_cells((PTuple *)obj); } } break; case PMETHOD: { PMethod *tmp = (PMethod *)obj; GC_KEEP(tmp->self); GC_KEEP(tmp->fn); } break; case PCLASS: { PClass *tmp = (PClass *)obj; GC_KEEP(tmp->bases); GC_KEEP(tmp->dict); } break; case PINSTANCE: { PInstance *tmp = (PInstance *)obj; GC_KEEP(tmp->base); GC_KEEP(tmp->dict); } break; case PITERATOR: GC_KEEP( ((PIterator *)obj)->iterable ); break; case PFRAME: { //debug("checking frame %i\n", obj); PFrame *tmp = (PFrame *)obj; PCode *code = PCODE_MAKE(tmp->code); GC_KEEP(tmp->parent); //GC_KEEP(tmp->block); GC_KEEP_MANY(PFRAME_PSTACK(tmp), tmp->sp); GC_KEEP_MANY(PFRAME_PLOCALS(tmp, code), code->nlocals); if (PCODE_HASVARS(code)) GC_KEEP_MANY(PFRAME_VARS(tmp, code), 2); /*if (PCODE_FREEVARS(code)) { obj = PFRAME_TFREEVARS(tmp,code);//(PObject *)PFRAME_FREEVARS(tmp); debug("keeping freevars %x for %x\n", obj, tmp); GC_KEEP(obj); } debug("FRAME %x %i %i\n", tmp, PCODE_CELLVARS(code), PCODE_FREEVARS(code)); if (PCODE_CELLVARS(code)) { obj = (PObject *)PFRAME_CELLVARS(tmp); debug("keeping cells for %x\n", obj); GC_KEEP(obj); //if (obj) // gc_keep_cells((PTuple *)obj); } */ } break; /*case PBLOCK: //debug("checking block %i\n", obj); GC_KEEP(((PBlock *)obj)->next); break; */ case PSYSOBJ: { PSysObject *tmp = (PSysObject *) obj; SYSLOCK(); if (tmp->type == PSYS_TIMER) { GC_KEEP(tmp->sys.timer.fn.fn); GC_KEEP(tmp->sys.timer.fn.args); } SYSUNLOCK(); } break; default: break; } //no need to mark obj. It has already been marked in gc_keep //GC_MARK(obj); } gc_trace(); _phead = NULL; obj = PNT(_vm.thlist); do { PThread *pth = (PThread *)obj; debug( "Scanning thread %x %i for consts %x %i\n", pth, pth->header.flags, pth->cocache, pth->cachesize); for (i = 0; i < pth->cachesize; i++) { PObject *co = pth->cocache[i].obj; if (co && GCH_FLAG(co) != GC_USED) continue; //not marked, not staged, not null, not const_marked: remove it pth->cocache[i].obj = NULL; } obj = PNT(pth->next); } while (obj != PNT(_vm.thlist)); debug( ">>>>>>>MARK stopped\n\n\n"); }
void gc_keep_root(void) { PObject *obj; int i; if (_vmpnt) { //get the root set obj = PNT(_vm.thlist); do { PThread *pth = (PThread *)obj; VThread vth = pth->th; debug( "Scanning thread %x %i\n", pth, pth->header.flags); if (vth && vosThGetStatus(vth) == VTHREAD_INACTIVE) { //terminated, remove from list...it will die if no references remain pth->prev->next = pth->next; pth->next->prev = pth->prev; GCH_FLAG_SET(pth, GC_USED); //free workspace //if PThread has references, it's ok. But it can't be restarted _gc_free(vth); pth->th = NULL; } else { GC_MARK(pth); if (pth->frame) GC_KEEP(pth->frame); } obj = PNT(pth->next); } while (obj != PNT(_vm.thlist)); for (i = 0; i < _vm.nmodules; i++) { PModule *mod = VM_MODULE(i); GC_MARK(mod); if (PMODULE_IS_LOADED(mod)) { GC_KEEP_MANY(mod->globals, mod->nfo.nums.nglobals); } else { GC_KEEP(mod->nfo.frame); } } //-----> irqs could be modifing irq struct here: no worries SYSLOCK(); //slots & irqstack for (i = 0; i < _vm.irqn; i++) { GC_KEEP(_vm.irqstack[i].fn); GC_KEEP_NOTNULL(_vm.irqstack[i].args); } for (i = 0; i < EXT_SLOTS; i++) { if (_vm.irqslots[0][i].fn) { GC_KEEP(_vm.irqslots[0][i].fn); GC_KEEP_NOTNULL(_vm.irqslots[0][i].args); } if (_vm.irqslots[1][i].fn) { GC_KEEP(_vm.irqslots[1][i].fn); GC_KEEP_NOTNULL(_vm.irqslots[1][i].args); } } if (_vm.irqcur) { GC_KEEP(_vm.irqcur->fn); GC_KEEP_NOTNULL(_vm.irqcur->args); } if (_vm.timers) { obj = _vm.timers; do { GC_KEEP(obj); obj = (PObject *)((PSysObject *)obj)->sys.timer.next; } while (obj != _vm.timers); } SYSUNLOCK(); //-----> irq could be modifing irq struct here: // - it can add something to irqslots: np, the objects added must be in an active frame (gc lock is on, no new frame can be created) // - it can add something to irqstack from pin irq: np, the objects are sitting in irqslots // - it can add something to irqstack from timers: that timer was in the timer list, so it is already kept // - it can be the irqthread at 2 different times: // - it modifies _vm.irqcur after putting it in a new frame: if happens up there, np. if happens now, already kept // - it does _vm.irqn--: if happens up there, the removed irqfn is in irqcur. if happens here, already kept } }