|
#include "gc.h"
|
|
#include "gc_heap.h"
|
|
#include "gc_mark.h"
|
|
#include "gc_sweep.h"
|
|
#include "gc_roots.h"
|
|
#include "../runtime.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static RavaVM_t *g_current_vm = NULL;
|
|
static RavaGCStats_t g_stats;
|
|
|
|
void rava_gc_init(void) {
|
|
rava_gc_heap_init();
|
|
rava_gc_mark_init();
|
|
memset(&g_stats, 0, sizeof(g_stats));
|
|
g_current_vm = NULL;
|
|
}
|
|
|
|
void rava_gc_shutdown(void) {
|
|
RavaGCHeap_t *heap = rava_gc_get_heap();
|
|
RavaGCHeader_t *obj = heap->all_objects;
|
|
while (obj) {
|
|
RavaGCHeader_t *next = obj->gc_next;
|
|
rava_gc_finalize_object(obj);
|
|
obj = next;
|
|
}
|
|
heap->all_objects = NULL;
|
|
|
|
rava_gc_heap_shutdown();
|
|
}
|
|
|
|
void rava_gc_set_vm(RavaVM_t *vm) {
|
|
g_current_vm = vm;
|
|
}
|
|
|
|
void* rava_gc_alloc(size_t size, uint8_t type) {
|
|
RavaGCState_t *state = rava_gc_get_state();
|
|
|
|
if (state->gc_enabled && !state->gc_active) {
|
|
rava_gc_collect_if_needed();
|
|
}
|
|
|
|
void *ptr = rava_gc_heap_alloc(size, type);
|
|
if (ptr) {
|
|
g_stats.objects_allocated++;
|
|
g_stats.bytes_allocated += size;
|
|
g_stats.current_live_objects++;
|
|
g_stats.current_live_bytes += size;
|
|
if (g_stats.current_live_bytes > g_stats.peak_live_bytes) {
|
|
g_stats.peak_live_bytes = g_stats.current_live_bytes;
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void rava_gc_free(void *ptr) {
|
|
(void)ptr;
|
|
}
|
|
|
|
void rava_gc_collect(void) {
|
|
RavaGCState_t *state = rava_gc_get_state();
|
|
|
|
if (state->gc_active) {
|
|
return;
|
|
}
|
|
|
|
state->gc_active = true;
|
|
state->objects_marked = 0;
|
|
state->bytes_marked = 0;
|
|
state->gray_count = 0;
|
|
|
|
rava_gc_scan_roots(g_current_vm);
|
|
|
|
rava_gc_process_gray_stack();
|
|
|
|
size_t live_before = g_stats.current_live_objects;
|
|
rava_gc_sweep();
|
|
|
|
rava_gc_recycle_blocks();
|
|
|
|
size_t freed = live_before - state->objects_marked;
|
|
g_stats.objects_freed += freed;
|
|
g_stats.current_live_objects = state->objects_marked;
|
|
g_stats.current_live_bytes = state->bytes_marked;
|
|
g_stats.total_collections++;
|
|
|
|
state->gc_active = false;
|
|
}
|
|
|
|
void rava_gc_collect_if_needed(void) {
|
|
RavaGCHeap_t *heap = rava_gc_get_heap();
|
|
|
|
if (heap->total_allocated > heap->gc_threshold) {
|
|
rava_gc_collect();
|
|
}
|
|
}
|
|
|
|
void rava_gc_enable(void) {
|
|
RavaGCState_t *state = rava_gc_get_state();
|
|
state->gc_enabled = true;
|
|
}
|
|
|
|
void rava_gc_disable(void) {
|
|
RavaGCState_t *state = rava_gc_get_state();
|
|
state->gc_enabled = false;
|
|
}
|
|
|
|
bool rava_gc_is_enabled(void) {
|
|
RavaGCState_t *state = rava_gc_get_state();
|
|
return state->gc_enabled;
|
|
}
|
|
|
|
void rava_gc_pin(void *ptr) {
|
|
if (!ptr) return;
|
|
RavaGCHeader_t *header = (RavaGCHeader_t*)ptr;
|
|
header->gc_flags |= RAVA_GC_FLAG_PINNED;
|
|
}
|
|
|
|
void rava_gc_unpin(void *ptr) {
|
|
if (!ptr) return;
|
|
RavaGCHeader_t *header = (RavaGCHeader_t*)ptr;
|
|
header->gc_flags &= ~RAVA_GC_FLAG_PINNED;
|
|
}
|
|
|
|
RavaGCStats_t rava_gc_get_stats(void) {
|
|
return g_stats;
|
|
}
|
|
|
|
void rava_gc_print_stats(void) {
|
|
printf("GC Statistics:\n");
|
|
printf(" Total collections: %zu\n", g_stats.total_collections);
|
|
printf(" Objects allocated: %zu\n", g_stats.objects_allocated);
|
|
printf(" Objects freed: %zu\n", g_stats.objects_freed);
|
|
printf(" Current live objects: %zu\n", g_stats.current_live_objects);
|
|
printf(" Current live bytes: %zu\n", g_stats.current_live_bytes);
|
|
printf(" Peak live bytes: %zu\n", g_stats.peak_live_bytes);
|
|
}
|