/** * Allocates large objects using the `LargeAllocator`. * If allocation fails, because there is not enough memory available, it will * trigger a collection of both the small and the large heap. */ word_t *Heap_AllocLarge(Heap *heap, uint32_t size) { assert(size % ALLOCATION_ALIGNMENT == 0); assert(size >= MIN_BLOCK_SIZE); // Request an object from the `LargeAllocator` Object *object = LargeAllocator_GetBlock(&largeAllocator, size); // If the object is not NULL, update it's metadata and return it if (object != NULL) { return (word_t *)object; } else { // Otherwise collect Heap_Collect(heap, &stack); // After collection, try to alloc again, if it fails, grow the heap by // at least the size of the object we want to alloc object = LargeAllocator_GetBlock(&largeAllocator, size); if (object != NULL) { assert(Heap_IsWordInHeap(heap, (word_t *)object)); return (word_t *)object; } else { size_t increment = MathUtils_DivAndRoundUp(size, BLOCK_TOTAL_SIZE); uint32_t pow2increment = 1U << MathUtils_Log2Ceil(increment); Heap_Grow(heap, pow2increment); object = LargeAllocator_GetBlock(&largeAllocator, size); assert(object != NULL); assert(Heap_IsWordInHeap(heap, (word_t *)object)); return (word_t *)object; } } }
INLINE word_t *Heap_AllocSmall(Heap *heap, uint32_t size) { assert(size % ALLOCATION_ALIGNMENT == 0); assert(size < MIN_BLOCK_SIZE); word_t *start = allocator.cursor; word_t *end = (word_t *)((uint8_t *)start + size); // Checks if the end of the block overlaps with the limit if (end >= allocator.limit) { return Heap_allocSmallSlow(heap, size); } allocator.cursor = end; memset(start, 0, size); Object *object = (Object *)start; ObjectMeta *objectMeta = Bytemap_Get(allocator.bytemap, (word_t *)object); ObjectMeta_SetAllocated(objectMeta); __builtin_prefetch(object + 36, 0, 3); assert(Heap_IsWordInHeap(heap, (word_t *)object)); return (word_t *)object; }
NOINLINE word_t *Heap_allocSmallSlow(Heap *heap, uint32_t size) { Object *object; object = (Object *)Allocator_Alloc(&allocator, size); if (object != NULL) goto done; Heap_Collect(heap, &stack); object = (Object *)Allocator_Alloc(&allocator, size); if (object != NULL) goto done; // A small object can always fit in a single free block // because it is no larger than 8K while the block is 32K. Heap_Grow(heap, 1); object = (Object *)Allocator_Alloc(&allocator, size); done: assert(Heap_IsWordInHeap(heap, (word_t *)object)); assert(object != NULL); ObjectMeta *objectMeta = Bytemap_Get(allocator.bytemap, (word_t *)object); ObjectMeta_SetAllocated(objectMeta); return (word_t *)object; }
void Marker_markProgramStack(Heap *heap, Stack *stack) { // Dumps registers into 'regs' which is on stack jmp_buf regs; setjmp(regs); word_t *dummy; word_t **current = &dummy; word_t **stackBottom = __stack_bottom; while (current <= stackBottom) { word_t *stackObject = (*current) - WORDS_IN_OBJECT_HEADER; if (Heap_IsWordInHeap(heap, stackObject)) { Marker_markConservative(heap, stack, stackObject); } current += 1; } }
void Marker_markConservative(Heap *heap, Stack *stack, word_t *address) { assert(Heap_IsWordInHeap(heap, address)); Object *object = NULL; if (Heap_IsWordInSmallHeap(heap, address)) { object = Object_GetObject(address); assert( object == NULL || Line_ContainsObject(&Block_GetBlockHeader((word_t *)object) ->lineHeaders[Block_GetLineIndexFromWord( Block_GetBlockHeader((word_t *)object), (word_t *)object)])); #ifdef DEBUG_PRINT if (object == NULL) { printf("Not found: %p\n", address); } #endif } else { object = Object_GetLargeObject(&largeAllocator, address); } if (object != NULL && !Object_IsMarked(&object->header)) { Marker_markObject(heap, stack, object); } }