This commit is contained in:
retoor 2025-12-05 01:12:25 +01:00
parent de7f824feb
commit e33fa20c60
8 changed files with 121 additions and 29 deletions

View File

@ -17,7 +17,10 @@ SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
IR_SOURCES = ir/ir.c ir/ir_gen.c
IR_OBJECTS = $(IR_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
GC_SOURCES = runtime/gc/gc.c runtime/gc/gc_heap.c runtime/gc/gc_mark.c runtime/gc/gc_sweep.c runtime/gc/gc_roots.c
GC_OBJECTS = $(GC_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c $(GC_SOURCES)
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
LOADER_SOURCES = loader/loader.c
@ -143,6 +146,9 @@ TEST_SOCKETS_OBJECTS = $(TEST_SOCKETS_SOURCES:.c=.o)
TEST_METHOD_REF_SOURCES = tests/test_method_ref.c
TEST_METHOD_REF_OBJECTS = $(TEST_METHOD_REF_SOURCES:.c=.o)
TEST_GC_SOURCES = tests/test_gc.c
TEST_GC_OBJECTS = $(TEST_GC_SOURCES:.c=.o)
UNITTEST_SOURCES = tests/unittest.c
UNITTEST_OBJECTS = $(UNITTEST_SOURCES:.c=.o)
@ -268,6 +274,9 @@ test_sockets: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJ
test_method_ref: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_METHOD_REF_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_gc: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_GC_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_unittest_demo: $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

View File

@ -496,7 +496,14 @@ static inline uint32_t _rava_class_hash(const char *name) {
return hash & (RAVA_CLASS_HASH_SIZE - 1);
}
static bool g_gc_initialized = false;
RavaVM_t* rava_vm_create(RavaProgram_t *program) {
if (!g_gc_initialized) {
rava_gc_init();
g_gc_initialized = true;
}
RavaVM_t *vm = calloc(1, sizeof(RavaVM_t));
if (!vm) return NULL;
vm->program = program;
@ -522,6 +529,8 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) {
vm->class_hash[h] = (int)i;
}
rava_gc_set_vm(vm);
return vm;
}
@ -4712,10 +4721,10 @@ uf_arraylist_size: {
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST) {
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
if (gc_type == RAVA_GC_TYPE_ARRAYLIST) {
UF_PUSH(rava_nanbox_int((int32_t)rava_arraylist_size((RavaArrayList_t*)ptr)));
} else if (type == RAVA_COLLECTION_HASHMAP) {
} else if (gc_type == RAVA_GC_TYPE_HASHMAP) {
UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size((RavaHashMap_t*)ptr)));
} else {
UF_PUSH(rava_nanbox_int(0));
@ -4731,15 +4740,15 @@ uf_arraylist_remove: {
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) {
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
if (gc_type == RAVA_GC_TYPE_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) {
RavaValue_t v = rava_arraylist_remove((RavaArrayList_t*)ptr, (size_t)rava_nanbox_to_int(idx_or_key));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else if (type == RAVA_COLLECTION_HASHMAP && rava_nanbox_is_string(idx_or_key)) {
} else if (gc_type == RAVA_GC_TYPE_HASHMAP && rava_nanbox_is_string(idx_or_key)) {
RavaValue_t v = rava_hashmap_remove((RavaHashMap_t*)ptr, rava_nanbox_as_string(idx_or_key));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
@ -4759,10 +4768,10 @@ uf_arraylist_clear: {
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST) {
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
if (gc_type == RAVA_GC_TYPE_ARRAYLIST) {
rava_arraylist_clear((RavaArrayList_t*)ptr);
} else if (type == RAVA_COLLECTION_HASHMAP) {
} else if (gc_type == RAVA_GC_TYPE_HASHMAP) {
rava_hashmap_clear((RavaHashMap_t*)ptr);
}
}

View File

@ -8,6 +8,15 @@
#include <stdint.h>
#include <stdbool.h>
typedef struct RavaGCHeader {
uint8_t gc_type;
uint8_t gc_mark;
uint8_t gc_age;
uint8_t gc_flags;
uint32_t gc_size;
struct RavaGCHeader *gc_next;
} RavaGCHeader_t;
typedef enum {
RAVA_VAL_INT,
RAVA_VAL_LONG,
@ -27,6 +36,7 @@ typedef enum {
} RavaValueType_e;
typedef struct {
RavaGCHeader_t gc;
RavaValueType_e element_type;
size_t length;
void *data;
@ -43,6 +53,7 @@ typedef struct RavaMethodRef_t RavaMethodRef_t;
#define RAVA_OBJECT_HASH_SIZE 32
struct RavaObject_t {
RavaGCHeader_t gc;
char *class_name;
char **field_names;
RavaValue_t *field_values;
@ -75,6 +86,7 @@ struct RavaValue_t {
#define RAVA_COLLECTION_HASHMAP 2
struct RavaArrayList_t {
RavaGCHeader_t gc;
int collection_type;
RavaValue_t *data;
size_t size;
@ -90,6 +102,7 @@ typedef struct {
} RavaHashMapEntry_t;
struct RavaHashMap_t {
RavaGCHeader_t gc;
int collection_type;
RavaHashMapEntry_t *buckets;
size_t bucket_count;
@ -100,6 +113,7 @@ struct RavaHashMap_t {
#define RAVA_SOCKET_TYPE_SERVER 2
struct RavaSocket_t {
RavaGCHeader_t gc;
int socket_type;
int fd;
bool connected;
@ -110,12 +124,14 @@ struct RavaSocket_t {
#define RAVA_STREAM_TYPE_OUTPUT 2
struct RavaStream_t {
RavaGCHeader_t gc;
int stream_type;
int fd;
bool closed;
};
struct RavaMethodRef_t {
RavaGCHeader_t gc;
char *class_name;
char *method_name;
bool is_constructor;
@ -406,4 +422,29 @@ RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char
RavaNativeValue_t rava_value_to_native(RavaValue_t value);
RavaValue_t rava_native_to_value(RavaNativeValue_t native);
#define RAVA_GC_WHITE 0
#define RAVA_GC_GRAY 1
#define RAVA_GC_BLACK 2
#define RAVA_GC_FLAG_PINNED 0x01
#define RAVA_GC_FLAG_FINALIZER 0x02
#define RAVA_GC_TYPE_OBJECT 1
#define RAVA_GC_TYPE_ARRAY 2
#define RAVA_GC_TYPE_ARRAYLIST 3
#define RAVA_GC_TYPE_HASHMAP 4
#define RAVA_GC_TYPE_STRING 5
#define RAVA_GC_TYPE_SOCKET 6
#define RAVA_GC_TYPE_STREAM 7
#define RAVA_GC_TYPE_METHODREF 8
void rava_gc_init(void);
void rava_gc_shutdown(void);
void rava_gc_set_vm(RavaVM_t *vm);
void* rava_gc_alloc(size_t size, uint8_t type);
void rava_gc_collect(void);
void rava_gc_collect_if_needed(void);
void rava_gc_enable(void);
void rava_gc_disable(void);
#endif

View File

@ -1,7 +1,9 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "gc/gc.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define RAVA_MAX_ARRAY_LENGTH 1000000
@ -12,9 +14,11 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
length = RAVA_MAX_ARRAY_LENGTH;
}
RavaArray_t *array = malloc(sizeof(RavaArray_t));
RavaArray_t *array = rava_gc_alloc(sizeof(RavaArray_t), RAVA_GC_TYPE_ARRAY);
if (!array) return NULL;
memset((char*)array + sizeof(RavaGCHeader_t), 0, sizeof(RavaArray_t) - sizeof(RavaGCHeader_t));
array->element_type = element_type;
array->length = length;
array->data = NULL;
@ -42,7 +46,6 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
}
if (!array->data && length > 0) {
free(array);
return NULL;
}
@ -52,7 +55,6 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
void rava_array_destroy(RavaArray_t *array) {
if (!array) return;
free(array->data);
free(array);
}
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) {

View File

@ -1,12 +1,17 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "gc/gc.h"
#include <stdlib.h>
#include <string.h>
#define ARRAYLIST_INITIAL_CAPACITY 16
RavaArrayList_t* rava_arraylist_create(void) {
RavaArrayList_t *list = calloc(1, sizeof(RavaArrayList_t));
RavaArrayList_t *list = rava_gc_alloc(sizeof(RavaArrayList_t), RAVA_GC_TYPE_ARRAYLIST);
if (!list) return NULL;
memset((char*)list + sizeof(RavaGCHeader_t), 0, sizeof(RavaArrayList_t) - sizeof(RavaGCHeader_t));
list->collection_type = RAVA_COLLECTION_ARRAYLIST;
list->data = calloc(ARRAYLIST_INITIAL_CAPACITY, sizeof(RavaValue_t));
list->size = 0;
@ -17,7 +22,6 @@ RavaArrayList_t* rava_arraylist_create(void) {
void rava_arraylist_destroy(RavaArrayList_t *list) {
if (!list) return;
free(list->data);
free(list);
}
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value) {
@ -75,7 +79,11 @@ static unsigned int _rava_hash_string(const char *str) {
}
RavaHashMap_t* rava_hashmap_create(void) {
RavaHashMap_t *map = calloc(1, sizeof(RavaHashMap_t));
RavaHashMap_t *map = rava_gc_alloc(sizeof(RavaHashMap_t), RAVA_GC_TYPE_HASHMAP);
if (!map) return NULL;
memset((char*)map + sizeof(RavaGCHeader_t), 0, sizeof(RavaHashMap_t) - sizeof(RavaGCHeader_t));
map->collection_type = RAVA_COLLECTION_HASHMAP;
map->bucket_count = RAVA_HASHMAP_BUCKET_SIZE;
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
@ -91,7 +99,6 @@ void rava_hashmap_destroy(RavaHashMap_t *map) {
}
}
free(map->buckets);
free(map);
}
static void _rava_hashmap_resize(RavaHashMap_t *map) {

View File

@ -1,11 +1,14 @@
#include "runtime.h"
#include "gc/gc.h"
#include <stdlib.h>
#include <string.h>
RavaMethodRef_t* rava_method_ref_create(const char *class_name, const char *method_name, bool is_constructor, bool is_static) {
RavaMethodRef_t *ref = calloc(1, sizeof(RavaMethodRef_t));
RavaMethodRef_t *ref = rava_gc_alloc(sizeof(RavaMethodRef_t), RAVA_GC_TYPE_METHODREF);
if (!ref) return NULL;
memset((char*)ref + sizeof(RavaGCHeader_t), 0, sizeof(RavaMethodRef_t) - sizeof(RavaGCHeader_t));
ref->class_name = class_name ? strdup(class_name) : NULL;
ref->method_name = method_name ? strdup(method_name) : NULL;
ref->is_constructor = is_constructor;
@ -19,5 +22,4 @@ void rava_method_ref_destroy(RavaMethodRef_t *ref) {
if (!ref) return;
free(ref->class_name);
free(ref->method_name);
free(ref);
}

View File

@ -1,5 +1,7 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "gc/gc.h"
#include "gc/gc_heap.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h>
#include <string.h>
@ -15,8 +17,11 @@ static inline uint32_t _rava_field_hash(const char *name) {
}
RavaObject_t* rava_object_create(const char *class_name) {
RavaObject_t *obj = calloc(1, sizeof(RavaObject_t));
RavaObject_t *obj = rava_gc_alloc(sizeof(RavaObject_t), RAVA_GC_TYPE_OBJECT);
if (!obj) return NULL;
memset((char*)obj + sizeof(RavaGCHeader_t), 0, sizeof(RavaObject_t) - sizeof(RavaGCHeader_t));
obj->class_name = strdup(class_name);
obj->field_capacity = 8;
obj->field_names = calloc(obj->field_capacity, sizeof(char*));
@ -25,7 +30,6 @@ RavaObject_t* rava_object_create(const char *class_name) {
free(obj->field_names);
free(obj->field_values);
free(obj->class_name);
free(obj);
return NULL;
}
obj->field_count = 0;
@ -43,7 +47,6 @@ void rava_object_destroy(RavaObject_t *obj) {
}
free(obj->field_names);
free(obj->field_values);
free(obj);
}
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) {

View File

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "gc/gc.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -10,7 +11,11 @@
#include <errno.h>
RavaSocket_t* rava_socket_create(void) {
RavaSocket_t *sock = calloc(1, sizeof(RavaSocket_t));
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
if (!sock) return NULL;
memset((char*)sock + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
sock->socket_type = RAVA_SOCKET_TYPE_CLIENT;
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
sock->connected = false;
@ -20,6 +25,7 @@ RavaSocket_t* rava_socket_create(void) {
RavaSocket_t* rava_socket_create_connected(const char *host, int port) {
RavaSocket_t *sock = rava_socket_create();
if (!sock) return NULL;
if (sock->fd < 0) return sock;
if (rava_socket_connect(sock, host, port)) {
@ -29,7 +35,11 @@ RavaSocket_t* rava_socket_create_connected(const char *host, int port) {
}
RavaSocket_t* rava_server_socket_create(int port) {
RavaSocket_t *sock = calloc(1, sizeof(RavaSocket_t));
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
if (!sock) return NULL;
memset((char*)sock + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
sock->socket_type = RAVA_SOCKET_TYPE_SERVER;
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
sock->connected = false;
@ -66,7 +76,6 @@ void rava_socket_destroy(RavaSocket_t *socket) {
if (!socket->closed && socket->fd >= 0) {
close(socket->fd);
}
free(socket);
}
bool rava_socket_connect(RavaSocket_t *socket, const char *host, int port) {
@ -100,7 +109,14 @@ RavaSocket_t* rava_server_socket_accept(RavaSocket_t *server) {
int client_fd = accept(server->fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) return NULL;
RavaSocket_t *client = calloc(1, sizeof(RavaSocket_t));
RavaSocket_t *client = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
if (!client) {
close(client_fd);
return NULL;
}
memset((char*)client + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
client->socket_type = RAVA_SOCKET_TYPE_CLIENT;
client->fd = client_fd;
client->connected = true;
@ -129,7 +145,11 @@ void rava_socket_close(RavaSocket_t *socket) {
}
RavaStream_t* rava_stream_create(int fd, int stream_type) {
RavaStream_t *stream = calloc(1, sizeof(RavaStream_t));
RavaStream_t *stream = rava_gc_alloc(sizeof(RavaStream_t), RAVA_GC_TYPE_STREAM);
if (!stream) return NULL;
memset((char*)stream + sizeof(RavaGCHeader_t), 0, sizeof(RavaStream_t) - sizeof(RavaGCHeader_t));
stream->stream_type = stream_type;
stream->fd = fd;
stream->closed = false;
@ -137,8 +157,7 @@ RavaStream_t* rava_stream_create(int fd, int stream_type) {
}
void rava_stream_destroy(RavaStream_t *stream) {
if (!stream) return;
free(stream);
(void)stream;
}
char* rava_stream_read(RavaStream_t *stream) {