This commit is contained in:
nub31
2025-05-03 20:37:47 +02:00
parent bc2d858c5a
commit 248f95fa6e
2 changed files with 44 additions and 60 deletions

View File

@@ -1,19 +1,16 @@
import "core"; import "core";
struct Human {
let name: String;
let age: int64;
}
func main() { func main() {
let i = 1;
while true { while true {
let x = new Human let x = new Human
{ {
name = "test", name = "test",
age = 34958743 age = 34958743
}; };
i = i + 1;
} }
}
struct Human {
let name: String;
let age: int64;
} }

View File

@@ -1,38 +1,35 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h>
/* Constants */ #define MINIMUM_THRESHOLD (1024 * 1024 * 8)
#define GC_INITIAL_THRESHOLD (1024 * 1024 * 8) // 8MB initial threshold #define MINIMUM_BLOCK_SIZE 4096
#define GC_MIN_ALLOC 4096 // Minimum allocation size
/* Allocation metadata structures */
typedef struct alloc_block { typedef struct alloc_block {
uint8_t mark; // Mark bit for GC uint64_t mark;
uint8_t padding[7]; // Padding for alignment uint64_t size;
int64_t size; // Size of the allocation struct alloc_block* next;
struct alloc_block* next; // Next allocation in the list
} alloc_block_t; } alloc_block_t;
typedef struct free_block { typedef struct free_block {
int64_t size; // Size of the free block uint64_t size;
struct free_block* next; // Next free block in the list struct free_block* next;
} free_block_t; } free_block_t;
/* Global variables */
static alloc_block_t* alloc_list_head = NULL; static alloc_block_t* alloc_list_head = NULL;
static free_block_t* free_list_head = NULL; static free_block_t* free_list_head = NULL;
static void* stack_start = NULL; static void* stack_start = NULL;
static int64_t free_list_size = 0; static int64_t free_list_size = 0;
static int64_t mark_count = 0; static int64_t mark_count = 0;
/* GC metrics */ /* Bytes allocated since last collect */
static int64_t gc_bytes_allocated = 0; static int64_t bytes_allocated = 0;
static int64_t gc_trigger_threshold = GC_INITIAL_THRESHOLD; /* Threshold for next collect */
static int64_t trigger_threshold = MINIMUM_THRESHOLD;
/* Forward declarations */
static void* sys_mmap(size_t size); static void* sys_mmap(size_t size);
static void* get_sp(void);
static void gc_collect(void); static void gc_collect(void);
static void gc_mark(void* ptr); static void gc_mark(void* ptr);
static void gc_mark_stack(void); static void gc_mark_stack(void);
@@ -41,23 +38,19 @@ static int64_t max(int64_t a, int64_t b);
static void insert_into_free(free_block_t* block); static void insert_into_free(free_block_t* block);
static void merge(free_block_t* block); static void merge(free_block_t* block);
/* Initialize the garbage collector */
void gc_init(void) { void gc_init(void) {
// Save the current stack pointer as the start of the stack stack_start = get_sp();
volatile unsigned long var = 0;
stack_start = (void*)((unsigned long)&var + 4);
} }
/* Allocate memory with garbage collection */ /* Allocate memory with garbage collection */
void* gc_alloc(int64_t size) { void* gc_alloc(int64_t size) {
size += sizeof(alloc_block_t); // Adjust for metadata size size += sizeof(alloc_block_t); // Adjust for metadata size
// Check if we need to trigger garbage collection if (bytes_allocated > trigger_threshold) {
if (gc_bytes_allocated > gc_trigger_threshold) {
gc_collect(); gc_collect();
} }
gc_bytes_allocated += size; // Adjust allocation counter bytes_allocated += size;
// Search free list for a suitable block // Search free list for a suitable block
free_block_t* current = free_list_head; free_block_t* current = free_list_head;
@@ -74,7 +67,7 @@ void* gc_alloc(int64_t size) {
if (current == NULL) { if (current == NULL) {
// No suitable block found, allocate a new one // No suitable block found, allocate a new one
int64_t alloc_size = max(size, GC_MIN_ALLOC); int64_t alloc_size = max(size, MINIMUM_BLOCK_SIZE);
void* memory = sys_mmap(alloc_size); void* memory = sys_mmap(alloc_size);
free_block_t* new_block = (free_block_t*)memory; free_block_t* new_block = (free_block_t*)memory;
@@ -128,21 +121,16 @@ void* gc_alloc(int64_t size) {
/* Run garbage collection */ /* Run garbage collection */
static void gc_collect(void) { static void gc_collect(void) {
printf("Reached threshold of %ld bytes. Starting GC\n", gc_bytes_allocated);
gc_mark_stack(); gc_mark_stack();
printf("\tMarking done. Objects marked is %ld\n", mark_count);
gc_sweep(); gc_sweep();
printf("\tSweep done. We now have %ld allocated bytes\n", gc_bytes_allocated); trigger_threshold = max(bytes_allocated * 2, MINIMUM_THRESHOLD);
gc_trigger_threshold = max(gc_bytes_allocated * 2, GC_INITIAL_THRESHOLD); bytes_allocated = 0;
gc_bytes_allocated = 0;
printf("\tThe next threshold is %ld allocated bytes\n", gc_trigger_threshold);
printf("\tFree list size is %ld\n", free_list_size);
} }
/* Mark phase of GC - scan stack for pointers */
static void gc_mark_stack(void) { static void gc_mark_stack(void) {
mark_count = 0; mark_count = 0;
void** current = (void**)&current; // Approximate current stack position
void** current = get_sp();
void** end = (void**)stack_start; void** end = (void**)stack_start;
while (current < end) { while (current < end) {
@@ -153,23 +141,20 @@ static void gc_mark_stack(void) {
/* Mark a single object and recursively mark its contents */ /* Mark a single object and recursively mark its contents */
static void gc_mark(void* ptr) { static void gc_mark(void* ptr) {
if (ptr == NULL) if (ptr == NULL) {
return; return;
}
// Check if ptr points to a valid allocation
alloc_block_t* block = alloc_list_head; alloc_block_t* block = alloc_list_head;
while (block != NULL) { while (block != NULL) {
void* block_data = (void*)(block + 1); void* block_data = (void*)(block + 1);
if (block_data == ptr) { if (block_data == ptr) {
// Found the block, mark it if not already marked
if (block->mark == 0) { if (block->mark == 0) {
mark_count++; mark_count++;
block->mark = 1; block->mark = 1;
// Recursively mark all pointers in the object
void** p = (void**)block_data; void** p = (void**)block_data;
void** end = (void**)((char*)block_data + block->size); void** end = (void**)((char*)block_data + block->size);
while (p < end) { while (p < end) {
gc_mark(*p); gc_mark(*p);
p++; p++;
@@ -181,14 +166,12 @@ static void gc_mark(void* ptr) {
} }
} }
/* Sweep phase of GC - free unmarked objects */
static void gc_sweep(void) { static void gc_sweep(void) {
alloc_block_t* current = alloc_list_head; alloc_block_t* current = alloc_list_head;
alloc_block_t* prev = NULL; alloc_block_t* prev = NULL;
while (current != NULL) { while (current != NULL) {
if (current->mark == 0) { if (current->mark == 0) {
// Unmarked object, remove it from the allocation list
alloc_block_t* next = current->next; alloc_block_t* next = current->next;
if (prev == NULL) { if (prev == NULL) {
@@ -197,10 +180,8 @@ static void gc_sweep(void) {
prev->next = next; prev->next = next;
} }
// Adjust allocated bytes counter bytes_allocated -= (current->size + sizeof(alloc_block_t));
gc_bytes_allocated -= (current->size + sizeof(alloc_block_t));
// Add to free list
free_block_t* free_block = (free_block_t*)current; free_block_t* free_block = (free_block_t*)current;
free_block->size = current->size + sizeof(alloc_block_t) - sizeof(free_block_t); free_block->size = current->size + sizeof(alloc_block_t) - sizeof(free_block_t);
free_block->next = NULL; free_block->next = NULL;
@@ -209,7 +190,6 @@ static void gc_sweep(void) {
current = next; current = next;
} else { } else {
// Marked object, unmark it for next GC cycle
current->mark = 0; current->mark = 0;
prev = current; prev = current;
current = current->next; current = current->next;
@@ -243,35 +223,42 @@ static void insert_into_free(free_block_t* block) {
merge(current); merge(current);
} }
/* Merge a block with any adjacent blocks */
static void merge(free_block_t* block) { static void merge(free_block_t* block) {
while (block->next != NULL) { while (block->next != NULL) {
char* block_end = (char*)block + block->size + sizeof(free_block_t); char* block_end = (char*)block + block->size + sizeof(free_block_t);
if (block_end == (char*)block->next) { if (block_end == (char*)block->next) {
// Blocks are adjacent, merge them
free_list_size--; free_list_size--;
block->size += block->next->size + sizeof(free_block_t); block->size += block->next->size + sizeof(free_block_t);
block->next = block->next->next; block->next = block->next->next;
} else { } else {
// No more adjacent blocks
break; break;
} }
} }
} }
/* Helper to map memory from the system */
static void* sys_mmap(size_t size) { static void* sys_mmap(size_t size) {
void* result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); void* result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (result == MAP_FAILED) { if (result == MAP_FAILED) {
_exit(1); // Exit on failure perror("[sys_mmap] mmap failed");
exit(1);
} }
return result; return result;
} }
/* Return maximum of two values */
static int64_t max(int64_t a, int64_t b) { static int64_t max(int64_t a, int64_t b) {
return (a > b) ? a : b; if (a > b) {
return a;
} else {
return b;
}
}
void* get_sp(void) {
volatile unsigned long var = 0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-local-addr"
return (void*)((unsigned long)&var + 4);
#pragma GCC diagnostic pop
} }