Skip to content

Commit

Permalink
Fix lots of memory leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
Josep M. Bach committed Feb 26, 2013
1 parent 11ce217 commit a387678
Show file tree
Hide file tree
Showing 16 changed files with 165 additions and 11 deletions.
12 changes: 12 additions & 0 deletions src/terror/call_frame.c
Expand Up @@ -15,9 +15,21 @@ CallFrame_new(VALUE self, Function *fn, int *ret)
cf->ret = ret;
cf->locals = DArray_create(sizeof(VALUE), 10);
cf->parent = NULL;
cf->refcount = 0;
return cf;
}

void
CallFrame_destroy(CallFrame *frame)
{
if(frame->refcount <= 0) {
if(frame->parent) frame->parent->refcount--;
DArray_destroy(frame->locals);
free(frame);
}
}


VALUE
CallFrame_getlocal(CallFrame *frame, int idx)
{
Expand Down
2 changes: 2 additions & 0 deletions src/terror/call_frame.h
Expand Up @@ -12,12 +12,14 @@ struct call_frame_s {
DArray *locals;
Function *fn;
int *ret;
int refcount;
struct call_frame_s *parent;
};

typedef struct call_frame_s CallFrame;

CallFrame* CallFrame_new(struct val_s* self, Function *fn, int *ret);
void CallFrame_destroy(CallFrame *frame);

struct val_s* CallFrame_getlocal(CallFrame *frame, int idx);
void CallFrame_setlocal(CallFrame *frame, int idx, struct val_s* value);
Expand Down
8 changes: 8 additions & 0 deletions src/terror/debugger.c
Expand Up @@ -2,6 +2,7 @@
#include <terror/debugger.h>
#include <terror/file_utils.h>
#include <terror/vm.h>
#include <treadmill/gc.h>
#include "stdlib.h"
#include "stdio.h"

Expand Down Expand Up @@ -100,6 +101,7 @@ Debugger_prompt(STATE)
printf("\nd: show the stack");
printf("\nl: show locals");
printf("\nt: show backtrace");
printf("\ng: show GC stats");
printf("\nb: set breakpoint in a line. Example: b 30");
printf("\n\n");
break;
Expand All @@ -126,6 +128,12 @@ Debugger_prompt(STATE)
CallFrame_print_backtrace(CURR_FRAME);
break;
}
case 'g': {
printf("\nGC");
printf("\n--\n");
TmHeap_print(state->heap);
break;
}
case 'l': {
printf("\nLocals");
printf("\n------");
Expand Down
17 changes: 15 additions & 2 deletions src/terror/function.c
Expand Up @@ -18,14 +18,26 @@ Function_new(char *filename, int *code, DArray *literals)
return fn;
}

void
Function_destroy(Function *fn)
{
if(fn->filename) free(fn->filename);
if(fn->code) free(fn->code);
DArray_destroy(fn->literals);
free(fn);
}

Function*
Function_native_new(native_fn c_fn)
{
Function *fn = calloc(1, sizeof(Function));
fn->filename = "(native)";
char *name = malloc(9 * sizeof(char));
strcpy(name, "(native)");

fn->filename = name;
fn->code = NULL;
fn->literals = NULL;
fn->scope = NULL;
fn->scope = NULL;
fn->c_fn = c_fn;
return fn;
}
Expand Down Expand Up @@ -67,6 +79,7 @@ Function_call(
// If it is a closure, we nest the call frames.
if(fn->scope) {
new_frame->parent = fn->scope;
new_frame->parent->refcount++;
}

Stack_push(FRAMES, new_frame);
Expand Down
1 change: 1 addition & 0 deletions src/terror/function.h
Expand Up @@ -20,6 +20,7 @@ struct function_s {
typedef struct function_s Function;

Function* Function_new(char*, int*, DArray*);
void Function_destroy(Function*);
Function* Function_native_new(native_fn);
struct val_s* Function_native_call(struct state_s*, Function*, struct val_s*, DArray*);
int* Function_call(struct state_s*, Function*, struct val_s*, DArray*, char* name);
Expand Down
8 changes: 7 additions & 1 deletion src/terror/gc.c
Expand Up @@ -20,7 +20,13 @@ GC_release(void *value)
void
GC_scan_pointers(TmHeap *heap, TmObjectHeader *object, TmCallbackFn callback)
{
Value_each((VALUE)object, ^ void (VALUE key, VALUE val) {
VALUE val = (VALUE)object;

for(int i = 0; i < DArray_count(val->fields); i++) {
callback(heap, (TmObjectHeader*)DArray_at(val->fields, i));
}

Value_each(val, ^ void (VALUE key, VALUE val) {
callback(heap, (TmObjectHeader*)key);
callback(heap, (TmObjectHeader*)val);
});
Expand Down
8 changes: 4 additions & 4 deletions src/terror/hashmap.c
Expand Up @@ -58,16 +58,16 @@ Hashmap *Hashmap_create(Hashmap_compare compare, Hashmap_hash hash)
void Hashmap_destroy(Hashmap *map)
{
int i = 0;
/* int j = 0; */
int j = 0;

if(map) {
if(map->buckets) {
for(i = 0; i < DArray_count(map->buckets); i++) {
DArray *bucket = DArray_get(map->buckets, i);
if(bucket) {
/* for(j = 0; j < DArray_count(bucket); j++) { */
/* free(DArray_get(bucket, j)); */
/* } */
for(j = 0; j < DArray_count(bucket); j++) {
free(DArray_get(bucket, j));
}
DArray_destroy(bucket);
}
}
Expand Down
17 changes: 16 additions & 1 deletion src/terror/input_reader.c
Expand Up @@ -96,6 +96,8 @@ BytecodeFile *BytecodeFile_new(STATE, bstring compiled_filename)

bdestroy(buf);

DArray_push(state->files, file);

return file;

error:
Expand All @@ -109,7 +111,20 @@ BytecodeFile_destroy(BytecodeFile *file)
{
if(file->filename) bdestroy(file->filename);
if(file->compiled_filename) bdestroy(file->compiled_filename);
if(file->functions) Hashmap_destroy(file->functions);

for(int i = 0; i < DArray_count(file->function_names); i++) {
bdestroy((bstring)DArray_at(file->function_names, i));
}
Hashmap_traverse(file->functions, Hashmap_Function_destroy);
Hashmap_destroy(file->functions);

free(file);
}

int
Hashmap_Function_destroy(HashmapNode *node)
{
Function_destroy((Function*)node->data);
return 0;
}

1 change: 1 addition & 0 deletions src/terror/input_reader.h
Expand Up @@ -18,5 +18,6 @@ typedef struct {

BytecodeFile *BytecodeFile_new(struct state_s*, bstring filename);
void BytecodeFile_destroy(BytecodeFile *file);
int Hashmap_Function_destroy(HashmapNode *node);

#endif
20 changes: 18 additions & 2 deletions src/terror/state.c
Expand Up @@ -21,6 +21,8 @@ State_new()
State *state = calloc(1, sizeof(State));
state->functions = Hashmap_create(NULL, NULL);
state->frames = Stack_create();
state->files = DArray_create(sizeof(BytecodeFile*), 10);
state->native_fns = DArray_create(sizeof(Function*), 10);
state->stack = Stack_create();
state->dbg = Debugger_new();

Expand All @@ -41,9 +43,14 @@ State_new()
void
State_destroy(STATE)
{
while(Stack_count(state->frames) > 0) {
CallFrame_destroy((CallFrame*)Stack_pop(state->stack));
}

Stack_destroy(state->frames);

while(Stack_count(state->stack) > 0) Stack_pop(state->stack);

Stack_destroy(state->stack);

Debugger_destroy(state->dbg);
Expand All @@ -60,6 +67,15 @@ State_destroy(STATE)
Map_bp = NULL;
Closure_bp = NULL;

// TODO destroy functions
}
for(int i = 0; i < DArray_count(state->files); i++) {
BytecodeFile_destroy((BytecodeFile*)DArray_at(state->files, i));
}
DArray_destroy(state->files);

for(int i = 0; i < DArray_count(state->native_fns); i++) {
Function_destroy((Function*)DArray_at(state->native_fns, i));
}
DArray_destroy(state->native_fns);

free(state);
}
2 changes: 2 additions & 0 deletions src/terror/state.h
Expand Up @@ -13,6 +13,8 @@ struct state_s {
Hashmap *functions;
Stack *frames;
Stack *stack;
DArray *files;
DArray *native_fns;
VALUE lobby;
int *ret;
TmHeap *heap;
Expand Down
15 changes: 14 additions & 1 deletion src/terror/value.c
Expand Up @@ -34,6 +34,13 @@ Value_from_prototype(STATE, ValueType type, VALUE prototype) {
return val;
}

static inline int
Hashmap_destroy_bstring_key(HashmapNode *node)
{
bdestroy(node->key);
return 0;
}

void
Value_destroy(VALUE o)
{
Expand All @@ -49,7 +56,9 @@ Value_destroy(VALUE o)
break;
}
if(o->fields) DArray_destroy(o->fields);
if(o->table) Hashmap_destroy(o->table);

Hashmap_traverse(o->table, Hashmap_destroy_bstring_key);
Hashmap_destroy(o->table);

if(o) free(o);
}
Expand Down Expand Up @@ -180,6 +189,10 @@ Closure_new(STATE, Function *fn, CallFrame *scope)
{
VALUE val = Value_from_prototype(state, ClosureType, Closure_bp);
fn->scope = scope;

// Keep track of native functions to deallocate them properly
if(fn->c_fn) DArray_push(state->native_fns, fn);

val->data.as_data = fn;
return val;
}
Expand Down
5 changes: 5 additions & 0 deletions src/terror/vm.c
Expand Up @@ -334,6 +334,11 @@ VALUE VM_run(STATE)
CallFrame *old_frame = Stack_pop(FRAMES);

ip = old_frame->ret;

printf("Destroying call frame...\n");
CallFrame_print_backtrace(old_frame);
CallFrame_destroy(old_frame);

check(Stack_count(STACK) > 0, "Stack underflow.");

if (ip == NULL) return Stack_pop(STACK); // if there's nowhere to return, exit
Expand Down
40 changes: 40 additions & 0 deletions tests/gc_tests.c
@@ -0,0 +1,40 @@
#include "minunit.h"
#include <terror/runtime.h>
#include <terror/input_reader.h>
#include <terror/state.h>
#include <assert.h>

// Extern global objects declared in runtime.h
VALUE TrueObject;
VALUE FalseObject;
VALUE NilObject;

#define SETUP() \
Hashmap *fns = Hashmap_create(NULL, NULL); \
STATE = State_new(); \
Hashmap_destroy(state->functions); \
state->functions = fns; \
Runtime_init(state); \

#define TEARDOWN() \
Hashmap_traverse(fns, Hashmap_Function_destroy); \
Hashmap_destroy(fns); \
State_destroy(state); \
return NULL; \

char *test_empty()
{
SETUP();
TEARDOWN();
}


char *all_tests() {
mu_suite_start();

mu_run_test(test_empty);

return NULL;
}

RUN_TESTS(all_tests);
3 changes: 3 additions & 0 deletions tests/vm_tests.c
Expand Up @@ -24,10 +24,13 @@ VALUE NilObject;
Hashmap *fns = Hashmap_create(NULL, NULL); \
DArray *locals = DArray_create(sizeof(VALUE), 10); \
STATE = State_new(); \
Hashmap_destroy(state->functions); \
state->functions = fns; \
Runtime_init(state); \

#define TEARDOWN() \
Hashmap_traverse(fns, Hashmap_Function_destroy); \
Hashmap_destroy(fns); \
State_destroy(state); \
return NULL; \

Expand Down
17 changes: 17 additions & 0 deletions tests/void_tests.c
@@ -0,0 +1,17 @@
#include "minunit.h"

char *test_void()
{
return NULL;
}

char *all_tests() {
mu_suite_start();

mu_run_test(test_void);

return NULL;
}

RUN_TESTS(all_tests);

0 comments on commit a387678

Please sign in to comment.