/* * Initializes the heap state variables */ PmReturn_t heap_init(void) { pPmHeapDesc_t pchunk; #if PM_HEAP_SIZE > 65535 uint32_t hs; #else uint16_t hs; #endif #if __DEBUG__ /* Fill the heap with a non-NULL value to bring out any heap bugs. */ sli_memset(pmHeap.base, 0xAA, sizeof(pmHeap.base)); #endif /* Init heap globals */ pmHeap.pfreelist = C_NULL; pmHeap.avail = 0; #ifdef HAVE_GC pmHeap.gcval = (uint8_t)0; pmHeap.temp_root_index = (uint8_t)0; heap_gcSetAuto(C_TRUE); #endif /* HAVE_GC */ /* Create as many max-sized chunks as possible in the freelist */ for (pchunk = (pPmHeapDesc_t)pmHeap.base, hs = PM_HEAP_SIZE; hs >= HEAP_MAX_FREE_CHUNK_SIZE; hs -= HEAP_MAX_FREE_CHUNK_SIZE) { OBJ_SET_FREE(pchunk, 1); OBJ_SET_SIZE(pchunk, HEAP_MAX_FREE_CHUNK_SIZE); heap_linkToFreelist(pchunk); pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MAX_FREE_CHUNK_SIZE); } /* Add any leftover memory to the freelist */ if (hs >= HEAP_MIN_CHUNK_SIZE) { /* Round down to a multiple of four */ hs = hs & ~3; OBJ_SET_FREE(pchunk, 1); OBJ_SET_SIZE(pchunk, hs); heap_linkToFreelist(pchunk); } C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%d\n", pmHeap.base, pmHeap.avail); string_cacheInit(); return PM_RET_OK; }
/* * Initializes the heap state variables */ PmReturn_t heap_init(void) { pPmHeapDesc_t pchunk; /* Create one big chunk */ pchunk = (pPmHeapDesc_t)pmHeap.base; OBJ_SET_FREE(pchunk, 1); OBJ_SET_SIZE(pchunk, HEAP_SIZE); pchunk->next = C_NULL; pchunk->prev = C_NULL; /* Init heap globals */ pmHeap.pfreelist = pchunk; pmHeap.avail = HEAP_SIZE; pmHeap.gcval = (uint8_t)0; pmHeap.auto_gc = C_TRUE; C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%d\n", pmHeap.base, HEAP_SIZE); string_cacheInit(); 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; }
/** * 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; }
/* * 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; }
/* * 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; }