FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_root))::FreeAligned(void *blk) { FLEXT_ASSERT(blk); char *ori = *(char **)((char *)blk-sizeof(size_t)-sizeof(char *)); size_t bytes = *(size_t *)((char *)blk-sizeof(size_t)); if(UNLIKELY(bytes >= LARGEALLOC)) { #if FLEXT_SYS == FLEXT_SYS_MAX && defined(_SYSMEM_H_) sysmem_freeptr(ori); #else // use C library function for large memory blocks free(ori); #endif } else { //! We need system locking here for secondary threads! SYSLOCK(); #if defined(FLEXT_USE_CMEM) free(ori); #else freebytes(ori,bytes); #endif SYSUNLOCK(); } }
FLEXT_TEMPIMPL(void *FLEXT_CLASSDEF(flext_root))::NewAligned(size_t bytes,int bitalign) { const size_t ovh = sizeof(size_t)+sizeof(char *); const size_t alignovh = bitalign/8-1; bytes += ovh+alignovh; char *blk; if(UNLIKELY(bytes >= LARGEALLOC)) { #if FLEXT_SYS == FLEXT_SYS_MAX && defined(_SYSMEM_H_) blk = (char *)sysmem_newptr(bytes); #else // use C library function for large memory blocks blk = (char *)malloc(bytes); #endif } else { //! We need system locking here for secondary threads! SYSLOCK(); #if defined(FLEXT_USE_CMEM) blk = (char *)malloc(bytes); #else blk = (char *)getbytes(bytes); #endif SYSUNLOCK(); } FLEXT_ASSERT(blk); char *ablk = reinterpret_cast<char *>((reinterpret_cast<size_t>(blk)+ovh+alignovh) & ~alignovh); *(char **)(ablk-sizeof(size_t)-sizeof(char *)) = blk; *(size_t *)(ablk-sizeof(size_t)) = bytes; return ablk; }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_root))::operator delete(void *blk) { if(!blk) return; FLEXT_ASSERT(MemCheck(blk)); #ifdef FLEXT_DEBUGMEM char *ori = (char *)blk-sizeof(size_t)-sizeof(memtest); #else char *ori = (char *)blk-sizeof(size_t); #endif size_t bytes = *(size_t *)ori; if(UNLIKELY(bytes >= LARGEALLOC)) { #if FLEXT_SYS == FLEXT_SYS_MAX && defined(_SYSMEM_H_) sysmem_freeptr(ori); #else // use C library function for large memory blocks free(ori); #endif } else { //! We need system locking here for secondary threads! SYSLOCK(); freebytes(ori,bytes); SYSUNLOCK(); } }
FLEXT_TEMPIMPL(void *FLEXT_CLASSDEF(flext_root))::operator new(size_t bytes) { bytes += sizeof(size_t); #ifdef FLEXT_DEBUGMEM bytes += sizeof(memtest)*2; #endif char *blk; if(UNLIKELY(bytes >= LARGEALLOC)) { #if FLEXT_SYS == FLEXT_SYS_MAX && defined(_SYSMEM_H_) blk = (char *)sysmem_newptr(bytes); #else // use C library function for large memory blocks blk = (char *)malloc(bytes); #endif } else { //! We need system locking here for secondary threads! SYSLOCK(); blk = (char *)getbytes(bytes); SYSUNLOCK(); } FLEXT_ASSERT(blk); *(size_t *)blk = bytes; #ifdef FLEXT_DEBUGMEM *(size_t *)(blk+sizeof(size_t)) = memtest; *(size_t *)(blk+bytes-sizeof(memtest)) = memtest; return blk+sizeof(size_t)+sizeof(memtest); #else return blk+sizeof(size_t); #endif }
//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 } }