#include "gc_heap.h" #include "../runtime.h" #include #include static RavaGCHeap_t g_heap; void rava_gc_heap_init(void) { memset(&g_heap, 0, sizeof(g_heap)); g_heap.gc_threshold = RAVA_GC_INITIAL_THRESHOLD; g_heap.all_blocks = NULL; g_heap.current_block = NULL; g_heap.free_blocks = NULL; g_heap.recyclable_blocks = NULL; g_heap.all_objects = NULL; } void rava_gc_heap_shutdown(void) { RavaGCBlock_t *block = g_heap.all_blocks; while (block) { RavaGCBlock_t *next = block->next; free(block); block = next; } block = g_heap.free_blocks; while (block) { RavaGCBlock_t *next = block->next; free(block); block = next; } memset(&g_heap, 0, sizeof(g_heap)); } static RavaGCBlock_t* _rava_gc_create_block(void) { RavaGCBlock_t *block = calloc(1, sizeof(RavaGCBlock_t)); if (!block) return NULL; block->flags = 0; block->free_lines = RAVA_GC_LINES_PER_BLOCK; memset(block->line_marks, 0, sizeof(block->line_marks)); return block; } bool rava_gc_request_block(void) { if (g_heap.free_blocks) { RavaGCBlock_t *block = g_heap.free_blocks; g_heap.free_blocks = block->next; block->next = g_heap.all_blocks; block->prev = NULL; if (g_heap.all_blocks) { g_heap.all_blocks->prev = block; } g_heap.all_blocks = block; g_heap.current_block = block; g_heap.bump_ptr = block->data; g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE; return true; } if (g_heap.recyclable_blocks) { RavaGCBlock_t *block = g_heap.recyclable_blocks; g_heap.recyclable_blocks = block->next; block->next = g_heap.all_blocks; block->prev = NULL; if (g_heap.all_blocks) { g_heap.all_blocks->prev = block; } g_heap.all_blocks = block; g_heap.current_block = block; g_heap.bump_ptr = block->data; g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE; return true; } RavaGCBlock_t *block = _rava_gc_create_block(); if (!block) return false; block->next = g_heap.all_blocks; block->prev = NULL; if (g_heap.all_blocks) { g_heap.all_blocks->prev = block; } g_heap.all_blocks = block; g_heap.current_block = block; g_heap.bump_ptr = block->data; g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE; return true; } void* rava_gc_heap_alloc(size_t size, uint8_t type) { size = RAVA_ALIGN(size, 8); if (size > RAVA_GC_BLOCK_SIZE) { RavaGCHeader_t *obj = calloc(1, size); if (!obj) return NULL; obj->gc_type = type; obj->gc_mark = RAVA_GC_WHITE; obj->gc_age = 0; obj->gc_flags = RAVA_GC_FLAG_PINNED; obj->gc_size = (uint32_t)size; obj->gc_next = g_heap.all_objects; g_heap.all_objects = obj; g_heap.total_allocated += size; return obj; } if (!g_heap.current_block || g_heap.bump_ptr + size > g_heap.block_limit) { if (!rava_gc_request_block()) { return NULL; } } RavaGCHeader_t *obj = (RavaGCHeader_t*)g_heap.bump_ptr; g_heap.bump_ptr += size; g_heap.total_allocated += size; obj->gc_type = type; obj->gc_mark = RAVA_GC_WHITE; obj->gc_age = 0; obj->gc_flags = 0; obj->gc_size = (uint32_t)size; obj->gc_next = g_heap.all_objects; g_heap.all_objects = obj; return obj; } void rava_gc_heap_free(void *ptr, size_t size) { (void)ptr; (void)size; } void rava_gc_recycle_blocks(void) { RavaGCBlock_t *block = g_heap.all_blocks; RavaGCBlock_t *prev = NULL; while (block) { RavaGCBlock_t *next = block->next; bool has_live = false; for (size_t i = 0; i < RAVA_GC_LINES_PER_BLOCK; i++) { if (block->line_marks[i]) { has_live = true; break; } } if (!has_live && block != g_heap.current_block) { if (prev) { prev->next = next; } else { g_heap.all_blocks = next; } if (next) { next->prev = prev; } block->next = g_heap.free_blocks; block->prev = NULL; g_heap.free_blocks = block; memset(block->line_marks, 0, sizeof(block->line_marks)); block->flags = 0; block->free_lines = RAVA_GC_LINES_PER_BLOCK; } else { prev = block; } block = next; } } RavaGCHeap_t* rava_gc_get_heap(void) { return &g_heap; }