size_t heap_size(chunk_t* chunk) { if(chunk->size >= HEAP_SIZECLASSES) return chunk->size; return SIZECLASS_SIZE(chunk->size); }
static size_t sweep_small(chunk_t* chunk, chunk_t** avail, chunk_t** full, uint32_t empty) { size_t used = 0; chunk_t* next; while(chunk != NULL) { next = chunk->next; chunk->slots &= chunk->shallow; if(chunk->slots == 0) { used += sizeof(block_t); chunk->next = *full; *full = chunk; } else if(chunk->slots == empty) { destroy_small(chunk); } else { used += sizeof(block_t) - (__pony_popcount(chunk->slots) * SIZECLASS_SIZE(chunk->size)); chunk->next = *avail; *avail = chunk; } chunk = next; } return used; }
void ponyint_heap_endgc(heap_t* heap) { size_t used = 0; for(int i = 0; i < HEAP_SIZECLASSES; i++) { chunk_t* list1 = heap->small_free[i]; chunk_t* list2 = heap->small_full[i]; heap->small_free[i] = NULL; heap->small_full[i] = NULL; chunk_t** avail = &heap->small_free[i]; chunk_t** full = &heap->small_full[i]; size_t size = SIZECLASS_SIZE(i); uint32_t empty = sizeclass_empty[i]; used += sweep_small(list1, avail, full, empty, size); used += sweep_small(list2, avail, full, empty, size); } heap->large = sweep_large(heap->large, &used); // Foreign object sizes will have been added to heap->used already. Here we // add local object sizes as well and set the next gc point for when memory // usage has increased. heap->used += used; heap->next_gc = (size_t)((double)heap->used * heap_nextgc_factor); if(heap->next_gc < heap_initialgc) heap->next_gc = heap_initialgc; }
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_alloc_small(pony_actor_t* actor, heap_t* heap, uint32_t sizeclass) { chunk_t* chunk = heap->small_free[sizeclass]; void* m; // If there are none in this size class, get a new one. if(chunk != NULL) { // Clear and use the first available slot. uint32_t slots = chunk->slots; uint32_t bit = __pony_ffs(slots) - 1; slots &= ~(1 << bit); m = chunk->m + (bit << HEAP_MINBITS); chunk->slots = slots; if(slots == 0) { heap->small_free[sizeclass] = chunk->next; chunk->next = heap->small_full[sizeclass]; heap->small_full[sizeclass] = chunk; } } else { chunk_t* n = (chunk_t*) POOL_ALLOC(chunk_t); n->actor = actor; n->m = (char*) POOL_ALLOC(block_t); n->size = sizeclass; // Clear the first bit. n->shallow = n->slots = sizeclass_init[sizeclass]; n->next = NULL; pagemap_set(n->m, n); heap->small_free[sizeclass] = n; chunk = n; // Use the first slot. m = chunk->m; } heap->used += SIZECLASS_SIZE(sizeclass); return m; }
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; } if(chunk->size < HEAP_SIZECLASSES) { // Previous allocation was a ponyint_heap_alloc_small. if(size <= HEAP_MAX) { 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; } // Get new memory and copy from the old memory. void* q = ponyint_heap_alloc(actor, heap, size); memcpy(q, p, SIZECLASS_SIZE(chunk->size)); return q; } // Previous allocation was a ponyint_heap_alloc_large. if(size <= chunk->size) return p; // Get new memory and copy from the old memory. void* q = ponyint_heap_alloc(actor, heap, size); memcpy(q, p, chunk->size); return q; }