|
#include "gc_heap.h"
|
|
#include "../runtime.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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;
|
|
}
|