added garbage collector draft
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
i = 0;
|
||||||
|
n = 10000000;
|
||||||
|
|
||||||
|
while i < n:
|
||||||
|
{
|
||||||
|
1 + 1 * 1;
|
||||||
|
i = i + 1;
|
||||||
|
print('\r', 100.0 * i / n, '% ');
|
||||||
|
}
|
||||||
@@ -237,6 +237,8 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
Object *result = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0);
|
Object *result = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0);
|
||||||
|
|
||||||
|
// NOTE: The `builtins` pointer is invalidated now.
|
||||||
|
|
||||||
if(result == NULL)
|
if(result == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "RUNTIME ERROR: %s.\n", error.base.message);
|
fprintf(stderr, "RUNTIME ERROR: %s.\n", error.base.message);
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ typedef struct {
|
|||||||
Runtime *runtime;
|
Runtime *runtime;
|
||||||
} BuiltinsMapOjbect;
|
} BuiltinsMapOjbect;
|
||||||
|
|
||||||
static const Type t_builtins_map = {
|
static TypeObject t_builtins_map = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "builtins map",
|
.name = "builtins map",
|
||||||
.size = sizeof(BuiltinsMapOjbect),
|
.size = sizeof(BuiltinsMapOjbect),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ typedef struct {
|
|||||||
Runtime *runtime;
|
Runtime *runtime;
|
||||||
} NetworkBuiltinsMapOjbect;
|
} NetworkBuiltinsMapOjbect;
|
||||||
|
|
||||||
static const Type t_builtins_map = {
|
static TypeObject t_builtins_map = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "network builtins map",
|
.name = "network builtins map",
|
||||||
.size = sizeof(NetworkBuiltinsMapOjbect),
|
.size = sizeof(NetworkBuiltinsMapOjbect),
|
||||||
|
|||||||
+169
-1
@@ -17,8 +17,17 @@ struct OflowAlloc {
|
|||||||
struct xHeap {
|
struct xHeap {
|
||||||
int size;
|
int size;
|
||||||
int used;
|
int used;
|
||||||
|
int total;
|
||||||
void *body;
|
void *body;
|
||||||
OflowAlloc *oflow;
|
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)
|
Heap *Heap_New(int size)
|
||||||
@@ -31,10 +40,12 @@ Heap *Heap_New(int size)
|
|||||||
if(heap == NULL)
|
if(heap == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
heap->total = 0;
|
||||||
heap->size = size;
|
heap->size = size;
|
||||||
heap->used = 0;
|
heap->used = 0;
|
||||||
heap->body = malloc(size);
|
heap->body = malloc(size);
|
||||||
heap->oflow = 0;
|
heap->oflow = 0;
|
||||||
|
heap->collecting = 0;
|
||||||
|
|
||||||
if(heap->body == NULL)
|
if(heap->body == NULL)
|
||||||
{
|
{
|
||||||
@@ -67,7 +78,12 @@ void Heap_Free(Heap *heap)
|
|||||||
free(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);
|
void *addr = Heap_RawMalloc(heap, type->size, err);
|
||||||
|
|
||||||
@@ -107,14 +123,20 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
|
|||||||
heap->oflow = oflow;
|
heap->oflow = oflow;
|
||||||
|
|
||||||
addr = oflow->body;
|
addr = oflow->body;
|
||||||
|
|
||||||
|
heap->total += size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int prev_used = heap->used;
|
||||||
|
|
||||||
if(heap->used & 7)
|
if(heap->used & 7)
|
||||||
heap->used = (heap->used & ~7) + 8;
|
heap->used = (heap->used & ~7) + 8;
|
||||||
|
|
||||||
addr = heap->body + heap->used;
|
addr = heap->body + heap->used;
|
||||||
|
|
||||||
heap->used += size;
|
heap->used += size;
|
||||||
|
heap->total += heap->used - prev_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(((intptr_t) addr) % 8 == 0);
|
assert(((intptr_t) addr) % 8 == 0);
|
||||||
@@ -125,3 +147,149 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
|
|||||||
|
|
||||||
return addr;
|
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);
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
static _Bool to_bool(Object *obj, Error *err);
|
static _Bool to_bool(Object *obj, Error *err);
|
||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
|
|
||||||
static const Type t_bool = {
|
static TypeObject t_bool = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "bool",
|
.name = "bool",
|
||||||
.size = sizeof (Object),
|
.size = sizeof (Object),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error
|
|||||||
static int count(Object *self);
|
static int count(Object *self);
|
||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
|
|
||||||
static const Type t_buffer = {
|
static TypeObject t_buffer = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "buffer",
|
.name = "buffer",
|
||||||
.size = sizeof (BufferObject),
|
.size = sizeof (BufferObject),
|
||||||
|
|||||||
+11
-1
@@ -9,13 +9,15 @@ struct ClosureObject {
|
|||||||
Object *vars;
|
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 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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "closure",
|
.name = "closure",
|
||||||
.size = sizeof(ClosureObject),
|
.size = sizeof(ClosureObject),
|
||||||
.select = select,
|
.select = select,
|
||||||
|
.walk = walk,
|
||||||
};
|
};
|
||||||
|
|
||||||
Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error)
|
Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error)
|
||||||
@@ -55,3 +57,11 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err)
|
|||||||
|
|
||||||
return selected;
|
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);
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ typedef struct {
|
|||||||
double val;
|
double val;
|
||||||
} FloatObject;
|
} FloatObject;
|
||||||
|
|
||||||
static const Type t_float = {
|
static TypeObject t_float = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "float",
|
.name = "float",
|
||||||
.size = sizeof (FloatObject),
|
.size = sizeof (FloatObject),
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ typedef struct {
|
|||||||
long long int val;
|
long long int val;
|
||||||
} IntObject;
|
} IntObject;
|
||||||
|
|
||||||
static const Type t_int = {
|
static TypeObject t_int = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "int",
|
.name = "int",
|
||||||
.size = sizeof (IntObject),
|
.size = sizeof (IntObject),
|
||||||
|
|||||||
+20
-1
@@ -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 _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
||||||
static int count(Object *self);
|
static int count(Object *self);
|
||||||
static void print(Object *obj, FILE *fp);
|
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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "list",
|
.name = "list",
|
||||||
.size = sizeof (ListObject),
|
.size = sizeof (ListObject),
|
||||||
@@ -21,6 +23,8 @@ static const Type t_list = {
|
|||||||
.insert = insert,
|
.insert = insert,
|
||||||
.count = count,
|
.count = count,
|
||||||
.print = print,
|
.print = print,
|
||||||
|
.walk = walk,
|
||||||
|
.walkexts = walkexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int calc_capacity(int mapper_size)
|
static inline int calc_capacity(int mapper_size)
|
||||||
@@ -53,6 +57,21 @@ Object *Object_NewList(int capacity, Heap *heap, Error *error)
|
|||||||
return (Object*) obj;
|
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)
|
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|||||||
+25
-1
@@ -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 _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
||||||
static int count(Object *self);
|
static int count(Object *self);
|
||||||
static void print(Object *self, FILE *fp);
|
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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "map",
|
.name = "map",
|
||||||
.size = sizeof (MapObject),
|
.size = sizeof (MapObject),
|
||||||
@@ -23,6 +25,8 @@ static const Type t_map = {
|
|||||||
.insert = insert,
|
.insert = insert,
|
||||||
.count = count,
|
.count = count,
|
||||||
.print = print,
|
.print = print,
|
||||||
|
.walk = walk,
|
||||||
|
.walkexts = walkexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int calc_capacity(int mapper_size)
|
static inline int calc_capacity(int mapper_size)
|
||||||
@@ -68,6 +72,26 @@ Object *Object_NewMap(int num, Heap *heap, Error *error)
|
|||||||
return (Object*) obj;
|
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)
|
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
static _Bool op_eql(Object *self, Object *other);
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
|
|
||||||
static const Type t_none = {
|
static TypeObject t_none = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "none",
|
.name = "none",
|
||||||
.size = sizeof (Object),
|
.size = sizeof (Object),
|
||||||
|
|||||||
+10
-1
@@ -16,8 +16,9 @@ static Object *copy(Object *self, Heap *heap, Error *err);
|
|||||||
static void print(Object *obj, FILE *fp);
|
static void print(Object *obj, FILE *fp);
|
||||||
static char *to_string(Object *self, int *size, Heap *heap, Error *err);
|
static char *to_string(Object *self, int *size, Heap *heap, Error *err);
|
||||||
static _Bool op_eql(Object *self, Object *other);
|
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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "string",
|
.name = "string",
|
||||||
.atomic = ATMTP_STRING,
|
.atomic = ATMTP_STRING,
|
||||||
@@ -28,6 +29,7 @@ static const Type t_string = {
|
|||||||
.print = print,
|
.print = print,
|
||||||
.to_string = to_string,
|
.to_string = to_string,
|
||||||
.op_eql = op_eql,
|
.op_eql = op_eql,
|
||||||
|
.walkexts = walkexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *to_string(Object *self, int *size, Heap *heap, Error *err)
|
static char *to_string(Object *self, int *size, Heap *heap, Error *err)
|
||||||
@@ -128,3 +130,10 @@ static void print(Object *obj, FILE *fp)
|
|||||||
|
|
||||||
fprintf(fp, "%.*s", str->size, str->body);
|
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);
|
||||||
|
}
|
||||||
+32
-20
@@ -2,17 +2,17 @@
|
|||||||
#include "../utils/defs.h"
|
#include "../utils/defs.h"
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
const Type t_type = {
|
TypeObject t_type = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "type",
|
.name = "type",
|
||||||
.size = sizeof (Type),
|
.size = sizeof (TypeObject),
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *Object_GetName(const Object *obj)
|
const char *Object_GetName(const Object *obj)
|
||||||
{
|
{
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
const char *name = type->name;
|
const char *name = type->name;
|
||||||
@@ -21,7 +21,7 @@ const char *Object_GetName(const Object *obj)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *Object_GetType(const Object *obj)
|
const TypeObject *Object_GetType(const Object *obj)
|
||||||
{
|
{
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
assert(obj->type != NULL);
|
assert(obj->type != NULL);
|
||||||
@@ -33,7 +33,7 @@ unsigned int Object_GetSize(const Object *obj, Error *err)
|
|||||||
assert(err != NULL);
|
assert(err != NULL);
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
return type->size;
|
return type->size;
|
||||||
@@ -44,7 +44,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err)
|
|||||||
assert(err != NULL);
|
assert(err != NULL);
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->deepsize == NULL)
|
if(type->deepsize == NULL)
|
||||||
@@ -60,7 +60,7 @@ int Object_Hash(Object *obj, Error *err)
|
|||||||
{
|
{
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type != NULL);
|
assert(type != NULL);
|
||||||
|
|
||||||
if(type->hash == NULL)
|
if(type->hash == NULL)
|
||||||
@@ -77,7 +77,7 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
|
|||||||
assert(err != NULL);
|
assert(err != NULL);
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type != NULL);
|
assert(type != NULL);
|
||||||
|
|
||||||
if(type->copy == 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(err);
|
||||||
assert(obj);
|
assert(obj);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->call == NULL)
|
if(type->call == NULL)
|
||||||
@@ -110,7 +110,7 @@ void Object_Print(Object *obj, FILE *fp)
|
|||||||
{
|
{
|
||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->print == NULL)
|
if(type->print == NULL)
|
||||||
@@ -125,7 +125,7 @@ Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
assert(key);
|
assert(key);
|
||||||
assert(coll);
|
assert(coll);
|
||||||
|
|
||||||
const Type *type = Object_GetType(coll);
|
const TypeObject *type = Object_GetType(coll);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->select == NULL)
|
if(type->select == NULL)
|
||||||
@@ -143,7 +143,7 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
assert(key);
|
assert(key);
|
||||||
assert(coll);
|
assert(coll);
|
||||||
|
|
||||||
const Type *type = Object_GetType(coll);
|
const TypeObject *type = Object_GetType(coll);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->delete == NULL)
|
if(type->delete == NULL)
|
||||||
@@ -161,7 +161,7 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
assert(key);
|
assert(key);
|
||||||
assert(coll);
|
assert(coll);
|
||||||
|
|
||||||
const Type *type = Object_GetType(coll);
|
const TypeObject *type = Object_GetType(coll);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->insert == NULL)
|
if(type->insert == NULL)
|
||||||
@@ -178,7 +178,7 @@ int Object_Count(Object *coll, Error *err)
|
|||||||
assert(err);
|
assert(err);
|
||||||
assert(coll);
|
assert(coll);
|
||||||
|
|
||||||
const Type *type = Object_GetType(coll);
|
const TypeObject *type = Object_GetType(coll);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->count == NULL)
|
if(type->count == NULL)
|
||||||
@@ -195,7 +195,7 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err)
|
|||||||
assert(err);
|
assert(err);
|
||||||
assert(iter);
|
assert(iter);
|
||||||
|
|
||||||
const Type *type = Object_GetType(iter);
|
const TypeObject *type = Object_GetType(iter);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->next == NULL)
|
if(type->next == NULL)
|
||||||
@@ -212,7 +212,7 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err)
|
|||||||
assert(err);
|
assert(err);
|
||||||
assert(iter);
|
assert(iter);
|
||||||
|
|
||||||
const Type *type = Object_GetType(iter);
|
const TypeObject *type = Object_GetType(iter);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->prev == NULL)
|
if(type->prev == NULL)
|
||||||
@@ -263,7 +263,7 @@ long long int Object_ToInt(Object *obj, Error *err)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_int == NULL)
|
if(type->to_int == NULL)
|
||||||
@@ -286,7 +286,7 @@ _Bool Object_ToBool(Object *obj, Error *err)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_bool == NULL)
|
if(type->to_bool == NULL)
|
||||||
@@ -309,7 +309,7 @@ double Object_ToFloat(Object *obj, Error *err)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_float == NULL)
|
if(type->to_float == NULL)
|
||||||
@@ -332,7 +332,7 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_string == NULL)
|
if(type->to_string == NULL)
|
||||||
@@ -361,3 +361,15 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
|
|||||||
|
|
||||||
return obj1->type->op_eql(obj1, obj2);
|
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);
|
||||||
|
}
|
||||||
+22
-6
@@ -4,15 +4,20 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../utils/error.h"
|
#include "../utils/error.h"
|
||||||
|
|
||||||
typedef struct Type Type;
|
typedef struct TypeObject TypeObject;
|
||||||
typedef struct Object Object;
|
typedef struct Object Object;
|
||||||
typedef struct xHeap Heap;
|
typedef struct xHeap Heap;
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
const Type *type;
|
TypeObject *type;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Object base;
|
||||||
|
Object *new_location;
|
||||||
|
} MovedObject;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ATMTP_NOTATOMIC = 0,
|
ATMTP_NOTATOMIC = 0,
|
||||||
ATMTP_INT,
|
ATMTP_INT,
|
||||||
@@ -21,7 +26,7 @@ typedef enum {
|
|||||||
ATMTP_STRING,
|
ATMTP_STRING,
|
||||||
} AtomicType;
|
} AtomicType;
|
||||||
|
|
||||||
struct Type {
|
struct TypeObject {
|
||||||
|
|
||||||
Object base;
|
Object base;
|
||||||
|
|
||||||
@@ -57,18 +62,27 @@ struct Type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_Bool (*op_eql)(Object *self, Object *other);
|
_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 {
|
enum {
|
||||||
Object_STATIC = 1,
|
Object_STATIC = 1,
|
||||||
|
Object_MOVED = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Heap* Heap_New(int size);
|
Heap* Heap_New(int size);
|
||||||
void Heap_Free(Heap *heap);
|
void Heap_Free(Heap *heap);
|
||||||
void* Heap_Malloc (Heap *heap, const Type *type, Error *err);
|
void* Heap_Malloc (Heap *heap, TypeObject *type, Error *err);
|
||||||
void* Heap_RawMalloc(Heap *heap, int size, 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);
|
const char* Object_GetName(const Object *obj);
|
||||||
unsigned int Object_GetSize(const Object *obj, Error *err);
|
unsigned int Object_GetSize(const Object *obj, Error *err);
|
||||||
unsigned int Object_GetDeepSize(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);
|
int Object_Count (Object *coll, Error *err);
|
||||||
Object* Object_Next (Object *iter, Heap *heap, Error *err);
|
Object* Object_Next (Object *iter, Heap *heap, Error *err);
|
||||||
Object* Object_Prev (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_NewMap(int num, Heap *heap, Error *error);
|
||||||
Object* Object_NewList(int capacity, 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);
|
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error);
|
||||||
|
|
||||||
extern const Type t_type;
|
extern TypeObject t_type;
|
||||||
#endif
|
#endif
|
||||||
@@ -13,14 +13,22 @@ typedef struct {
|
|||||||
} FunctionObject;
|
} FunctionObject;
|
||||||
|
|
||||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
|
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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "function",
|
.name = "function",
|
||||||
.size = sizeof (FunctionObject),
|
.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)
|
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ typedef struct {
|
|||||||
|
|
||||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
|
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 },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = "native function",
|
.name = "native function",
|
||||||
.size = sizeof (NativeFunctionObject),
|
.size = sizeof (NativeFunctionObject),
|
||||||
|
|||||||
+43
-1
@@ -1032,6 +1032,33 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
return 1;
|
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)
|
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc)
|
||||||
{
|
{
|
||||||
assert(runtime != NULL);
|
assert(runtime != NULL);
|
||||||
@@ -1086,14 +1113,29 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
|
|||||||
Error_Report(error, 0, "Forced abortion");
|
Error_Report(error, 0, "Forced abortion");
|
||||||
else
|
else
|
||||||
while(step(runtime, error))
|
while(step(runtime, error))
|
||||||
|
{
|
||||||
if(!runtime->callback_addr(runtime, runtime->callback_userp))
|
if(!runtime->callback_addr(runtime, runtime->callback_userp))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Forced abortion");
|
Error_Report(error, 0, "Forced abortion");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap));
|
||||||
|
|
||||||
|
if(Heap_GetUsagePercentage(runtime->heap) > 100)
|
||||||
|
if(!collect(runtime, error))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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.
|
// This is what the function will return.
|
||||||
Object *result = NULL;
|
Object *result = NULL;
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ void *Stack_Top(Stack *s, int n)
|
|||||||
return s->body[s->used + n - 1];
|
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)
|
_Bool Stack_Pop(Stack *s, unsigned int n)
|
||||||
{
|
{
|
||||||
if(Stack_IsReadOnlyCopy(s))
|
if(Stack_IsReadOnlyCopy(s))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ _Bool Stack_Push(Stack *s, void *item);
|
|||||||
void Stack_Free(Stack *s);
|
void Stack_Free(Stack *s);
|
||||||
unsigned int Stack_Size(Stack *s);
|
unsigned int Stack_Size(Stack *s);
|
||||||
Stack *Stack_Copy(Stack *s, _Bool readonly);
|
Stack *Stack_Copy(Stack *s, _Bool readonly);
|
||||||
|
void **Stack_TopRef(Stack *s, int n);
|
||||||
unsigned int Stack_Capacity(Stack *s);
|
unsigned int Stack_Capacity(Stack *s);
|
||||||
_Bool Stack_IsReadOnlyCopy(Stack *s);
|
_Bool Stack_IsReadOnlyCopy(Stack *s);
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user