free(heap);
}
-static void* allocate_small_block(heap_t* heap, uintptr_t num_slots)
+static void* allocate_small_block(heap_t* heap, uint64_t ptrmap, uintptr_t num_slots)
{
- void* object;
uintptr_t index = (num_slots >= MIN_NUM_SLOTS) ? (num_slots - HEAP_INDEX_OFFSET) : 0;
/* If we dont have any available segments, allocate a new one */
if (NULL == heap->heaps[index].available) {
splaytree_insert(heap->segments, (uintptr_t)&(heap->heaps[index].available->start[0]), heap->heaps[index].available);
}
/* Allocate the object */
- object = segment_alloc(heap->heaps[index].available);
+ obj_t* obj = (obj_t*)segment_alloc(heap->heaps[index].available);
+ obj->objmap = ptrmap;
/* If we filled it up then move it to the full list */
if (segment_full(heap->heaps[index].available)) {
segment_t* current = heap->heaps[index].available;
current->next = heap->heaps[index].full;
heap->heaps[index].full = current;
}
- return object;
+ return (void*)(obj+1);
}
-static void* allocate_large_block(heap_t* heap, uintptr_t num_slots)
+static void* allocate_large_block(heap_t* heap, uint64_t ptrmap, uintptr_t num_slots)
{
uintptr_t size = (num_slots * sizeof(uintptr_t));
block_t* blk = (block_t*)malloc(sizeof(block_t) + size);
blk->size = size;
splaytree_insert(heap->blocks, (uintptr_t)&blk->data[0], blk);
- return (&blk->data[0]);
+ obj_t* obj = (obj_t*)(&blk->data[0]);
+ obj->objmap = ptrmap;
+ return (obj_t*)(obj+1);
}
-void* heap_allocate(heap_t* heap, uintptr_t num_slots)
+void* heap_allocate(heap_t* heap, uint64_t ptrmap, uintptr_t num_slots)
{
void* obj = NULL;
if (num_slots <= MAX_NUM_SLOTS) {
- obj = allocate_small_block(heap, num_slots);
+ obj = allocate_small_block(heap, ptrmap, num_slots);
} else {
- obj = allocate_large_block(heap, num_slots);
+ obj = allocate_large_block(heap, ptrmap, num_slots);
}
return obj;
}
{
heap->greylist = heap->blocks;
heap->blocks = splaytree_create((del_fn_t)free, (cmp_fn_t)block_compare);
+ for (unsigned int i = 0; i < NUM_HEAP_STACKS; i++) {
+ segment_clear_map(heap->heaps[i].available);
+ segment_clear_map(heap->heaps[i].full);
+ }
}
void heap_finish_collection(heap_t* heap)
void* heap_find_and_mark(heap_t* heap, uintptr_t addr)
{
- void* obj = NULL;
+ obj_t* obj = NULL;
segment_t* seg = splaytree_lookup(heap->segments, addr);
if (NULL != seg) {
obj = segment_find_and_mark(seg, addr);
block_t* block = splaytree_delete(heap->greylist, addr);
if (NULL != block) {
splaytree_insert(heap->blocks, addr, block);
- obj = &block->data[0];
+ obj = (obj_t*)&block->data[0];
}
}
- return obj;
+ return (obj == NULL) ? NULL : (void*)(obj+1);
}
#include "atf.h"
#include "heap.h"
-
#include "gc.h"
+#include <stdio.h>
+
TEST_SUITE(Heap) {
/* Verify: heap_create
*************************************************************************/
TEST(Verify_Create_allocates_and_initializes_a_heap) {
heap_t* heap = heap_create();
CHECK(heap != NULL);
- CHECK(NULL != heap_allocate(heap, 64));
- CHECK(NULL != heap_allocate(heap, 65));
+ CHECK(NULL != heap_allocate(heap, 0, 64));
+ CHECK(NULL != heap_allocate(heap, 0, 65));
heap_destroy(heap);
}
*************************************************************************/
TEST(Verify_Allocate_should_allocate_a_new_segment_if_the_subheap_is_empty) {
heap_t* heap = heap_create();
- CHECK(NULL != heap_allocate(heap, 1));
+ CHECK(NULL != heap_allocate(heap, 0, 1));
CHECK(heap->heaps[0].available != NULL);
heap_destroy(heap);
}
TEST(Verify_Allocate_should_allocate_a_new_segment_if_the_current_segment_is_full) {
heap_t* heap = heap_create();
- CHECK(NULL != heap_allocate(heap, 1));
+ CHECK(NULL != heap_allocate(heap, 0, 1));
heap->heaps[0].available->blockmap[0] = 1 << ((sizeof(uint16_t) * 8) - 1);
heap->heaps[0].available->blockmap[16] = 1 << ((sizeof(uint16_t) * 8) - 1);
- CHECK(NULL != heap_allocate(heap, 1));
+ CHECK(NULL != heap_allocate(heap, 0, 1));
CHECK(heap->heaps[0].available == NULL);
CHECK(heap->heaps[0].full != NULL);
CHECK(heap->heaps[0].full->next == NULL);
TEST(Verify_Allocate_should_allocate_the_minimum_size_if_num_slots_is_less_than_the_minimum) {
heap_t* heap = heap_create();
- CHECK(NULL != heap_allocate(heap, 0));
+ CHECK(NULL != heap_allocate(heap, 0, 0));
CHECK(heap->heaps[0].available != NULL);
heap_destroy(heap);
}
TEST(Verify_Allocate_should_allocate_a_large_block_if_the_number_of_slots_is_greater_than_the_max) {
heap_t* heap = heap_create();
- CHECK(NULL != heap_allocate(heap, 65));
+ CHECK(NULL != heap_allocate(heap, 0, 65));
CHECK(NULL != heap->blocks->root->value);
heap_destroy(heap);
}
TEST(Verify_finish_collection_moves_segments_from_the_full_list_to_the_available_list_when_some_blocks_are_reclaimed) {
heap_t* heap = heap_create();
segment_t* seg = segment_create(2, NULL);
- seg->blockmap[0] = 42;
splaytree_t* blocks = heap->blocks;
heap->heaps[1].full = seg;
heap_start_collection(heap);
+ seg->blockmap[0] = 42;
heap_finish_collection(heap);
CHECK(blocks != heap->blocks);
CHECK(heap->heaps[1].available == seg);
heap_t* heap = heap_create();
segment_t* seg2 = segment_create(2, NULL);
segment_t* seg1 = segment_create(2, seg2);
- seg1->blockmap[0] = 0;
- seg2->blockmap[0] = 42;
splaytree_t* blocks = heap->blocks;
heap->heaps[1].full = seg1;
heap_start_collection(heap);
+ seg1->blockmap[0] = 0;
+ seg2->blockmap[0] = 42;
heap_finish_collection(heap);
CHECK(blocks != heap->blocks);
CHECK(heap->heaps[1].available == seg2);
heap_t* heap = heap_create();
segment_t* seg2 = segment_create(2, NULL);
segment_t* seg1 = segment_create(2, seg2);
- seg1->blockmap[0] = 0;
splaytree_t* blocks = heap->blocks;
heap->heaps[1].full = seg1;
heap_start_collection(heap);
+ seg1->blockmap[0] = 0;
heap_finish_collection(heap);
CHECK(blocks != heap->blocks);
CHECK(heap->heaps[1].available == NULL);
TEST(Verify_finish_collection_does_nothing_when_full_list_contains_only_full_segments) {
heap_t* heap = heap_create();
segment_t* seg = segment_create(2, NULL);
- seg->blockmap[0] = 0;
splaytree_t* blocks = heap->blocks;
heap->heaps[1].full = seg;
heap_start_collection(heap);
+ seg->blockmap[0] = 0;
heap_finish_collection(heap);
CHECK(blocks != heap->blocks);
CHECK(heap->heaps[1].available == NULL);
CHECK(heap->heaps[1].full == seg);
heap_destroy(heap);
}
+
+ /* Verify: heap_find_and_mark
+ *************************************************************************/
+ TEST(Verify_find_and_mark_should_find_and_return_the_indicated_small_block) {
+ heap_t* heap = heap_create();
+ void* addr = heap_allocate(heap, 0, 2);
+ heap_start_collection(heap);
+ CHECK(addr == heap_find_and_mark(heap, (uintptr_t)addr));
+ heap_finish_collection(heap);
+ heap_destroy(heap);
+ }
+
+ TEST(Verify_find_and_mark_should_fail_to_find_the_indicated_small_block) {
+ heap_t* heap = heap_create();
+ (void)heap_allocate(heap, 0, 2);
+ heap_start_collection(heap);
+ CHECK(NULL == heap_find_and_mark(heap, (uintptr_t)NULL));
+ heap_finish_collection(heap);
+ heap_destroy(heap);
+ }
+
+ TEST(Verify_find_and_mark_should_find_and_return_the_indicated_large_block) {
+ heap_t* heap = heap_create();
+ void* addr = heap_allocate(heap, 0, 65);
+ heap_start_collection(heap);
+ CHECK(addr == heap_find_and_mark(heap, (uintptr_t)addr));
+ heap_finish_collection(heap);
+ heap_destroy(heap);
+ }
+
+ TEST(Verify_find_and_mark_should_fail_to_find_the_indicated_large_block) {
+ heap_t* heap = heap_create();
+ (void)heap_allocate(heap, 0, 65);
+ heap_start_collection(heap);
+ CHECK(NULL == heap_find_and_mark(heap, (uintptr_t)NULL));
+ heap_finish_collection(heap);
+ heap_destroy(heap);
+ }
}