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 } } }
void *potion_mark_major(Potion *P, const struct PNObject *ptr) { struct PNMemory *M = P->mem; PN_SIZE i; PN_SIZE sz = 16; switch (((struct PNFwd *)ptr)->fwd) { case POTION_COPIED: case POTION_FWD: GC_MAJOR_UPDATE(((struct PNFwd *)ptr)->ptr); goto done; } if (ptr->vt > PN_TUSER) { GC_MAJOR_UPDATE(PN_VTABLE(ptr->vt)); int ivars = ((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen; for (i = 0; i < ivars; i++) GC_MAJOR_UPDATE(((struct PNObject *)ptr)->ivars[i]); goto done; } switch (ptr->vt) { case PN_TWEAK: GC_MAJOR_UPDATE(((struct PNWeakRef *)ptr)->data); break; case PN_TCLOSURE: GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->sig); for (i = 0; i < ((struct PNClosure *)ptr)->extra; i++) GC_MAJOR_UPDATE(((struct PNClosure *)ptr)->data[i]); break; case PN_TTUPLE: { struct PNTuple * volatile t = (struct PNTuple *)potion_fwd((PN)ptr); for (i = 0; i < t->len; i++) GC_MAJOR_UPDATE(t->set[i]); } break; case PN_TSTATE: GC_MAJOR_UPDATE(((Potion *)ptr)->strings); GC_MAJOR_UPDATE(((Potion *)ptr)->lobby); GC_MAJOR_UPDATE(((Potion *)ptr)->vts); GC_MAJOR_UPDATE(((Potion *)ptr)->source); GC_MAJOR_UPDATE(((Potion *)ptr)->input); GC_MAJOR_UPDATE(((Potion *)ptr)->pbuf); GC_MAJOR_UPDATE(((Potion *)ptr)->unclosed); GC_MAJOR_UPDATE(((Potion *)ptr)->call); GC_MAJOR_UPDATE(((Potion *)ptr)->callset); break; case PN_TFILE: GC_MAJOR_UPDATE(((struct PNFile *)ptr)->path); break; case PN_TVTABLE: GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->parent); GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ivars); GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->methods); GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->ctor); GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->call); GC_MAJOR_UPDATE(((struct PNVtable *)ptr)->callset); break; case PN_TSOURCE: GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[0]); GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[1]); GC_MAJOR_UPDATE(((struct PNSource *)ptr)->a[2]); break; case PN_TPROTO: GC_MAJOR_UPDATE(((struct PNProto *)ptr)->source); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->sig); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->stack); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->paths); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->locals); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->upvals); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->values); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->protos); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->tree); GC_MAJOR_UPDATE(((struct PNProto *)ptr)->asmb); break; case PN_TTABLE: GC_MAJOR_UPDATE_TABLE(PN, (struct PNTable *)potion_fwd((PN)ptr), 1); break; case PN_TFLEX: for (i = 0; i < PN_FLEX_SIZE(ptr); i++) GC_MAJOR_UPDATE(PN_FLEX_AT(ptr, i)); break; case PN_TCONT: GC_KEEP(ptr); pngc_mark_array(P, (_PN *)((struct PNCont *)ptr)->stack + 3, ((struct PNCont *)ptr)->len - 3, 2); break; } done: sz = potion_type_size(P, ptr); return (void *)((char *)ptr + sz); }
//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 } }