From 51d744ef2e9f2d06a49621b3270e26b4acbca979 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Tue, 7 Dec 2021 12:54:55 +0100 Subject: [PATCH] added a basic heap inspection utility to the debugger and modified the impl of the buffer object --- build.sh | 1 + samples/makegarbage.noja | 2 +- src/debug.c | 66 ++++++++ src/heap_reconst.c | 240 ++++++++++++++++++++++++++++ src/heap_reconst.h | 15 ++ src/objects/heap.c | 27 +++- src/objects/o_buffer.c | 330 +++++++++++++++++++++++++++++++-------- src/objects/objects.c | 2 + src/objects/objects.h | 3 + src/runtime/runtime.c | 37 ++++- src/runtime/runtime.h | 5 + 11 files changed, 653 insertions(+), 75 deletions(-) create mode 100644 src/heap_reconst.c create mode 100644 src/heap_reconst.h diff --git a/build.sh b/build.sh index 23564ae..82b6038 100755 --- a/build.sh +++ b/build.sh @@ -73,6 +73,7 @@ gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-object gcc src/main.c \ src/debug.c \ + src/heap_reconst.c \ temp/o_builtins.o \ temp/o_net_builtins.o \ temp/utils/hash.o \ diff --git a/samples/makegarbage.noja b/samples/makegarbage.noja index 88d35bc..0b43759 100644 --- a/samples/makegarbage.noja +++ b/samples/makegarbage.noja @@ -10,7 +10,7 @@ while i < n: i = i + 1; fun printPercent() - print('\r', 100.0 * i / n, '% '); + print(100.0 * i / n, '%\n'); printPercent(); } diff --git a/src/debug.c b/src/debug.c index 25ea157..2b494c7 100644 --- a/src/debug.c +++ b/src/debug.c @@ -7,6 +7,7 @@ #include #include "debug.h" #include "utils/defs.h" +#include "heap_reconst.h" #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" @@ -269,6 +270,7 @@ _Bool Debug_Callback(Runtime *runtime, void *userp) "continue .......... Run until a breakpoint or the end of the code is reached\n" "breakpoint ........ Add a breakpoint\n" "stack ............. Show the contents of the stack\n" + "heap .............. Show the contents of the heap\n" "disassembly ....... Show the current file's bytecode\n"); } else if(!strcmp(argv[1], "help")) @@ -363,6 +365,17 @@ _Bool Debug_Callback(Runtime *runtime, void *userp) " Description | Show the contents of the stack.\n" "\n"); } + else if(!strcmp(argv[1], "heap")) + { + fprintf(stderr, + "\n" + " Command | heap\n" + " | \n" + " Usage | > heap\n" + " | \n" + " Description | Show the contents of the heap.\n" + "\n"); + } else { fprintf(stdout, "Unknown command \"%s\".\n", argv[1]); @@ -483,6 +496,59 @@ _Bool Debug_Callback(Runtime *runtime, void *userp) fprintf(stderr, "\n"); } } + else if(!strcmp(argv[0], "heap")) + { + ReconstructedHeap *rh = reconstruct_heap(runtime); + + if(rh == NULL) + { + fprintf(stderr, "Something went wrong.\n"); + } + else + { + if(rh->count == 0) + { + printf("The heap is empty.\n"); + } + else + { + _Bool in_pool = 0; + + for(int i = 0; i < rh->count; i += 1) + { + MemoryChunk *chunk = rh->chunks + i; + + if(in_pool == 0 && chunk->in_pool == 1) + { + printf("-- Pool start --\n"); + in_pool = 1; + } + else if(in_pool == 1 && chunk->in_pool == 0) + { + printf("-- Pool end --\n"); + in_pool = 0; + } + + if(chunk->parent == NULL) + printf("%d bytes at %p (%s)\n", + chunk->size, + chunk->addr, + Object_GetName(chunk->addr)); + else + printf("%d bytes at %p, extension of %p (%s)\n", + chunk->size, + chunk->addr, + chunk->parent, + Object_GetName(chunk->parent)); + } + + if(in_pool) + printf("-- Pool end --\n"); + } + + free(rh); + } + } else if(!strcmp(argv[0], "quit")) { return 0; diff --git a/src/heap_reconst.c b/src/heap_reconst.c new file mode 100644 index 0000000..c95bfd1 --- /dev/null +++ b/src/heap_reconst.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include "heap_reconst.h" + +typedef struct { + Object *parent; + void *addr; + int size; +} Extension; + +typedef struct { + Object **objs; + Extension *exts; + int ext_size, ext_used; + int obj_size, obj_used; +} ReconstructionState; + +static _Bool append_ext(ReconstructionState *state, Extension ext) +{ + if(state->exts == NULL) + { + int n = 8; + + state->exts = malloc(n * sizeof(Extension)); + + if(state->exts == NULL) + return 0; + + state->ext_size = n; + state->ext_used = 0; + } + else if(state->ext_size == state->ext_used) + { + int factor = 2; + + Extension *temp = realloc(state->exts, factor * state->ext_size * sizeof(Extension)); + + if(temp == NULL) + return 0; + + state->exts = temp; + state->ext_size *= factor; + } + + state->exts[state->ext_used++] = ext; + return 1; +} + +static _Bool contains_ext(ReconstructionState *state, void *addr) +{ + for(int i = 0; i < state->ext_used; i += 1) + if(state->exts[i].addr == addr) + return 1; + return 0; +} + +static void exension_walker(void **addr, unsigned int size, void *userp) +{ + ReconstructionState *state = userp; + + if(contains_ext(state, *addr)) + return; + + if(!append_ext(state, (Extension) { .addr = *addr, .size = size, .parent = NULL })) + { + assert(0); + } +} + +static _Bool append_obj(ReconstructionState *state, Object *obj) +{ + if(state->objs == NULL) + { + int n = 8; + + state->objs = malloc(n * sizeof(Object*)); + + if(state->objs == NULL) + return 0; + + state->obj_size = n; + state->obj_used = 0; + } + else if(state->obj_size == state->obj_used) + { + int factor = 2; + + Object **temp = realloc(state->objs, factor * state->obj_size * sizeof(Extension)); + + if(temp == NULL) + return 0; + + state->objs = temp; + state->obj_size *= factor; + } + + state->objs[state->obj_used++] = obj; + return 1; +} + +static _Bool contains_obj(ReconstructionState *state, Object *obj) +{ + for(int i = 0; i < state->obj_used; i += 1) + if(state->objs[i] == obj) + return 1; + return 0; +} + +static void object_walker(Object **referer, void *userp) +{ + ReconstructionState *state = userp; + Object *obj = *referer; + + if(obj == NULL) + return; + + if(!contains_obj(state, obj)) + { + // Object wasn't already encountered. + // Store it at index `left`. + + if(!append_obj(state, obj)) + { + assert(0); + } + + // Walk over its extensions. + { + Object_WalkExtensions(obj, exension_walker, userp); + + if(state->ext_used > 0) + { + int i = state->ext_used-1; + while(i >= 0 && state->exts[i].parent == NULL) + { + state->exts[i].parent = obj; + i -= 1; + } + } + } + + // Walk over its children. + Object_WalkReferences(obj, object_walker, state); + } + else + { + // Object was already encountered and + // it's pointer is stored at index `index`. + } +} + +static int chunk_order(const void *p1, const void *p2) +{ + const MemoryChunk + *c1 = p1, + *c2 = p2; + + intptr_t l = (intptr_t) c1->addr; + intptr_t r = (intptr_t) c2->addr; + + return (l > r) - (l < r); +} + +ReconstructedHeap *reconstruct_heap(Runtime *runtime) +{ + ReconstructionState state; + state.exts = NULL; + state.ext_used = 0; + state.ext_size = 0; + state.objs = NULL; + state.obj_used = 0; + state.obj_size = 0; + + Object *builtins = Runtime_GetBuiltins(runtime); + if(builtins != NULL) + { + object_walker(&builtins, &state); + Object_WalkReferences(builtins, object_walker, &state); + } + + CallStackScanner *scanner = CallStackScanner_New(runtime); + assert(scanner != NULL); + + Object *locals, *closure; + while(CallStackScanner_Next(&scanner, &locals, &closure, NULL, NULL)) + { + if(locals != NULL) + { + object_walker(&locals, &state); + Object_WalkReferences(locals, object_walker, &state); + } + + if(closure != NULL) + { + object_walker(&closure, &state); + Object_WalkReferences(closure, object_walker, &state); + } + } + + ReconstructedHeap *recheap = malloc(sizeof(ReconstructedHeap) + (state.obj_used + state.ext_used) * sizeof(MemoryChunk)); + if(recheap == NULL) + { + free(state.objs); + free(state.exts); + return NULL; + } + + recheap->count = state.obj_used + state.ext_used; + + Heap *heap = Runtime_GetHeap(runtime); + char *heap_addr = Heap_GetPointer(heap); + unsigned int heap_size = Heap_GetSize(heap); + + for(int i = 0; i < state.obj_used; i += 1) + { + recheap->chunks[i] = (MemoryChunk) { + .in_pool = (heap_addr <= (char*) state.objs[i] && (char*) state.objs[i] < heap_addr + heap_size), + .parent = NULL, + .addr = state.objs[i], + .size = state.objs[i]->type->size, + }; + } + + for(int i = 0; i < state.ext_used; i += 1) + { + recheap->chunks[state.obj_used + i] = (MemoryChunk) { + .in_pool = (heap_addr <= (char*) state.exts[i].addr && (char*) state.exts[i].addr < heap_addr + heap_size), + .parent = state.exts[i].parent, + .addr = state.exts[i].addr, + .size = state.exts[i].size, + }; + } + + qsort(recheap->chunks, recheap->count, sizeof(MemoryChunk), chunk_order); + + free(state.objs); + free(state.exts); + return recheap; +} \ No newline at end of file diff --git a/src/heap_reconst.h b/src/heap_reconst.h new file mode 100644 index 0000000..c9a2256 --- /dev/null +++ b/src/heap_reconst.h @@ -0,0 +1,15 @@ +#include "runtime/runtime.h" + +typedef struct { + _Bool in_pool; + Object *parent; + void *addr; + int size; +} MemoryChunk; + +typedef struct { + int count; + MemoryChunk chunks[]; +} ReconstructedHeap; + +ReconstructedHeap *reconstruct_heap(Runtime *runtime); diff --git a/src/objects/heap.c b/src/objects/heap.c index a5c7794..8e66abe 100644 --- a/src/objects/heap.c +++ b/src/objects/heap.c @@ -20,6 +20,7 @@ typedef struct { } PendingDestruct; struct xHeap { + int objcount; int size; int used; int total; @@ -30,7 +31,7 @@ struct xHeap { _Bool collecting; _Bool collection_failed; - int moved_with_destructors; + int movedcount; void *old_body; int old_used; int old_total; @@ -48,6 +49,7 @@ Heap *Heap_New(int size) if(heap == NULL) return NULL; + heap->objcount = 0; heap->total = 0; heap->size = size; heap->used = 0; @@ -105,6 +107,21 @@ void Heap_Free(Heap *heap) free(heap); } +void *Heap_GetPointer(Heap *heap) +{ + return heap->body; +} + +unsigned int Heap_GetSize(Heap *heap) +{ + return heap->size; +} + +unsigned int Heap_GetObjectCount(Heap *heap) +{ + return heap->objcount; +} + float Heap_GetUsagePercentage(Heap *heap) { return 100.0 * heap->total / heap->size; @@ -176,6 +193,8 @@ void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err) if(requires_destruct) heap->pend[heap->pend_used++] = (PendingDestruct) { .object = obj, .destructor = obj->type->free }; + heap->objcount += 1; + return (Object*) addr; } @@ -246,7 +265,7 @@ _Bool Heap_StartCollection(Heap *heap, Error *error) heap->oflow = NULL; heap->collecting = 1; heap->collection_failed = 0; - heap->moved_with_destructors = 0; + heap->movedcount = 0; heap->error = error; return 1; } @@ -311,6 +330,7 @@ _Bool Heap_StopCollection(Heap *heap) free(heap->old_body); heap->collecting = 0; + heap->objcount = heap->movedcount; return 1; } @@ -397,8 +417,7 @@ void Heap_CollectReference(Object **referer, void *userp) ((MovedObject*) old_location)->new_location = new_location; } - if(type->free != NULL) - heap->moved_with_destructors += 1; + heap->movedcount += 1; } // Collect the reference to the type. diff --git a/src/objects/o_buffer.c b/src/objects/o_buffer.c index 6942dd9..ece8001 100644 --- a/src/objects/o_buffer.c +++ b/src/objects/o_buffer.c @@ -1,35 +1,57 @@ +#include #include #include #include "../utils/defs.h" #include "objects.h" typedef struct { - int size, - refs; - unsigned char data[]; -} BufferBody; - -typedef struct { - Object base; - BufferBody *body; - int offset, length; + Object base; + int size; + unsigned char *body; } BufferObject; -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); +typedef struct { + Object base; + BufferObject *sliced; + int offset, + length; +} BufferSliceObject; + +static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *err); +static _Bool buffer_insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); +static int buffer_count(Object *self); +static void buffer_print(Object *obj, FILE *fp); +static _Bool buffer_free(Object *self, Error *error); + +static Object *slice_select(Object *self, Object *key, Heap *heap, Error *err); +static _Bool slice_insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); +static int slice_count(Object *self); +static void slice_print(Object *obj, FILE *fp); + static TypeObject t_buffer = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "buffer", .size = sizeof (BufferObject), - .select = select, - .insert = insert, - .count = count, - .print = print, + .select = buffer_select, + .insert = buffer_insert, + .count = buffer_count, + .print = buffer_print, + .free = buffer_free, }; +static TypeObject t_buffer_slice = { + .base = (Object) { .type = &t_type, .flags = Object_STATIC }, + .name = "buffer slice", + .size = sizeof (BufferSliceObject), + .select = slice_select, + .insert = slice_insert, + .count = slice_count, + .print = slice_print, +}; + +#define THRESHOLD 128 + Object *Object_NewBuffer(int size, Heap *heap, Error *error) { assert(size >= 0); @@ -42,73 +64,147 @@ Object *Object_NewBuffer(int size, Heap *heap, Error *error) if(obj == NULL) return NULL; - obj->offset = 0; - obj->length = size; - obj->body = Heap_RawMalloc(heap, sizeof(BufferBody) + sizeof(unsigned char) * size, error); + unsigned char *body; - if(obj->body == NULL) - return NULL; + if(size > THRESHOLD) + { + body = malloc(sizeof(unsigned char) * size); - obj->body->size = size; - obj->body->refs = 1; - memset(obj->body->data, 0, size); + if(body == NULL) + { + Error_Report(error, 1, "No memory"); + return NULL; + } + } + else + { + body = Heap_RawMalloc(heap, sizeof(unsigned char) * size, error); + + if(body == NULL) + return NULL; + } + + obj->size = size; + obj->body = body; + memset(obj->body, 0, size); } return (Object*) obj; } +static _Bool buffer_free(Object *self, Error *error) +{ + (void) error; + + BufferObject *buffer = (BufferObject*) self; + + if(buffer->size > THRESHOLD) + free(buffer->body); + return 1; +} + Object *Object_SliceBuffer(Object *buffer, int offset, int length, Heap *heap, Error *error) { - if(buffer->type != &t_buffer) + if(buffer->type != &t_buffer && buffer->type != &t_buffer_slice) { - Error_Report(error, 0, "Not a buffer"); + Error_Report(error, 0, "Not a buffer or a buffer slice"); return NULL; } - BufferObject *original = (BufferObject*) buffer; - BufferObject *slice = (BufferObject*) Heap_Malloc(heap, &t_buffer, error); + BufferSliceObject *slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error); - if(offset < 0 || offset >= original->length) + if(slice == NULL) + return NULL; + + if(buffer->type == &t_buffer) { - Error_Report(error, 0, "offset out of range"); - return NULL; + BufferObject *original = (BufferObject*) buffer; + + if(offset < 0 || offset >= original->size) + { + Error_Report(error, 0, "offset out of range"); + return NULL; + } + + if(length < 0 || length >= original->size) + { + Error_Report(error, 0, "length out of range"); + return NULL; + } + + if(offset + length > original->size) + { + Error_Report(error, 0, "slice out of range"); + return NULL; + } + + slice->sliced = original; + slice->offset = offset; + slice->length = length; + } + else + { + assert(buffer->type == &t_buffer_slice); + + BufferSliceObject *original = (BufferSliceObject*) buffer; + + if(offset < 0 || offset >= original->length) + { + Error_Report(error, 0, "offset out of range"); + return NULL; + } + + if(length < 0 || length >= original->length) + { + Error_Report(error, 0, "length out of range"); + return NULL; + } + + if(offset + length > original->length) + { + Error_Report(error, 0, "slice out of range"); + return NULL; + } + + slice->sliced = original->sliced; + slice->offset = original->offset + offset; + slice->length = length; } - if(length < 0 || length >= original->length) - { - Error_Report(error, 0, "length out of range"); - return NULL; - } - - if(offset + length > original->length) - { - Error_Report(error, 0, "slice out of range"); - return NULL; - } - - slice->offset = original->offset + offset; - slice->length = length; - slice->body = original->body; - slice->body->refs += 1; return (Object*) slice; } void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error) { - if(obj->type != &t_buffer) + if(obj->type != &t_buffer && obj->type != &t_buffer_slice) { - Error_Report(error, 0, "Not a buffer"); + Error_Report(error, 0, "Not a buffer or a buffer slice"); return NULL; } - BufferObject *buf = (BufferObject*) obj; + if(obj->type == &t_buffer) + { + BufferObject *buffer = (BufferObject*) obj; + + if(size) + *size = buffer->size; - if(size) - *size = buf->length; - return buf->body->data + buf->offset; + return buffer->body; + } + else + { + assert(obj->type == &t_buffer_slice); + + BufferSliceObject *slice = (BufferSliceObject*) obj; + + if(size) + *size = slice->length; + + return slice->sliced->body + slice->offset; + } } -static Object *select(Object *self, Object *key, Heap *heap, Error *error) +static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error) { assert(self != NULL); assert(self->type == &t_buffer); @@ -127,18 +223,48 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) BufferObject *buffer = (BufferObject*) self; - if(idx < 0 || idx >= buffer->length) + if(idx < 0 || idx >= buffer->size) { Error_Report(error, 0, "Out of range index"); return NULL; } - unsigned char byte = buffer->body->data[buffer->offset + idx]; + unsigned char byte = buffer->body[idx]; return Object_FromInt(byte, heap, error); } -static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *error) +static Object *slice_select(Object *self, Object *key, Heap *heap, Error *error) +{ + assert(self != NULL); + assert(self->type == &t_buffer_slice); + assert(key != NULL); + assert(heap != NULL); + assert(error != NULL); + + if(!Object_IsInt(key)) + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } + + int idx = Object_ToInt(key, error); + assert(error->occurred == 0); + + BufferSliceObject *slice = (BufferSliceObject*) self; + + if(idx < 0 || idx >= slice->length) + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } + + unsigned char byte = slice->sliced->body[slice->offset + idx]; + + return Object_FromInt(byte, heap, error); +} + +static _Bool buffer_insert(Object *self, Object *key, Object *val, Heap *heap, Error *error) { assert(error != NULL); assert(key != NULL); @@ -158,39 +284,95 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e int idx = Object_ToInt(key, error); assert(error->occurred == 0); - if(idx < 0 || idx >= buffer->length) + if(idx < 0 || idx >= buffer->size) { Error_Report(error, 0, "Out of range index"); return NULL; } - unsigned char byte = Object_ToInt(val, error); + long long int qword = Object_ToInt(val, error); + + if(qword > 255 || qword < 0) + { + Error_Report(error, 0, "Not in range [0, 255]"); + return NULL; + } + + unsigned char byte = qword & 0xff; if(error->occurred == 1) return 0; - buffer->body->data[buffer->offset + idx] = byte; + buffer->body[idx] = byte; return 1; } -static int count(Object *self) +static _Bool slice_insert(Object *self, Object *key, Object *val, Heap *heap, Error *error) { - BufferObject *buffer = (BufferObject*) self; + assert(error != NULL); + assert(key != NULL); + assert(val != NULL); + assert(heap != NULL); + assert(self != NULL); + assert(self->type == &t_buffer_slice); - return buffer->length; + BufferSliceObject *slice = (BufferSliceObject*) self; + + if(!Object_IsInt(key)) + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } + + int idx = Object_ToInt(key, error); + assert(error->occurred == 0); + + if(idx < 0 || idx >= slice->length) + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } + + long long int qword = Object_ToInt(val, error); + + if(qword > 255 || qword < 0) + { + Error_Report(error, 0, "Not in range [0, 255]"); + return NULL; + } + + unsigned char byte = qword & 0xff; + + if(error->occurred == 1) + return 0; + + slice->sliced->body[slice->offset + idx] = byte; + return 1; } -static void print(Object *self, FILE *fp) +static int buffer_count(Object *self) { BufferObject *buffer = (BufferObject*) self; + return buffer->size; +} + +static int slice_count(Object *self) +{ + BufferSliceObject *slice = (BufferSliceObject*) self; + + return slice->length; +} + +static void print_bytes(FILE *fp, unsigned char *addr, int size) +{ fprintf(fp, "["); - for(int i = 0; i < buffer->length; i += 1) + for(int i = 0; i < size; i += 1) { unsigned char byte, low, high; - byte = buffer->body->data[buffer->offset + i]; + byte = addr[i]; low = byte & 0xf; high = byte >> 4; @@ -204,8 +386,20 @@ static void print(Object *self, FILE *fp) fprintf(fp, "%c%c", c1, c2); - if(i+1 < buffer->length) + if(i+1 < size) fprintf(fp, ", "); } fprintf(fp, "]"); +} + +static void buffer_print(Object *self, FILE *fp) +{ + BufferObject *buffer = (BufferObject*) self; + print_bytes(fp, buffer->body, buffer->size); +} + +static void slice_print(Object *self, FILE *fp) +{ + BufferSliceObject *slice = (BufferSliceObject*) self; + print_bytes(fp, slice->sliced->body + slice->offset, slice->length); } \ No newline at end of file diff --git a/src/objects/objects.c b/src/objects/objects.c index 3097e1b..bac1fee 100644 --- a/src/objects/objects.c +++ b/src/objects/objects.c @@ -364,12 +364,14 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error) void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp) { + assert(parent != NULL); 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) { + assert(parent != NULL); 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 ca15a09..a79455a 100644 --- a/src/objects/objects.h +++ b/src/objects/objects.h @@ -81,6 +81,9 @@ _Bool Heap_StartCollection(Heap *heap, Error *error); _Bool Heap_StopCollection(Heap *heap); void Heap_CollectReference(Object **referer, void *heap); float Heap_GetUsagePercentage(Heap *heap); +unsigned int Heap_GetObjectCount(Heap *heap); +void *Heap_GetPointer(Heap *heap); +unsigned int Heap_GetSize(Heap *heap); const TypeObject* Object_GetType(const Object *obj); const char* Object_GetName(const Object *obj); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 6dddcd3..c9b6a7e 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -6,8 +6,8 @@ #define MAX_FRAME_STACK 16 #define MAX_FRAMES 16 -typedef struct Frame Frame; -struct Frame { +typedef struct xFrame Frame; +struct xFrame { Frame *prev; Object *locals; Object *closure; @@ -25,6 +25,39 @@ struct xRuntime { Heap *heap; }; +CallStackScanner *CallStackScanner_New(Runtime *runtime) +{ + return runtime->frame; +} + +_Bool CallStackScanner_Next(CallStackScanner **scanner, Object **locals, Object **closure, Executable **exe, int *index) +{ + assert(scanner != NULL); + + if(*scanner == NULL) + return 0; + + { + Frame *frame = *scanner; + + if(exe) + *exe = frame->exe; + + if(index) + *index = frame->index; + + if(locals) + *locals = frame->locals; + + if(closure) + *closure = frame->closure; + } + + (*scanner) = ((Frame*) (*scanner))->prev; + return 1; +} + + Stack *Runtime_GetStack(Runtime *runtime) { return Stack_Copy(runtime->stack, 1); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index c617456..76d4ac8 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -7,6 +7,7 @@ #include "../common/executable.h" typedef struct xRuntime Runtime; +typedef void CallStackScanner; Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*)); void Runtime_Free(Runtime *runtime); _Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n); @@ -23,6 +24,10 @@ Snapshot *Snapshot_New(Runtime *runtime); void Snapshot_Free(Snapshot *snapshot); void Snapshot_Print(Snapshot *snapshot, FILE *fp); +CallStackScanner *CallStackScanner_New(Runtime *runtime); +_Bool CallStackScanner_Next(CallStackScanner **scanner, Object **locals, Object **closure, Executable **exe, int *index); + + Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc); Object* Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);