bool heap_mark(chunk_t* chunk, void* p) { // If it's an internal pointer, we shallow mark it instead. This will // preserve the external pointer, but allow us to mark and recurse the // external pointer in the same pass. bool marked; if(chunk->size >= HEAP_SIZECLASSES) { marked = chunk->slots == 0; if(p == chunk->m) chunk->slots = 0; else chunk->shallow = 0; } else { // Calculate the external pointer. void* ext = EXTERNAL_PTR(p, chunk->size); // Shift to account for smallest allocation size. uint32_t slot = FIND_SLOT(ext, chunk->m); // Check if it was already marked. marked = (chunk->slots & slot) == 0; // A clear bit is in-use, a set bit is available. if(p == ext) chunk->slots &= ~slot; else chunk->shallow &= ~slot; } return marked; }
void* ponyint_heap_realloc(pony_actor_t* actor, heap_t* heap, void* p, size_t size) { if(p == NULL) return ponyint_heap_alloc(actor, heap, size); chunk_t* chunk = (chunk_t*)ponyint_pagemap_get(p); if(chunk == NULL) { // Get new memory and copy from the old memory. void* q = ponyint_heap_alloc(actor, heap, size); memcpy(q, p, size); return q; } size_t oldsize; if(chunk->size < HEAP_SIZECLASSES) { // Previous allocation was a ponyint_heap_alloc_small. void* ext = EXTERNAL_PTR(p, chunk->size); // If the new allocation is a ponyint_heap_alloc_small and the pointer is // not an internal pointer, we may be able to reuse this memory. If it is // an internal pointer, we know where the old allocation begins but not // where it ends, so we cannot reuse this memory. if((size <= HEAP_MAX) && (p == ext)) { uint32_t sizeclass = ponyint_heap_index(size); // If the new allocation is the same size or smaller, return the old // one. if(sizeclass <= chunk->size) return p; } oldsize = SIZECLASS_SIZE(chunk->size) - ((uintptr_t)p - (uintptr_t)ext); } else { // Previous allocation was a ponyint_heap_alloc_large. if((size <= chunk->size) && (p == chunk->m)) { // If the new allocation is the same size or smaller, and this is not an // internal pointer, return the old one. We can't reuse internal // pointers in large allocs for the same reason as small ones. return p; } oldsize = chunk->size - ((uintptr_t)p - (uintptr_t)chunk->m); } // Determine how much memory to copy. if(oldsize > size) oldsize = size; // Get new memory and copy from the old memory. void* q = ponyint_heap_alloc(actor, heap, size); memcpy(q, p, oldsize); return q; }
void heap_mark_shallow(chunk_t* chunk, void* p) { if(chunk->size >= HEAP_SIZECLASSES) { chunk->shallow = 0; } else { // Calculate the external pointer. void* ext = EXTERNAL_PTR(p, chunk->size); // Shift to account for smallest allocation size. uint32_t slot = FIND_SLOT(ext, chunk->m); // A clear bit is in-use, a set bit is available. chunk->shallow &= ~slot; } }
void heap_free(chunk_t* chunk, void* p) { if(chunk->size >= HEAP_SIZECLASSES) { if(p == chunk->m) { pool_free_size(chunk->size, chunk->m); chunk->m = NULL; chunk->slots = 1; } return; } // Calculate the external pointer. void* ext = EXTERNAL_PTR(p, chunk->size); if(p == ext) { // Shift to account for smallest allocation size. uint32_t slot = FIND_SLOT(ext, chunk->m); chunk->slots |= slot; } }