/* * 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; }
/** * 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; }
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; }