...
This commit is contained in:
@@ -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;
|
|
||||||
}
|
}
|
||||||
@@ -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**)¤t; // 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
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user