PmReturn_t seqiter_new(pPmObj_t pobj, pPmObj_t *r_pobj) { PmReturn_t retval; uint8_t *pchunk; pPmSeqIter_t psi; C_ASSERT(pobj != C_NULL); C_ASSERT(*r_pobj != C_NULL); /* Raise a TypeError if pobj is not a sequence */ if ((OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR) && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_TUP) && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_LST)) { PM_RAISE(retval, PM_RET_EX_TYPE); return retval; } /* Alloc a chunk for the sequence iterator obj */ retval = heap_getChunk(sizeof(PmSeqIter_t), &pchunk); PM_RETURN_IF_ERROR(retval); /* Set the sequence iterator's fields */ psi = (pPmSeqIter_t)pchunk; OBJ_SET_TYPE(psi, OBJ_TYPE_SQI); psi->si_sequence = pobj; psi->si_index = 0; *r_pobj = (pPmObj_t)psi; return retval; }
/* Returns an instance of the class by reference */ PmReturn_t class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj) { PmReturn_t retval = PM_RET_OK; uint8_t *pchunk; pPmObj_t pobj; pPmObj_t pattrs; uint8_t objid; /* Allocate a class instance */ retval = heap_getChunk(sizeof(PmInstance_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_CLI); /* Set the instance's fields */ ((pPmInstance_t)pobj)->cli_class = (pPmClass_t)pclass; ((pPmInstance_t)pobj)->cli_attrs = C_NULL; /* Create the attributes dict */ heap_gcPushTempRoot(pobj, &objid); retval = dict_new(&pattrs); heap_gcPopTempRoot(objid); ((pPmInstance_t)pobj)->cli_attrs = (pPmDict_t)pattrs; /* TODO: Store pclass in __class__ attr */ *r_pobj = pobj; return retval; }
PmReturn_t thread_new(pPmObj_t pframe, pPmObj_t *r_pobj) { PmReturn_t retval = PM_RET_OK; pPmThread_t pthread = C_NULL; C_ASSERT(pframe != C_NULL); /* If it's not a frame, raise TypeError */ if (OBJ_GET_TYPE(pframe) != OBJ_TYPE_FRM) { PM_RAISE(retval, PM_RET_EX_TYPE); return retval; } /* Allocate a thread */ retval = heap_getChunk(sizeof(PmThread_t), (uint8_t **)r_pobj); PM_RETURN_IF_ERROR(retval); /* Set type, frame and initialize status */ pthread = (pPmThread_t)*r_pobj; OBJ_SET_TYPE(pthread, OBJ_TYPE_THR); pthread->pframe = (pPmFrame_t)pframe; pthread->interpctrl = INTERP_CTRL_CONT; return retval; }
PmReturn_t mod_new(pPmObj_t pco, pPmObj_t *pmod) { PmReturn_t retval; uint8_t *pchunk; pPmObj_t pobj; /* If it's not a code obj, raise TypeError */ if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB) { PM_RAISE(retval, PM_RET_EX_TYPE); return retval; } /* Alloc and init func obj */ retval = heap_getChunk(sizeof(PmFunc_t), &pchunk); PM_RETURN_IF_ERROR(retval); *pmod = (pPmObj_t)pchunk; OBJ_SET_TYPE(*pmod, OBJ_TYPE_MOD); ((pPmFunc_t)*pmod)->f_co = (pPmCo_t)pco; /* Alloc and init attrs dict */ retval = dict_new(&pobj); ((pPmFunc_t)*pmod)->f_attrs = (pPmDict_t)pobj; /* A module's globals is the same as its attrs */ ((pPmFunc_t)*pmod)->f_globals = (pPmDict_t)pobj; return retval; }
PmReturn_t class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth) { PmReturn_t retval = PM_RET_OK; uint8_t *pchunk; pPmMethod_t pmeth; pPmObj_t pattrs; uint8_t objid; /* Allocate a method */ retval = heap_getChunk(sizeof(PmMethod_t), &pchunk); PM_RETURN_IF_ERROR(retval); OBJ_SET_TYPE(pchunk, OBJ_TYPE_MTH); /* Set method fields */ pmeth = (pPmMethod_t)pchunk; pmeth->m_instance = (pPmInstance_t)pinstance; pmeth->m_func = (pPmFunc_t)pfunc; pmeth->m_attrs = C_NULL; /* Create the attributes dict */ heap_gcPushTempRoot((pPmObj_t)pmeth, &objid); retval = dict_new(&pattrs); heap_gcPopTempRoot(objid); pmeth->m_attrs = (pPmDict_t)pattrs; *r_pmeth = (pPmObj_t)pmeth; return retval; }
PmReturn_t class_new(pPmObj_t pattrs, pPmObj_t pbases, pPmObj_t pname, pPmObj_t *r_pclass) { PmReturn_t retval = PM_RET_OK; uint8_t *pchunk; pPmObj_t pobj; /* Ensure types */ if ((OBJ_GET_TYPE(pattrs) != OBJ_TYPE_DIC) || (OBJ_GET_TYPE(pbases) != OBJ_TYPE_TUP) || (OBJ_GET_TYPE(pname) != OBJ_TYPE_STR)) { PM_RAISE(retval, PM_RET_EX_TYPE); return retval; } /* Allocate a class obj */ retval = heap_getChunk(sizeof(PmClass_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_CLO); /* Class has no access to its CO */ ((pPmClass_t)pobj)->cl_attrs = (pPmDict_t)pattrs; ((pPmClass_t)pobj)->cl_bases = (pPmTuple_t)pbases; *r_pclass = pobj; return retval; }
PmReturn_t obj_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pobj) { PmReturn_t retval = PM_RET_OK; PmObj_t obj; /* Get the object descriptor */ obj.od = (PmObjDesc_t)0x0000; OBJ_SET_TYPE(&obj, mem_getByte(memspace, paddr)); switch (OBJ_GET_TYPE(&obj)) { case OBJ_TYPE_NON: /* If it's the None object, return global None */ *r_pobj = PM_NONE; break; case OBJ_TYPE_INT: /* Read an integer and create an integer object with the value */ retval = int_new(mem_getInt(memspace, paddr), r_pobj); break; #ifdef HAVE_FLOAT case OBJ_TYPE_FLT: /* Read a float and create an float object with the value */ retval = float_new(mem_getFloat(memspace, paddr), r_pobj); break; #endif /* HAVE_FLOAT */ case OBJ_TYPE_STR: retval = string_loadFromImg(memspace, paddr, r_pobj); break; case OBJ_TYPE_TUP: retval = tuple_loadFromImg(memspace, paddr, r_pobj); break; case OBJ_TYPE_NIM: /* If it's a native code img, load into a code obj */ retval = no_loadFromImg(memspace, paddr, r_pobj); break; case OBJ_TYPE_CIM: /* If it's a code img, load into a code obj */ retval = co_loadFromImg(memspace, paddr, r_pobj); break; default: /* All other types should not be in an img obj */ PM_RAISE(retval, PM_RET_EX_SYS); break; } return retval; }
PmReturn_t float_new(float f, pPmObj_t *r_pf) { PmReturn_t retval = PM_RET_OK; retval = heap_getChunk(sizeof(PmFloat_t), (uint8_t **)r_pf); PM_RETURN_IF_ERROR(retval); OBJ_SET_TYPE(*r_pf, OBJ_TYPE_FLT); ((pPmFloat_t) * r_pf)->val = f; return retval; }
PmReturn_t co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco) { PmReturn_t retval = PM_RET_OK; pPmObj_t pobj; pPmCo_t pco = C_NULL; uint8_t *pchunk; /* Store ptr to top of code img (less type byte) */ uint8_t const *pci = *paddr - 1; /* Get size of code img */ uint16_t size = mem_getWord(memspace, paddr); /* Allocate a code obj */ retval = heap_getChunk(sizeof(PmCo_t), &pchunk); PM_RETURN_IF_ERROR(retval); pco = (pPmCo_t)pchunk; /* Fill in the CO struct */ OBJ_SET_TYPE(pco, OBJ_TYPE_COB); pco->co_memspace = memspace; pco->co_codeimgaddr = pci; /* Load names (tuple obj) */ *paddr = pci + CI_NAMES_FIELD; retval = obj_loadFromImg(memspace, paddr, &pobj); PM_RETURN_IF_ERROR(retval); pco->co_names = (pPmTuple_t)pobj; /* Load consts (tuple obj) assume it follows names */ retval = obj_loadFromImg(memspace, paddr, &pobj); PM_RETURN_IF_ERROR(retval); pco->co_consts = (pPmTuple_t)pobj; /* Start of bcode always follows consts */ pco->co_codeaddr = *paddr; /* Set addr to point one past end of img */ *paddr = pci + size; *r_pco = (pPmObj_t)pco; return PM_RET_OK; }
PmReturn_t dict_new(pPmObj_t *r_pdict) { PmReturn_t retval = PM_RET_OK; pPmDict_t pdict = C_NULL; uint8_t *pchunk; /* Allocate a dict */ retval = heap_getChunk(sizeof(PmDict_t), &pchunk); PM_RETURN_IF_ERROR(retval); /* Init dict fields */ pdict = (pPmDict_t)pchunk; OBJ_SET_TYPE(pdict, OBJ_TYPE_DIC); pdict->length = 0; pdict->d_keys = C_NULL; pdict->d_vals = C_NULL; *r_pdict = (pPmObj_t)pchunk; return retval; }
PmReturn_t no_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pno) { PmReturn_t retval = PM_RET_OK; pPmNo_t pno = C_NULL; uint8_t *pchunk; /* Allocate a code obj */ retval = heap_getChunk(sizeof(PmNo_t), &pchunk); PM_RETURN_IF_ERROR(retval); pno = (pPmNo_t)pchunk; /* Fill in the NO struct */ OBJ_SET_TYPE(pno, OBJ_TYPE_NOB); pno->no_argcount = mem_getByte(memspace, paddr); /* Get index into native fxn table */ pno->no_funcindx = (int16_t)mem_getWord(memspace, paddr); *r_pno = (pPmObj_t)pno; return PM_RET_OK; }
/* Releases chunk to the free list */ PmReturn_t heap_freeChunk(pPmObj_t ptr) { PmReturn_t retval; C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n", ptr, OBJ_GET_SIZE(ptr)); /* Ensure the chunk falls within the heap */ C_ASSERT(((uint8_t *)ptr >= pmHeap.base) && ((uint8_t *)ptr < pmHeap.base + PM_HEAP_SIZE)); /* Insert the chunk into the freelist */ OBJ_SET_FREE(ptr, 1); /* Clear type so that heap descriptor's size's upper byte is zero */ OBJ_SET_TYPE(ptr, 0); retval = heap_linkToFreelist((pPmHeapDesc_t)ptr); PM_RETURN_IF_ERROR(retval); return retval; }
/* * Reclaims any object that does not have a current mark. * Puts it in the free list. Coalesces all contiguous free chunks. */ static PmReturn_t heap_gcSweep(void) { PmReturn_t retval; pPmObj_t pobj; pPmHeapDesc_t pchunk; uint16_t totalchunksize; #if USE_STRING_CACHE retval = heap_purgeStringCache(pmHeap.gcval); #endif /* Start at the base of the heap */ pobj = (pPmObj_t)pmHeap.base; while ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE]) { /* Skip to the next unmarked or free chunk within the heap */ while (!OBJ_GET_FREE(pobj) && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) && ((uint8_t *)pobj < &pmHeap.base[PM_HEAP_SIZE])) { pobj = (pPmObj_t)((uint8_t *)pobj + OBJ_GET_SIZE(pobj)); } /* Stop if reached the end of the heap */ if ((uint8_t *)pobj >= &pmHeap.base[PM_HEAP_SIZE]) { break; } /* Accumulate the sizes of all consecutive unmarked or free chunks */ totalchunksize = 0; /* Coalesce all contiguous free chunks */ pchunk = (pPmHeapDesc_t)pobj; while (OBJ_GET_FREE(pchunk) || (!OBJ_GET_FREE(pchunk) && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval))) { if ((totalchunksize + OBJ_GET_SIZE(pchunk)) > HEAP_MAX_FREE_CHUNK_SIZE) { break; } totalchunksize = totalchunksize + OBJ_GET_SIZE(pchunk); /* * If the chunk is already free, unlink it because its size * is about to change */ if (OBJ_GET_FREE(pchunk)) { retval = heap_unlinkFromFreelist(pchunk); PM_RETURN_IF_ERROR(retval); } /* Otherwise free and reclaim the unmarked chunk */ else { OBJ_SET_TYPE(pchunk, 0); OBJ_SET_FREE(pchunk, 1); } C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n", pchunk, OBJ_GET_SIZE(pchunk)); /* Proceed to the next chunk */ pchunk = (pPmHeapDesc_t) ((uint8_t *)pchunk + OBJ_GET_SIZE(pchunk)); /* Stop if it's past the end of the heap */ if ((uint8_t *)pchunk >= &pmHeap.base[PM_HEAP_SIZE]) { break; } } /* Set the heap descriptor data */ OBJ_SET_FREE(pobj, 1); OBJ_SET_SIZE(pobj, totalchunksize); /* Insert chunk into free list */ retval = heap_linkToFreelist((pPmHeapDesc_t)pobj); PM_RETURN_IF_ERROR(retval); /* Continue to the next chunk */ pobj = (pPmObj_t)pchunk; } return PM_RET_OK; }
PmReturn_t global_init(void) { PmReturn_t retval; uint8_t *codestr = (uint8_t *)"code"; uint8_t *pchunk; pPmObj_t pobj; #ifdef HAVE_CLASSES uint8_t const *initstr = (uint8_t const *)"__init__"; #endif /* HAVE_CLASSES */ #ifdef HAVE_GENERATORS uint8_t const *genstr = (uint8_t const *)"Generator"; uint8_t const *nextstr = (uint8_t const *)"next"; #endif /* HAVE_GENERATORS */ #ifdef HAVE_ASSERT uint8_t const *exnstr = (uint8_t const *)"Exception"; #endif /* HAVE_ASSERT */ #ifdef HAVE_BYTEARRAY uint8_t const *pbastr = (uint8_t const *)"bytearray"; #endif /* HAVE_BYTEARRAY */ /* Clear the global struct */ sli_memset((uint8_t *)&gVmGlobal, '\0', sizeof(PmVmGlobal_t)); /* Set the PyMite release num (for debug and post mortem) */ gVmGlobal.errVmRelease = PM_RELEASE; /* Init zero */ retval = heap_getChunk(sizeof(PmInt_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); ((pPmInt_t)pobj)->val = (int32_t)0; gVmGlobal.pzero = (pPmInt_t)pobj; /* Init one */ retval = heap_getChunk(sizeof(PmInt_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); ((pPmInt_t)pobj)->val = (int32_t)1; gVmGlobal.pone = (pPmInt_t)pobj; /* Init negone */ retval = heap_getChunk(sizeof(PmInt_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); ((pPmInt_t)pobj)->val = (int32_t)-1; gVmGlobal.pnegone = (pPmInt_t)pobj; /* Init False */ retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL); ((pPmBoolean_t) pobj)->val = (int32_t)C_FALSE; gVmGlobal.pfalse = (pPmInt_t)pobj; /* Init True */ retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL); ((pPmBoolean_t) pobj)->val = (int32_t)C_TRUE; gVmGlobal.ptrue = (pPmInt_t)pobj; /* Init None */ retval = heap_getChunk(sizeof(PmObj_t), &pchunk); PM_RETURN_IF_ERROR(retval); pobj = (pPmObj_t)pchunk; OBJ_SET_TYPE(pobj, OBJ_TYPE_NON); gVmGlobal.pnone = pobj; /* Init "code" string obj */ retval = string_new((uint8_t const **)&codestr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pcodeStr = (pPmString_t)pobj; #ifdef HAVE_CLASSES /* Init "__init__" string obj */ retval = string_new((uint8_t const **)&initstr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pinitStr = (pPmString_t)pobj; #endif /* HAVE_CLASSES */ #ifdef HAVE_GENERATORS /* Init "Generator" string obj */ retval = string_new((uint8_t const **)&genstr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pgenStr = (pPmString_t)pobj; /* Init "next" string obj */ retval = string_new((uint8_t const **)&nextstr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pnextStr = (pPmString_t)pobj; #endif /* HAVE_GENERATORS */ #ifdef HAVE_ASSERT /* Init "Exception" string obj */ retval = string_new((uint8_t const **)&exnstr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pexnStr = (pPmString_t)pobj; #endif /* HAVE_ASSERT */ #ifdef HAVE_BYTEARRAY /* Init "bytearray" string obj */ retval = string_new((uint8_t const **)&pbastr, &pobj); PM_RETURN_IF_ERROR(retval); gVmGlobal.pbaStr = (pPmString_t)pobj; #endif /* HAVE_BYTEARRAY */ /* Init empty builtins */ gVmGlobal.builtins = C_NULL; /* Init native frame */ OBJ_SET_SIZE(&gVmGlobal.nativeframe, sizeof(PmNativeFrame_t)); OBJ_SET_TYPE(&gVmGlobal.nativeframe, OBJ_TYPE_NFM); gVmGlobal.nativeframe.nf_func = C_NULL; gVmGlobal.nativeframe.nf_stack = C_NULL; gVmGlobal.nativeframe.nf_active = C_FALSE; gVmGlobal.nativeframe.nf_numlocals = 0; /* Create empty threadList */ retval = list_new(&pobj); gVmGlobal.threadList = (pPmList_t)pobj; /* Init the PmImgPaths with std image info */ gVmGlobal.imgPaths.memspace[0] = MEMSPACE_PROG; gVmGlobal.imgPaths.pimg[0] = (uint8_t *)&stdlib_img; gVmGlobal.imgPaths.pathcount = 1; #ifdef HAVE_PRINT gVmGlobal.needSoftSpace = C_FALSE; gVmGlobal.somethingPrinted = C_FALSE; #endif /* HAVE_PRINT */ return retval; }
PmReturn_t frame_new(pPmObj_t pfunc, pPmObj_t *r_pobj) { PmReturn_t retval = PM_RET_OK; int16_t fsize = 0; pPmCo_t pco = C_NULL; pPmFrame_t pframe = C_NULL; uint8_t *pchunk; /* Get fxn's code obj */ pco = ((pPmFunc_t)pfunc)->f_co; /* TypeError if passed func's CO is not a true COB */ if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB) { PM_RAISE(retval, PM_RET_EX_TYPE); return retval; } #ifdef HAVE_GENERATORS /* #207: Initializing a Generator using CALL_FUNC needs extra stack slot */ fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 2) * sizeof(pPmObj_t); #elif defined(HAVE_CLASSES) /* #230: Calling a class's __init__() takes two extra spaces on the stack */ fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 1) * sizeof(pPmObj_t); #else fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals - 1) * sizeof(pPmObj_t); #endif /* HAVE_CLASSES */ #ifdef HAVE_CLOSURES /* #256: Add support for closures */ fsize = fsize + pco->co_nfreevars + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length); #endif /* HAVE_CLOSURES */ /* Allocate a frame */ retval = heap_getChunk(fsize, &pchunk); PM_RETURN_IF_ERROR(retval); pframe = (pPmFrame_t)pchunk; /* Set frame fields */ OBJ_SET_TYPE(pframe, OBJ_TYPE_FRM); pframe->fo_back = C_NULL; pframe->fo_func = (pPmFunc_t)pfunc; pframe->fo_memspace = pco->co_memspace; /* Init instruction pointer and block stack */ pframe->fo_ip = pco->co_codeaddr; pframe->fo_blockstack = C_NULL; /* Get globals and attrs from the function object */ pframe->fo_globals = ((pPmFunc_t)pfunc)->f_globals; pframe->fo_attrs = ((pPmFunc_t)pfunc)->f_attrs; #ifndef HAVE_CLOSURES /* Empty stack points to one past locals */ pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals]); #else /* #256: Add support for closures */ pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals + pco->co_nfreevars + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length)]); #endif /* HAVE_CLOSURES */ /* By default, this is a normal frame, not an import or __init__ one */ pframe->fo_isImport = 0; #ifdef HAVE_CLASSES pframe->fo_isInit = 0; #endif /* Clear the stack */ sli_memset((unsigned char *)&(pframe->fo_locals), (char const)0, (unsigned int)fsize - sizeof(PmFrame_t)); /* Return ptr to frame */ *r_pobj = (pPmObj_t)pframe; return retval; }
/* * Reclaims any object that doesn't have a current mark. * Puts it in the free list. Coalesces all contiguous free chunks. */ static PmReturn_t heap_gcSweep(void) { PmReturn_t retval; pPmObj_t pobj; pPmHeapDesc_t pchunk; uint16_t totalchunksize; uint16_t additionalheapsize; /* Start at the base of the heap */ pobj = (pPmObj_t)pmHeap.base; while ((uint8_t *)pobj < &pmHeap.base[HEAP_SIZE]) { /* Skip to the next unmarked or free chunk within the heap */ while (!OBJ_GET_FREE(pobj) && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) && ((uint8_t *)pobj < &pmHeap.base[HEAP_SIZE])) { pobj = (pPmObj_t)((uint8_t *)pobj + OBJ_GET_SIZE(pobj)); /*printf("Object is at addr <%x>\n",(uint32_t)pobj);*/ #if 0 printf("pobj=");obj_print(pobj,0);printf("; type=%x; size=%x\n",OBJ_GET_TYPE(pobj),OBJ_GET_SIZE(pobj)); #endif } /* Stop if reached the end of the heap */ if ((uint8_t *)pobj >= &pmHeap.base[HEAP_SIZE]) { break; } /* Accumulate the sizes of all consecutive unmarked or free chunks */ totalchunksize = 0; additionalheapsize = 0; /* Coalesce all contiguous free chunks */ pchunk = (pPmHeapDesc_t)pobj; while (OBJ_GET_FREE(pchunk) || (!OBJ_GET_FREE(pchunk) && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval))) { totalchunksize += OBJ_GET_SIZE(pchunk); /* * If the chunk is already free, unlink it because its size * is about to change */ if (OBJ_GET_FREE(pchunk)) { retval = heap_unlinkFromFreelist(pchunk); PM_RETURN_IF_ERROR(retval); } /* Otherwise free and reclaim the unmarked chunk */ else { OBJ_SET_TYPE(pchunk, 0); OBJ_SET_FREE(pchunk, 1); additionalheapsize += OBJ_GET_SIZE(pchunk); } C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n", pchunk, OBJ_GET_SIZE(pchunk)); #if 0 /* It's possible for 0-sized chunks to exist (which makes no sense) TODO:solve */ /* They result in infinite loops, so we must curtail them */ if (OBJ_GET_SIZE(pchunk) == 0) { break; } #endif /* Proceed to the next chunk */ pchunk = (pPmHeapDesc_t) ((uint8_t *)pchunk + OBJ_GET_SIZE(pchunk)); /* Stop if it's past the end of the heap */ if ((uint8_t *)pchunk >= &pmHeap.base[HEAP_SIZE]) { break; } } /* Adjust the heap stats */ pmHeap.avail += additionalheapsize; /* Set the heap descriptor data */ OBJ_SET_FREE(pobj, 1); OBJ_SET_SIZE(pobj, totalchunksize); #if 0 /* avoid loops by breaking on 0-size */ if (totalchunksize == 0) { break; } #endif /* Insert chunk into free list */ retval = heap_linkToFreelist((pPmHeapDesc_t)pobj); PM_RETURN_IF_ERROR(retval); /* Continue to the next chunk */ pobj = (pPmObj_t)pchunk; } return PM_RET_OK; }
/** * Obtains a chunk of memory from the free list * * Performs the Best Fit algorithm. * Iterates through the freelist to see if a chunk of suitable size exists. * Shaves a chunk to perfect size iff the remainder is greater than * the minimum chunk size. * * @param size Requested chunk size * @param r_pchunk Return ptr to chunk * @return Return status */ static PmReturn_t heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk) { PmReturn_t retval; pPmHeapDesc_t pchunk; pPmHeapDesc_t premainderChunk; C_ASSERT(r_pchunk != C_NULL); /* Skip to the first chunk that can hold the requested size */ pchunk = pmHeap.pfreelist; while ((pchunk != C_NULL) && (OBJ_GET_SIZE(pchunk) < size)) { pchunk = pchunk->next; } /* No chunk of appropriate size was found, raise OutOfMemory exception */ if (pchunk == C_NULL) { *r_pchunk = C_NULL; PM_RAISE(retval, PM_RET_EX_MEM); return retval; } /* Remove the chunk from the free list */ retval = heap_unlinkFromFreelist(pchunk); PM_RETURN_IF_ERROR(retval); /* Check if a chunk should be carved from what is available */ if (OBJ_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE) { /* Create the heap descriptor for the remainder chunk */ premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size); OBJ_SET_FREE(premainderChunk, 1); OBJ_SET_SIZE(premainderChunk, OBJ_GET_SIZE(pchunk) - size); /* Put the remainder chunk back in the free list */ retval = heap_linkToFreelist(premainderChunk); PM_RETURN_IF_ERROR(retval); /* Convert the chunk from a heap descriptor to an object descriptor */ OBJ_SET_SIZE(pchunk, 0); OBJ_SET_FREE(pchunk, 0); OBJ_SET_SIZE(pchunk, size); C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk, size); } else { /* Set chunk's type to none (overwrites size field's high byte) */ OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON); OBJ_SET_FREE(pchunk, 0); C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk, OBJ_GET_SIZE(pchunk)); } /* * Set the chunk's GC mark so it will be collected during the next GC cycle * if it is not reachable */ OBJ_SET_GCVAL(pchunk, pmHeap.gcval); /* Return the chunk */ *r_pchunk = (uint8_t *)pchunk; return retval; }