added a basic heap inspection utility to the debugger and modified the impl of the buffer object

This commit is contained in:
Francesco Cozzuto
2021-12-07 12:54:55 +01:00
parent f751cbcbd5
commit 51d744ef2e
11 changed files with 653 additions and 75 deletions
+1
View File
@@ -73,6 +73,7 @@ gcc tests/src/test-objects.c -o build/test-objects $FLAGS -Lbuild/ -lnoja-object
gcc src/main.c \ gcc src/main.c \
src/debug.c \ src/debug.c \
src/heap_reconst.c \
temp/o_builtins.o \ temp/o_builtins.o \
temp/o_net_builtins.o \ temp/o_net_builtins.o \
temp/utils/hash.o \ temp/utils/hash.o \
+1 -1
View File
@@ -10,7 +10,7 @@ while i < n:
i = i + 1; i = i + 1;
fun printPercent() fun printPercent()
print('\r', 100.0 * i / n, '% '); print(100.0 * i / n, '%\n');
printPercent(); printPercent();
} }
+66
View File
@@ -7,6 +7,7 @@
#include <ctype.h> #include <ctype.h>
#include "debug.h" #include "debug.h"
#include "utils/defs.h" #include "utils/defs.h"
#include "heap_reconst.h"
#define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m" #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" "continue .......... Run until a breakpoint or the end of the code is reached\n"
"breakpoint ........ Add a breakpoint\n" "breakpoint ........ Add a breakpoint\n"
"stack ............. Show the contents of the stack\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"); "disassembly ....... Show the current file's bytecode\n");
} }
else if(!strcmp(argv[1], "help")) 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" " Description | Show the contents of the stack.\n"
"\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 else
{ {
fprintf(stdout, "Unknown command \"%s\".\n", argv[1]); fprintf(stdout, "Unknown command \"%s\".\n", argv[1]);
@@ -483,6 +496,59 @@ _Bool Debug_Callback(Runtime *runtime, void *userp)
fprintf(stderr, "\n"); 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")) else if(!strcmp(argv[0], "quit"))
{ {
return 0; return 0;
+240
View File
@@ -0,0 +1,240 @@
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
#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;
}
+15
View File
@@ -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);
+23 -4
View File
@@ -20,6 +20,7 @@ typedef struct {
} PendingDestruct; } PendingDestruct;
struct xHeap { struct xHeap {
int objcount;
int size; int size;
int used; int used;
int total; int total;
@@ -30,7 +31,7 @@ struct xHeap {
_Bool collecting; _Bool collecting;
_Bool collection_failed; _Bool collection_failed;
int moved_with_destructors; int movedcount;
void *old_body; void *old_body;
int old_used; int old_used;
int old_total; int old_total;
@@ -48,6 +49,7 @@ Heap *Heap_New(int size)
if(heap == NULL) if(heap == NULL)
return NULL; return NULL;
heap->objcount = 0;
heap->total = 0; heap->total = 0;
heap->size = size; heap->size = size;
heap->used = 0; heap->used = 0;
@@ -105,6 +107,21 @@ void Heap_Free(Heap *heap)
free(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) float Heap_GetUsagePercentage(Heap *heap)
{ {
return 100.0 * heap->total / heap->size; return 100.0 * heap->total / heap->size;
@@ -176,6 +193,8 @@ void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err)
if(requires_destruct) if(requires_destruct)
heap->pend[heap->pend_used++] = (PendingDestruct) { .object = obj, .destructor = obj->type->free }; heap->pend[heap->pend_used++] = (PendingDestruct) { .object = obj, .destructor = obj->type->free };
heap->objcount += 1;
return (Object*) addr; return (Object*) addr;
} }
@@ -246,7 +265,7 @@ _Bool Heap_StartCollection(Heap *heap, Error *error)
heap->oflow = NULL; heap->oflow = NULL;
heap->collecting = 1; heap->collecting = 1;
heap->collection_failed = 0; heap->collection_failed = 0;
heap->moved_with_destructors = 0; heap->movedcount = 0;
heap->error = error; heap->error = error;
return 1; return 1;
} }
@@ -311,6 +330,7 @@ _Bool Heap_StopCollection(Heap *heap)
free(heap->old_body); free(heap->old_body);
heap->collecting = 0; heap->collecting = 0;
heap->objcount = heap->movedcount;
return 1; return 1;
} }
@@ -397,8 +417,7 @@ void Heap_CollectReference(Object **referer, void *userp)
((MovedObject*) old_location)->new_location = new_location; ((MovedObject*) old_location)->new_location = new_location;
} }
if(type->free != NULL) heap->movedcount += 1;
heap->moved_with_destructors += 1;
} }
// Collect the reference to the type. // Collect the reference to the type.
+262 -68
View File
@@ -1,35 +1,57 @@
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "../utils/defs.h" #include "../utils/defs.h"
#include "objects.h" #include "objects.h"
typedef struct { typedef struct {
int size, Object base;
refs; int size;
unsigned char data[]; unsigned char *body;
} BufferBody;
typedef struct {
Object base;
BufferBody *body;
int offset, length;
} BufferObject; } BufferObject;
static Object *select(Object *self, Object *key, Heap *heap, Error *err); typedef struct {
static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); Object base;
static int count(Object *self); BufferObject *sliced;
static void print(Object *obj, FILE *fp); 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 = { 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),
.select = select, .select = buffer_select,
.insert = insert, .insert = buffer_insert,
.count = count, .count = buffer_count,
.print = print, .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) Object *Object_NewBuffer(int size, Heap *heap, Error *error)
{ {
assert(size >= 0); assert(size >= 0);
@@ -42,73 +64,147 @@ Object *Object_NewBuffer(int size, Heap *heap, Error *error)
if(obj == NULL) if(obj == NULL)
return NULL; return NULL;
obj->offset = 0; unsigned char *body;
obj->length = size;
obj->body = Heap_RawMalloc(heap, sizeof(BufferBody) + sizeof(unsigned char) * size, error);
if(obj->body == NULL) if(size > THRESHOLD)
return NULL; {
body = malloc(sizeof(unsigned char) * size);
obj->body->size = size; if(body == NULL)
obj->body->refs = 1; {
memset(obj->body->data, 0, size); 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; 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) 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; return NULL;
} }
BufferObject *original = (BufferObject*) buffer; BufferSliceObject *slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error);
BufferObject *slice = (BufferObject*) Heap_Malloc(heap, &t_buffer, 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"); BufferObject *original = (BufferObject*) buffer;
return NULL;
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; return (Object*) slice;
} }
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error) 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; return NULL;
} }
BufferObject *buf = (BufferObject*) obj; if(obj->type == &t_buffer)
{
BufferObject *buffer = (BufferObject*) obj;
if(size) if(size)
*size = buf->length; *size = buffer->size;
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 != NULL);
assert(self->type == &t_buffer); assert(self->type == &t_buffer);
@@ -127,18 +223,48 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
BufferObject *buffer = (BufferObject*) self; BufferObject *buffer = (BufferObject*) self;
if(idx < 0 || idx >= buffer->length) if(idx < 0 || idx >= buffer->size)
{ {
Error_Report(error, 0, "Out of range index"); Error_Report(error, 0, "Out of range index");
return NULL; return NULL;
} }
unsigned char byte = buffer->body->data[buffer->offset + idx]; unsigned char byte = buffer->body[idx];
return Object_FromInt(byte, heap, error); 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(error != NULL);
assert(key != 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); int idx = Object_ToInt(key, error);
assert(error->occurred == 0); assert(error->occurred == 0);
if(idx < 0 || idx >= buffer->length) if(idx < 0 || idx >= buffer->size)
{ {
Error_Report(error, 0, "Out of range index"); Error_Report(error, 0, "Out of range index");
return NULL; 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) if(error->occurred == 1)
return 0; return 0;
buffer->body->data[buffer->offset + idx] = byte; buffer->body[idx] = byte;
return 1; 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; 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, "["); fprintf(fp, "[");
for(int i = 0; i < buffer->length; i += 1) for(int i = 0; i < size; i += 1)
{ {
unsigned char byte, low, high; unsigned char byte, low, high;
byte = buffer->body->data[buffer->offset + i]; byte = addr[i];
low = byte & 0xf; low = byte & 0xf;
high = byte >> 4; high = byte >> 4;
@@ -204,8 +386,20 @@ static void print(Object *self, FILE *fp)
fprintf(fp, "%c%c", c1, c2); fprintf(fp, "%c%c", c1, c2);
if(i+1 < buffer->length) if(i+1 < size)
fprintf(fp, ", "); fprintf(fp, ", ");
} }
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);
}
+2
View File
@@ -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) void Object_WalkReferences(Object *parent, void (*callback)(Object **referer, void *userp), void *userp)
{ {
assert(parent != NULL);
if(parent->type->walk != NULL) if(parent->type->walk != NULL)
parent->type->walk(parent, callback, userp); parent->type->walk(parent, callback, userp);
} }
void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsigned int size, void *userp), void *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) if(parent->type->walkexts != NULL)
parent->type->walkexts(parent, callback, userp); parent->type->walkexts(parent, callback, userp);
} }
+3
View File
@@ -81,6 +81,9 @@ _Bool Heap_StartCollection(Heap *heap, Error *error);
_Bool Heap_StopCollection(Heap *heap); _Bool Heap_StopCollection(Heap *heap);
void Heap_CollectReference(Object **referer, void *heap); void Heap_CollectReference(Object **referer, void *heap);
float Heap_GetUsagePercentage(Heap *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 TypeObject* Object_GetType(const Object *obj);
const char* Object_GetName(const Object *obj); const char* Object_GetName(const Object *obj);
+35 -2
View File
@@ -6,8 +6,8 @@
#define MAX_FRAME_STACK 16 #define MAX_FRAME_STACK 16
#define MAX_FRAMES 16 #define MAX_FRAMES 16
typedef struct Frame Frame; typedef struct xFrame Frame;
struct Frame { struct xFrame {
Frame *prev; Frame *prev;
Object *locals; Object *locals;
Object *closure; Object *closure;
@@ -25,6 +25,39 @@ struct xRuntime {
Heap *heap; 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) Stack *Runtime_GetStack(Runtime *runtime)
{ {
return Stack_Copy(runtime->stack, 1); return Stack_Copy(runtime->stack, 1);
+5
View File
@@ -7,6 +7,7 @@
#include "../common/executable.h" #include "../common/executable.h"
typedef struct xRuntime Runtime; typedef struct xRuntime Runtime;
typedef void CallStackScanner;
Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*)); Runtime* Runtime_New(int stack_size, int heap_size, void *callback_userp, _Bool (*callback_addr)(Runtime*, void*));
void Runtime_Free(Runtime *runtime); void Runtime_Free(Runtime *runtime);
_Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n); _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_Free(Snapshot *snapshot);
void Snapshot_Print(Snapshot *snapshot, FILE *fp); 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 *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); Object* Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);