From dbcf50c71bda051ec950f8949c5456580d8efe88 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Mon, 6 Dec 2021 00:12:02 +0100 Subject: [PATCH] added garbage collector draft --- samples/makegarbage.noja | 10 +++ src/main.c | 2 + src/o_builtins.c | 2 +- src/o_net_builtins.c | 2 +- src/objects/heap.c | 170 ++++++++++++++++++++++++++++++++++++++- src/objects/o_bool.c | 2 +- src/objects/o_buffer.c | 2 +- src/objects/o_closure.c | 12 ++- src/objects/o_float.c | 2 +- src/objects/o_int.c | 2 +- src/objects/o_list.c | 21 ++++- src/objects/o_map.c | 26 +++++- src/objects/o_none.c | 2 +- src/objects/o_string.c | 11 ++- src/objects/objects.c | 52 +++++++----- src/objects/objects.h | 30 +++++-- src/runtime/o_func.c | 12 ++- src/runtime/o_nfunc.c | 2 +- src/runtime/runtime.c | 54 +++++++++++-- src/utils/stack.c | 20 +++++ src/utils/stack.h | 1 + 21 files changed, 389 insertions(+), 48 deletions(-) create mode 100644 samples/makegarbage.noja diff --git a/samples/makegarbage.noja b/samples/makegarbage.noja new file mode 100644 index 0000000..8210955 --- /dev/null +++ b/samples/makegarbage.noja @@ -0,0 +1,10 @@ + +i = 0; +n = 10000000; + +while i < n: + { + 1 + 1 * 1; + i = i + 1; + print('\r', 100.0 * i / n, '% '); + } diff --git a/src/main.c b/src/main.c index fde0a52..9f60976 100644 --- a/src/main.c +++ b/src/main.c @@ -237,6 +237,8 @@ int main(int argc, char **argv) Object *result = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0); + // NOTE: The `builtins` pointer is invalidated now. + if(result == NULL) { fprintf(stderr, "RUNTIME ERROR: %s.\n", error.base.message); diff --git a/src/o_builtins.c b/src/o_builtins.c index a424008..3276cb6 100644 --- a/src/o_builtins.c +++ b/src/o_builtins.c @@ -21,7 +21,7 @@ typedef struct { Runtime *runtime; } BuiltinsMapOjbect; -static const Type t_builtins_map = { +static TypeObject t_builtins_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "builtins map", .size = sizeof(BuiltinsMapOjbect), diff --git a/src/o_net_builtins.c b/src/o_net_builtins.c index ef4cbda..a710ad9 100644 --- a/src/o_net_builtins.c +++ b/src/o_net_builtins.c @@ -32,7 +32,7 @@ typedef struct { Runtime *runtime; } NetworkBuiltinsMapOjbect; -static const Type t_builtins_map = { +static TypeObject t_builtins_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "network builtins map", .size = sizeof(NetworkBuiltinsMapOjbect), diff --git a/src/objects/heap.c b/src/objects/heap.c index 2c6f4d9..27bddfd 100644 --- a/src/objects/heap.c +++ b/src/objects/heap.c @@ -17,8 +17,17 @@ struct OflowAlloc { struct xHeap { int size; int used; + int total; void *body; OflowAlloc *oflow; + + _Bool collecting; + _Bool collection_failed; + void *old_body; + int old_used; + int old_total; + OflowAlloc *old_oflow; + Error *error; }; Heap *Heap_New(int size) @@ -31,10 +40,12 @@ Heap *Heap_New(int size) if(heap == NULL) return NULL; + heap->total = 0; heap->size = size; heap->used = 0; heap->body = malloc(size); heap->oflow = 0; + heap->collecting = 0; if(heap->body == NULL) { @@ -67,7 +78,12 @@ void Heap_Free(Heap *heap) free(heap); } -void *Heap_Malloc(Heap *heap, const Type *type, Error *err) +float Heap_GetUsagePercentage(Heap *heap) +{ + return 100.0 * heap->total / heap->size; +} + +void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err) { void *addr = Heap_RawMalloc(heap, type->size, err); @@ -107,14 +123,20 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err) heap->oflow = oflow; addr = oflow->body; + + heap->total += size; } else { + int prev_used = heap->used; + if(heap->used & 7) heap->used = (heap->used & ~7) + 8; addr = heap->body + heap->used; + heap->used += size; + heap->total += heap->used - prev_used; } assert(((intptr_t) addr) % 8 == 0); @@ -124,4 +146,150 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err) #endif return addr; +} + +_Bool Heap_StartCollection(Heap *heap, Error *error) +{ + assert(heap->collecting == 0); + + void *new_body = malloc(heap->size); + + if(new_body == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + heap->old_body = heap->body; + heap->old_used = heap->used; + heap->old_total = heap->total; + heap->old_oflow = heap->oflow; + heap->total = 0; + heap->body = new_body; + heap->used = 0; + heap->oflow = NULL; + heap->collecting = 1; + heap->collection_failed = 0; + heap->error = error; + return 1; +} + +_Bool Heap_StopCollection(Heap *heap) +{ + assert(heap->collecting == 1); + + if(heap->collection_failed) + { + free(heap->old_body); + return 0; + } + + /* Call destructors here */ + + while(heap->old_oflow) + { + OflowAlloc *prev = heap->old_oflow->prev; + free(heap->old_oflow); + heap->old_oflow = prev; + } + + free(heap->old_body); + + heap->collecting = 0; + return 1; +} + +void Heap_CollectExtension(void **referer, int size, Heap *heap) +{ + assert(referer != NULL); + assert(heap->collecting); + + void *old_location = *referer; + + if(heap->collection_failed || old_location == NULL) + return; + + void *new_location = Heap_RawMalloc(heap, size, heap->error); + + if(new_location == NULL) + { + heap->collection_failed = 1; + return; + } + + memcpy(new_location, old_location, size); + + *referer = new_location; +} + +void Heap_CollectReference(Object **referer, Heap *heap) +{ + assert(referer != NULL); + assert(heap->collecting); + + Object *old_location = *referer; + + if(heap->collection_failed || old_location == NULL) + return; + + Object *new_location; + + if(old_location->flags & Object_STATIC) + + // The object doesn't need to be moved + // since it was statically allocated. + new_location = old_location; + + else if(old_location->flags & Object_MOVED) + + // The object was already moved. + new_location = ((MovedObject*) old_location)->new_location; + + else + { + // This object wasn't moved to + // the new heap yet. + + // Get some information. + TypeObject *type = old_location->type; + int size = type->size; + + // Copy the object to a new location. + { + new_location = Heap_RawMalloc(heap, size, heap->error); + + if(new_location == NULL) + { + heap->collection_failed = 1; + return; + } + + memcpy(new_location, old_location, size); + } + + // Set the old location as moved and + // leave the reference to the new + // location. + { + old_location->flags |= Object_MOVED; + + assert((int) sizeof(MovedObject) <= size); + ((MovedObject*) old_location)->new_location = new_location; + } + } + + // Update the referer + *referer = new_location; + + // Collect the reference to the type. + if((Object*) new_location->type != new_location) + Heap_CollectReference((Object**) &new_location->type, heap); + + // Collect all of the references to + // extensions allocate using the GC'd + // heap. + Object_WalkExtensions(new_location, Heap_CollectExtension, heap); + + // Now collect all of the children. + Object_WalkReferences(new_location, Heap_CollectReference, heap); } \ No newline at end of file diff --git a/src/objects/o_bool.c b/src/objects/o_bool.c index 53508e7..8e284a7 100644 --- a/src/objects/o_bool.c +++ b/src/objects/o_bool.c @@ -5,7 +5,7 @@ static _Bool to_bool(Object *obj, Error *err); static void print(Object *obj, FILE *fp); -static const Type t_bool = { +static TypeObject t_bool = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "bool", .size = sizeof (Object), diff --git a/src/objects/o_buffer.c b/src/objects/o_buffer.c index 833965f..6942dd9 100644 --- a/src/objects/o_buffer.c +++ b/src/objects/o_buffer.c @@ -20,7 +20,7 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error static int count(Object *self); static void print(Object *obj, FILE *fp); -static const Type t_buffer = { +static TypeObject t_buffer = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "buffer", .size = sizeof (BufferObject), diff --git a/src/objects/o_closure.c b/src/objects/o_closure.c index df53ca9..9694c99 100644 --- a/src/objects/o_closure.c +++ b/src/objects/o_closure.c @@ -9,13 +9,15 @@ struct ClosureObject { Object *vars; }; +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); static Object *select(Object *self, Object *key, Heap *heap, Error *err); -static const Type t_closure = { +static TypeObject t_closure = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "closure", .size = sizeof(ClosureObject), .select = select, + .walk = walk, }; Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error) @@ -54,4 +56,12 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err) } return selected; +} + +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) +{ + ClosureObject *closure = (ClosureObject*) self; + + callback((Object**) &closure->prev, userp); + callback(&closure->vars, userp); } \ No newline at end of file diff --git a/src/objects/o_float.c b/src/objects/o_float.c index ebc2bf7..5dfffc4 100644 --- a/src/objects/o_float.c +++ b/src/objects/o_float.c @@ -9,7 +9,7 @@ typedef struct { double val; } FloatObject; -static const Type t_float = { +static TypeObject t_float = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "float", .size = sizeof (FloatObject), diff --git a/src/objects/o_int.c b/src/objects/o_int.c index f0d730a..883ebd3 100644 --- a/src/objects/o_int.c +++ b/src/objects/o_int.c @@ -11,7 +11,7 @@ typedef struct { long long int val; } IntObject; -static const Type t_int = { +static TypeObject t_int = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "int", .size = sizeof (IntObject), diff --git a/src/objects/o_list.c b/src/objects/o_list.c index 6d1c97c..52bffe9 100644 --- a/src/objects/o_list.c +++ b/src/objects/o_list.c @@ -12,8 +12,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); static void print(Object *obj, FILE *fp); +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); -static const Type t_list = { +static TypeObject t_list = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "list", .size = sizeof (ListObject), @@ -21,6 +23,8 @@ static const Type t_list = { .insert = insert, .count = count, .print = print, + .walk = walk, + .walkexts = walkexts, }; static inline int calc_capacity(int mapper_size) @@ -53,6 +57,21 @@ Object *Object_NewList(int capacity, Heap *heap, Error *error) return (Object*) obj; } +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) +{ + ListObject *list = (ListObject*) self; + + for(int i = 0; i < list->count; i += 1) + callback(&list->vals[i], userp); +} + +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp) +{ + ListObject *list = (ListObject*) self; + + callback((void**) &list->vals, sizeof(Object) * list->capacity, userp); +} + static Object *select(Object *self, Object *key, Heap *heap, Error *error) { assert(self != NULL); diff --git a/src/objects/o_map.c b/src/objects/o_map.c index 86755c4..bb73ec0 100644 --- a/src/objects/o_map.c +++ b/src/objects/o_map.c @@ -14,8 +14,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); static void print(Object *self, FILE *fp); +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); -static const Type t_map = { +static TypeObject t_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "map", .size = sizeof (MapObject), @@ -23,6 +25,8 @@ static const Type t_map = { .insert = insert, .count = count, .print = print, + .walk = walk, + .walkexts = walkexts, }; static inline int calc_capacity(int mapper_size) @@ -68,6 +72,26 @@ Object *Object_NewMap(int num, Heap *heap, Error *error) return (Object*) obj; } +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) +{ + MapObject *map = (MapObject*) self; + + for(int i = 0; i < map->count; i += 1) + { + callback(&map->keys[i], userp); + callback(&map->vals[i], userp); + } +} + +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp) +{ + MapObject *map = (MapObject*) self; + + callback((void**) &map->mapper, sizeof(int) * map->mapper_size, userp); + callback((void**) &map->keys, sizeof(Object) * calc_capacity(map->mapper_size), userp); + callback((void**) &map->vals, sizeof(Object) * calc_capacity(map->mapper_size), userp); +} + static Object *select(Object *self, Object *key, Heap *heap, Error *error) { assert(self != NULL); diff --git a/src/objects/o_none.c b/src/objects/o_none.c index db15911..6c36025 100644 --- a/src/objects/o_none.c +++ b/src/objects/o_none.c @@ -5,7 +5,7 @@ static _Bool op_eql(Object *self, Object *other); static void print(Object *obj, FILE *fp); -static const Type t_none = { +static TypeObject t_none = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "none", .size = sizeof (Object), diff --git a/src/objects/o_string.c b/src/objects/o_string.c index 2758620..d6fea11 100644 --- a/src/objects/o_string.c +++ b/src/objects/o_string.c @@ -16,8 +16,9 @@ static Object *copy(Object *self, Heap *heap, Error *err); static void print(Object *obj, FILE *fp); static char *to_string(Object *self, int *size, Heap *heap, Error *err); static _Bool op_eql(Object *self, Object *other); +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); -static const Type t_string = { +static TypeObject t_string = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "string", .atomic = ATMTP_STRING, @@ -28,6 +29,7 @@ static const Type t_string = { .print = print, .to_string = to_string, .op_eql = op_eql, + .walkexts = walkexts, }; static char *to_string(Object *self, int *size, Heap *heap, Error *err) @@ -127,4 +129,11 @@ static void print(Object *obj, FILE *fp) StringObject *str = (StringObject*) obj; fprintf(fp, "%.*s", str->size, str->body); +} + +static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp) +{ + StringObject *str = (StringObject*) self; + + callback((void**) &str->body, str->size+1, userp); } \ No newline at end of file diff --git a/src/objects/objects.c b/src/objects/objects.c index efa36f3..3097e1b 100644 --- a/src/objects/objects.c +++ b/src/objects/objects.c @@ -2,17 +2,17 @@ #include "../utils/defs.h" #include "objects.h" -const Type t_type = { +TypeObject t_type = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "type", - .size = sizeof (Type), + .size = sizeof (TypeObject), }; const char *Object_GetName(const Object *obj) { assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); const char *name = type->name; @@ -21,7 +21,7 @@ const char *Object_GetName(const Object *obj) return name; } -const Type *Object_GetType(const Object *obj) +const TypeObject *Object_GetType(const Object *obj) { assert(obj != NULL); assert(obj->type != NULL); @@ -33,7 +33,7 @@ unsigned int Object_GetSize(const Object *obj, Error *err) assert(err != NULL); assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); return type->size; @@ -44,7 +44,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err) assert(err != NULL); assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->deepsize == NULL) @@ -60,7 +60,7 @@ int Object_Hash(Object *obj, Error *err) { assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type != NULL); if(type->hash == NULL) @@ -77,7 +77,7 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err) assert(err != NULL); assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type != NULL); if(type->copy == NULL) @@ -94,7 +94,7 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E assert(err); assert(obj); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->call == NULL) @@ -110,7 +110,7 @@ void Object_Print(Object *obj, FILE *fp) { assert(obj != NULL); - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->print == NULL) @@ -125,7 +125,7 @@ Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err) assert(key); assert(coll); - const Type *type = Object_GetType(coll); + const TypeObject *type = Object_GetType(coll); assert(type); if(type->select == NULL) @@ -143,7 +143,7 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err) assert(key); assert(coll); - const Type *type = Object_GetType(coll); + const TypeObject *type = Object_GetType(coll); assert(type); if(type->delete == NULL) @@ -161,7 +161,7 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *e assert(key); assert(coll); - const Type *type = Object_GetType(coll); + const TypeObject *type = Object_GetType(coll); assert(type); if(type->insert == NULL) @@ -178,7 +178,7 @@ int Object_Count(Object *coll, Error *err) assert(err); assert(coll); - const Type *type = Object_GetType(coll); + const TypeObject *type = Object_GetType(coll); assert(type); if(type->count == NULL) @@ -195,7 +195,7 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err) assert(err); assert(iter); - const Type *type = Object_GetType(iter); + const TypeObject *type = Object_GetType(iter); assert(type); if(type->next == NULL) @@ -212,7 +212,7 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err) assert(err); assert(iter); - const Type *type = Object_GetType(iter); + const TypeObject *type = Object_GetType(iter); assert(type); if(type->prev == NULL) @@ -263,7 +263,7 @@ long long int Object_ToInt(Object *obj, Error *err) return 0; } - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_int == NULL) @@ -286,7 +286,7 @@ _Bool Object_ToBool(Object *obj, Error *err) return 0; } - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_bool == NULL) @@ -309,7 +309,7 @@ double Object_ToFloat(Object *obj, Error *err) return 0; } - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_float == NULL) @@ -332,7 +332,7 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err) return NULL; } - const Type *type = Object_GetType(obj); + const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_string == NULL) @@ -360,4 +360,16 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error) } return obj1->type->op_eql(obj1, obj2); +} + +void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp) +{ + if(parent->type->walk != NULL) + parent->type->walk(parent, callback, userp); +} + +void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsigned int size, void *userp), void *userp) +{ + if(parent->type->walkexts != NULL) + parent->type->walkexts(parent, callback, userp); } \ No newline at end of file diff --git a/src/objects/objects.h b/src/objects/objects.h index 22dd5e7..85f80de 100644 --- a/src/objects/objects.h +++ b/src/objects/objects.h @@ -4,15 +4,20 @@ #include #include "../utils/error.h" -typedef struct Type Type; +typedef struct TypeObject TypeObject; typedef struct Object Object; typedef struct xHeap Heap; struct Object { - const Type *type; + TypeObject *type; unsigned int flags; }; +typedef struct { + Object base; + Object *new_location; +} MovedObject; + typedef enum { ATMTP_NOTATOMIC = 0, ATMTP_INT, @@ -21,7 +26,7 @@ typedef enum { ATMTP_STRING, } AtomicType; -struct Type { +struct TypeObject { Object base; @@ -57,18 +62,27 @@ struct Type { }; _Bool (*op_eql)(Object *self, Object *other); + + // All. + void (*walk) (Object *self, void (*callback)(Object **referer, void *userp), void *userp); + void (*walkexts)(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); }; enum { Object_STATIC = 1, + Object_MOVED = 2, }; Heap* Heap_New(int size); void Heap_Free(Heap *heap); -void* Heap_Malloc (Heap *heap, const Type *type, Error *err); -void* Heap_RawMalloc(Heap *heap, int size, Error *err); +void* Heap_Malloc (Heap *heap, TypeObject *type, Error *err); +void* Heap_RawMalloc(Heap *heap, int size, Error *err); +_Bool Heap_StartCollection(Heap *heap, Error *error); +_Bool Heap_StopCollection(Heap *heap); +void Heap_CollectReference(Object **referer, Heap *heap); +float Heap_GetUsagePercentage(Heap *heap); -const Type* Object_GetType(const Object *obj); +const TypeObject* Object_GetType(const Object *obj); const char* Object_GetName(const Object *obj); unsigned int Object_GetSize(const Object *obj, Error *err); unsigned int Object_GetDeepSize(const Object *obj, Error *err); @@ -83,6 +97,8 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error int Object_Count (Object *coll, Error *err); Object* Object_Next (Object *iter, Heap *heap, Error *err); Object* Object_Prev (Object *iter, Heap *heap, Error *err); +void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp); +void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); Object* Object_NewMap(int num, Heap *heap, Error *error); Object* Object_NewList(int capacity, Heap *heap, Error *error); @@ -108,5 +124,5 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err); _Bool Object_Compare(Object *obj1, Object *obj2, Error *error); -extern const Type t_type; +extern TypeObject t_type; #endif \ No newline at end of file diff --git a/src/runtime/o_func.c b/src/runtime/o_func.c index b1983d1..a1a256d 100644 --- a/src/runtime/o_func.c +++ b/src/runtime/o_func.c @@ -13,14 +13,22 @@ typedef struct { } FunctionObject; static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error); +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); -static const Type t_func = { +static TypeObject t_func = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "function", .size = sizeof (FunctionObject), - .call = call, + .call = call, + .walk = walk, }; +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) +{ + FunctionObject *func = (FunctionObject*) self; + callback(&func->closure, userp); +} + static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error) { assert(self != NULL); diff --git a/src/runtime/o_nfunc.c b/src/runtime/o_nfunc.c index ba61964..553a296 100644 --- a/src/runtime/o_nfunc.c +++ b/src/runtime/o_nfunc.c @@ -13,7 +13,7 @@ typedef struct { static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error); -static const Type t_nfunc = { +static TypeObject t_nfunc = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "native function", .size = sizeof (NativeFunctionObject), diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 812bdf4..70c4ae2 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -1032,6 +1032,33 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } +static _Bool collect(Runtime *runtime, Error *error) +{ + Frame *frame = runtime->frame; + + if(!Heap_StartCollection(runtime->heap, error)) + return 0; + + Heap_CollectReference(&runtime->builtins, runtime->heap); + + while(frame) + { + Heap_CollectReference(&frame->locals, runtime->heap); + Heap_CollectReference(&frame->closure, runtime->heap); + frame = frame->prev; + } + + for(unsigned int i = 0; i < Stack_Size(runtime->stack); i += 1) + { + Object **ref = (Object**) Stack_TopRef(runtime->stack, -i); + assert(ref != NULL); + + Heap_CollectReference(ref, runtime->heap); + } + + return Heap_StopCollection(runtime->heap); +} + Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc) { assert(runtime != NULL); @@ -1086,14 +1113,29 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * Error_Report(error, 0, "Forced abortion"); else while(step(runtime, error)) - if(!runtime->callback_addr(runtime, runtime->callback_userp)) - { - Error_Report(error, 0, "Forced abortion"); - break; - } + { + if(!runtime->callback_addr(runtime, runtime->callback_userp)) + { + Error_Report(error, 0, "Forced abortion"); + break; + } + + //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); + + if(Heap_GetUsagePercentage(runtime->heap) > 100) + if(!collect(runtime, error)) + break; + } } else - while(step(runtime, error)); + while(step(runtime, error)) + { + if(Heap_GetUsagePercentage(runtime->heap) > 100) + if(!collect(runtime, error)) + break; + + //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); + } // This is what the function will return. Object *result = NULL; diff --git a/src/utils/stack.c b/src/utils/stack.c index b695c50..a7b97b9 100644 --- a/src/utils/stack.c +++ b/src/utils/stack.c @@ -54,6 +54,26 @@ void *Stack_Top(Stack *s, int n) return s->body[s->used + n - 1]; } +void **Stack_TopRef(Stack *s, int n) +{ + assert(n <= 0); + + if(Stack_IsReadOnlyCopy(s)) + return NULL; + + // Remove readonly bit. + s = unmark(s); + + if(s->used == 0) + return NULL; + + if((int) s->used + n - 1 < 0) + return NULL; + + return &s->body[s->used + n - 1]; +} + + _Bool Stack_Pop(Stack *s, unsigned int n) { if(Stack_IsReadOnlyCopy(s)) diff --git a/src/utils/stack.h b/src/utils/stack.h index 7da5e94..fffd1e0 100644 --- a/src/utils/stack.h +++ b/src/utils/stack.h @@ -8,6 +8,7 @@ _Bool Stack_Push(Stack *s, void *item); void Stack_Free(Stack *s); unsigned int Stack_Size(Stack *s); Stack *Stack_Copy(Stack *s, _Bool readonly); +void **Stack_TopRef(Stack *s, int n); unsigned int Stack_Capacity(Stack *s); _Bool Stack_IsReadOnlyCopy(Stack *s); #endif \ No newline at end of file