/** * 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; }
/* * Marks the given object and the objects it references. * * @param pobj Any non-free heap object * @return Return code */ static PmReturn_t heap_gcMarkObj(pPmObj_t pobj) { PmReturn_t retval = PM_RET_OK; int16_t i = 0; int16_t n; PmType_t type; /* Return if ptr is null or object is already marked */ if (pobj == C_NULL) { return retval; } if (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) { return retval; } /* The pointer must be within the heap (native frame is special case) */ C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0]) && ((uint8_t *)pobj <= &pmHeap.base[PM_HEAP_SIZE])) || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe)); /* The object must not already be free */ C_ASSERT(OBJ_GET_FREE(pobj) == 0); type = (PmType_t)OBJ_GET_TYPE(pobj); switch (type) { /* Objects with no references to other objects */ case OBJ_TYPE_NON: case OBJ_TYPE_INT: case OBJ_TYPE_FLT: case OBJ_TYPE_STR: case OBJ_TYPE_NOB: case OBJ_TYPE_BOOL: case OBJ_TYPE_CIO: OBJ_SET_GCVAL(pobj, pmHeap.gcval); break; case OBJ_TYPE_TUP: i = ((pPmTuple_t)pobj)->length; /* Mark tuple head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark each obj in tuple */ while (--i >= 0) { retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]); PM_RETURN_IF_ERROR(retval); } break; case OBJ_TYPE_LST: /* Mark the list */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val); break; case OBJ_TYPE_DIC: /* Mark the dict head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the keys seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys); PM_RETURN_IF_ERROR(retval); /* Mark the vals seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals); break; case OBJ_TYPE_COB: /* Mark the code obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the names tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names); PM_RETURN_IF_ERROR(retval); /* Mark the consts tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts); PM_RETURN_IF_ERROR(retval); /* #122: Mark the code image if it is in RAM */ if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM) { retval = heap_gcMarkObj((pPmObj_t) (((pPmCo_t)pobj)->co_codeimgaddr)); PM_RETURN_IF_ERROR(retval); } #ifdef HAVE_CLOSURES /* #256: Add support for closures */ /* Mark the cellvars tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_cellvars); #endif /* HAVE_CLOSURES */ break; case OBJ_TYPE_MOD: case OBJ_TYPE_FXN: /* Module and Func objs are implemented via the PmFunc_t */ /* Mark the func obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the code obj */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co); PM_RETURN_IF_ERROR(retval); /* Mark the attr dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs); PM_RETURN_IF_ERROR(retval); /* Mark the globals dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_globals); PM_RETURN_IF_ERROR(retval); #ifdef HAVE_DEFAULTARGS /* Mark the default args tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_defaultargs); PM_RETURN_IF_ERROR(retval); #endif /* HAVE_DEFAULTARGS */ #ifdef HAVE_CLOSURES /* #256: Mark the closure tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_closure); #endif /* HAVE_CLOSURES */ break; #ifdef HAVE_CLASSES case OBJ_TYPE_CLI: /* Mark the obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the class */ retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_class); PM_RETURN_IF_ERROR(retval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs); break; case OBJ_TYPE_MTH: /* Mark the obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the instance */ retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_instance); PM_RETURN_IF_ERROR(retval); /* Mark the func */ retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_func); PM_RETURN_IF_ERROR(retval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_attrs); break; case OBJ_TYPE_CLO: /* Mark the obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_attrs); PM_RETURN_IF_ERROR(retval); /* Mark the base tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_bases); break; #endif /* HAVE_CLASSES */ /* * An obj in ram should not be of these types. * Images arrive in RAM as string objects (image is array of bytes) */ case OBJ_TYPE_CIM: case OBJ_TYPE_NIM: PM_RAISE(retval, PM_RET_EX_SYS); return retval; case OBJ_TYPE_FRM: { pPmObj_t *ppobj2 = C_NULL; /* Mark the frame obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the previous frame, if this isn't a generator's frame */ /* Issue #129: Fix iterator losing its object */ if ((((pPmFrame_t)pobj)->fo_func->f_co->co_flags & CO_GENERATOR) == 0) { retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back); PM_RETURN_IF_ERROR(retval); } /* Mark the fxn obj */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func); PM_RETURN_IF_ERROR(retval); /* Mark the blockstack */ retval = heap_gcMarkObj((pPmObj_t) ((pPmFrame_t)pobj)->fo_blockstack); PM_RETURN_IF_ERROR(retval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs); PM_RETURN_IF_ERROR(retval); /* Mark the globals dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals); PM_RETURN_IF_ERROR(retval); /* Mark each obj in the locals list and the stack */ ppobj2 = ((pPmFrame_t)pobj)->fo_locals; while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp) { retval = heap_gcMarkObj(*ppobj2); PM_RETURN_IF_ERROR(retval); ppobj2++; } break; } case OBJ_TYPE_BLK: /* Mark the block obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the next block in the stack */ retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next); break; case OBJ_TYPE_SGL: /* Mark the seglist obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the seglist's segments */ n = ((pSeglist_t)pobj)->sl_length; pobj = (pPmObj_t)((pSeglist_t)pobj)->sl_rootseg; for (i = 0; i < n; i++) { /* Mark the segment item */ retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i % SEGLIST_OBJS_PER_SEG]); PM_RETURN_IF_ERROR(retval); /* Mark the segment obj head */ if ((i % SEGLIST_OBJS_PER_SEG) == 0) { OBJ_SET_GCVAL(pobj, pmHeap.gcval); } /* Point to the next segment */ else if ((i % SEGLIST_OBJS_PER_SEG) == (SEGLIST_OBJS_PER_SEG - 1)) { pobj = (pPmObj_t)((pSegment_t)pobj)->next; if (pobj == C_NULL) { break; } } } break; case OBJ_TYPE_SQI: /* Mark the sequence iterator obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the sequence */ retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence); break; case OBJ_TYPE_THR: /* Mark the thread obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the current frame */ retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe); break; case OBJ_TYPE_NFM: /* * Mark the obj desc. This doesn't really do much since the * native frame is declared static (not from the heap), but this * is here in case that ever changes */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the native frame's remaining fields if active */ if (gVmGlobal.nativeframe.nf_active) { /* Mark the frame stack */ retval = heap_gcMarkObj((pPmObj_t) gVmGlobal.nativeframe.nf_back); PM_RETURN_IF_ERROR(retval); /* Mark the function object */ retval = heap_gcMarkObj((pPmObj_t) gVmGlobal.nativeframe.nf_func); PM_RETURN_IF_ERROR(retval); /* Mark the stack object */ retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack); PM_RETURN_IF_ERROR(retval); /* Mark the args to the native func */ for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++) { retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_locals[i]); PM_RETURN_IF_ERROR(retval); } } break; #ifdef HAVE_BYTEARRAY case OBJ_TYPE_BYA: OBJ_SET_GCVAL(pobj, pmHeap.gcval); retval = heap_gcMarkObj((pPmObj_t)((pPmBytearray_t)pobj)->val); break; case OBJ_TYPE_BYS: OBJ_SET_GCVAL(pobj, pmHeap.gcval); break; #endif /* HAVE_BYTEARRAY */ default: /* There should be no invalid types */ PM_RAISE(retval, PM_RET_EX_SYS); break; } return retval; }
/* * Marks the given object and the objects it references. * * @param pobj Any non-free heap object * @return Return code */ static PmReturn_t heap_gcMarkObj(pPmObj_t pobj) { PmReturn_t retval = PM_RET_OK; int16_t i = 0; PmType_t type; /* Return if ptr is null or object is already marked */ if ((pobj == C_NULL) || (OBJ_GET_GCVAL(pobj) == pmHeap.gcval)) { return retval; } /* The pointer must be within the heap (native frame is special case) */ C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0]) && ((uint8_t *)pobj <= &pmHeap.base[HEAP_SIZE])) || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe)); /* The object must not already be free */ C_ASSERT(OBJ_GET_FREE(pobj) == 0); type = OBJ_GET_TYPE(pobj); /*if (type == 0x03){ printf("came across string; value is "); string_print(pobj,0); printf("\n"); }*/ switch (type) { /* Objects with no references to other objects */ case OBJ_TYPE_NON: case OBJ_TYPE_INT: case OBJ_TYPE_FLT: case OBJ_TYPE_NOB: OBJ_SET_GCVAL(pobj, pmHeap.gcval); break; case OBJ_TYPE_STR: OBJ_SET_GCVAL(pobj, pmHeap.gcval); #if USE_STRING_CACHE retval = heap_gcMarkObj((pPmObj_t)((pPmString_t)pobj)->next); #endif break; case OBJ_TYPE_TUP: i = ((pPmTuple_t)pobj)->length; /* Mark tuple head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark each obj in tuple */ while (--i >= 0) { retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]); PM_RETURN_IF_ERROR(retval); } break; case OBJ_TYPE_LST: /* Mark the list */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val); break; case OBJ_TYPE_DIC: /* Mark the dict head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the keys seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys); PM_RETURN_IF_ERROR(retval); /* Mark the vals seglist */ retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals); break; case OBJ_TYPE_COB: /* Mark the code obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the names tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names); PM_RETURN_IF_ERROR(retval); /* Mark the consts tuple */ retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts); PM_RETURN_IF_ERROR(retval); /* #122: Mark the code image if it is in RAM */ if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM) { /* Special case: The image is contained in a string object */ retval = heap_gcMarkObj((pPmObj_t) (((pPmCo_t)pobj)->co_codeimgaddr - sizeof(PmObjDesc_t))); } break; case OBJ_TYPE_MOD: case OBJ_TYPE_FXN: /* Module and Func objs are implemented via the PmFunc_t */ /* Mark the func obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the code obj */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co); PM_RETURN_IF_ERROR(retval); /* Mark the attr dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs); PM_RETURN_IF_ERROR(retval); /* Mark the default args tuple */ retval = heap_gcMarkObj((pPmObj_t) ((pPmFunc_t)pobj)->f_defaultargs); break; case OBJ_TYPE_CLO: case OBJ_TYPE_CLI: case OBJ_TYPE_EXN: /* Mark the obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->attrs); PM_RETURN_IF_ERROR(retval); /* Mark the name */ retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->name); PM_RETURN_IF_ERROR(retval); /* Mark the bases */ retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->bases); break; /* * An obj in ram should not be of these types. * Images arrive in RAM as string objects (image is array of bytes) */ case OBJ_TYPE_CIM: case OBJ_TYPE_NIM: PM_RAISE(retval, PM_RET_EX_SYS); return retval; case OBJ_TYPE_FRM: { pPmObj_t *ppobj2 = C_NULL; /* Mark the frame obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the previous frame */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back); PM_RETURN_IF_ERROR(retval); /* Mark the fxn obj */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func); PM_RETURN_IF_ERROR(retval); /* Mark the blockstack */ retval = heap_gcMarkObj((pPmObj_t) ((pPmFrame_t)pobj)->fo_blockstack); PM_RETURN_IF_ERROR(retval); /* Mark the attrs dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs); PM_RETURN_IF_ERROR(retval); /* Mark the globals dict */ retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals); PM_RETURN_IF_ERROR(retval); /* Mark each obj in the locals list and the stack */ ppobj2 = ((pPmFrame_t)pobj)->fo_locals; while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp) { retval = heap_gcMarkObj(*ppobj2); PM_RETURN_IF_ERROR(retval); ppobj2++; } break; } case OBJ_TYPE_BLK: /* Mark the block obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the next block in the stack */ retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next); break; case OBJ_TYPE_SEG: /* Mark the segment obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark each obj in the segment */ for (i = 0; i < SEGLIST_OBJS_PER_SEG; i++) { retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i]); PM_RETURN_IF_ERROR(retval); } /* Mark the next segment */ retval = heap_gcMarkObj((pPmObj_t)((pSegment_t)pobj)->next); break; case OBJ_TYPE_SGL: /* Mark the seglist obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the root segment */ retval = heap_gcMarkObj((pPmObj_t)((pSeglist_t)pobj)->sl_rootseg); break; case OBJ_TYPE_SQI: /* Mark the sequence iterator obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the sequence */ retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence); break; case OBJ_TYPE_THR: /* Mark the thread obj head */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the current frame */ retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe); break; case OBJ_TYPE_NFM: /* * Mark the obj desc. This doesn't really do much since the * native frame is declared static (not from the heap), but this * is here in case that ever changes */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the native frame's fields if it is active */ if (gVmGlobal.nativeframe.nf_active) { /* Mark the frame stack */ retval = heap_gcMarkObj((pPmObj_t) gVmGlobal.nativeframe.nf_back); PM_RETURN_IF_ERROR(retval); /* Mark the function object */ retval = heap_gcMarkObj((pPmObj_t) gVmGlobal.nativeframe.nf_func); PM_RETURN_IF_ERROR(retval); /* Mark the stack object */ retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack); PM_RETURN_IF_ERROR(retval); /* Mark the args to the native func */ for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++) { retval = heap_gcMarkObj(gVmGlobal.nativeframe .nf_locals[i]); PM_RETURN_IF_ERROR(retval); } } break; case OBJ_TYPE_IIS: /* Mark the obj desc */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the name string */ retval = heap_gcMarkObj((pPmObj_t)((pPmImgInfo_t)pobj)->ii_name); PM_RETURN_IF_ERROR(retval); /* Mark the next node in the list */ retval = heap_gcMarkObj((pPmObj_t)((pPmImgInfo_t)pobj)->next); break; case OBJ_TYPE_SLC: /* Mark the obj desc */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the indices */ retval = heap_gcMarkObj((pPmObj_t)((pPmSlice_t)pobj)->start); PM_RETURN_IF_ERROR(retval); retval = heap_gcMarkObj((pPmObj_t)((pPmSlice_t)pobj)->end); PM_RETURN_IF_ERROR(retval); retval = heap_gcMarkObj((pPmObj_t)((pPmSlice_t)pobj)->step); PM_RETURN_IF_ERROR(retval); break; case OBJ_TYPE_MTH: /* Mark the obj desc */ OBJ_SET_GCVAL(pobj, pmHeap.gcval); /* Mark the function and self */ retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->self); PM_RETURN_IF_ERROR(retval); retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->func); PM_RETURN_IF_ERROR(retval); break; } return retval; }