Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix lots of memory leaks

  • Loading branch information...
commit a38767880e7d14dea1ebeb1305cde48045e50dca 1 parent 11ce217
Josep M. Bach authored
12 src/terror/call_frame.c
View
@@ -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)
{
2  src/terror/call_frame.h
View
@@ -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);
8 src/terror/debugger.c
View
@@ -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"
@@ -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;
@@ -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------");
17 src/terror/function.c
View
@@ -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;
}
@@ -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);
1  src/terror/function.h
View
@@ -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);
8 src/terror/gc.c
View
@@ -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);
});
8 src/terror/hashmap.c
View
@@ -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);
}
}
17 src/terror/input_reader.c
View
@@ -96,6 +96,8 @@ BytecodeFile *BytecodeFile_new(STATE, bstring compiled_filename)
bdestroy(buf);
+ DArray_push(state->files, file);
+
return file;
error:
@@ -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  src/terror/input_reader.h
View
@@ -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 src/terror/state.c
View
@@ -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();
@@ -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);
@@ -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  src/terror/state.h
View
@@ -13,6 +13,8 @@ struct state_s {
Hashmap *functions;
Stack *frames;
Stack *stack;
+ DArray *files;
+ DArray *native_fns;
VALUE lobby;
int *ret;
TmHeap *heap;
15 src/terror/value.c
View
@@ -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)
{
@@ -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);
}
@@ -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;
}
5 src/terror/vm.c
View
@@ -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
40 tests/gc_tests.c
View
@@ -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  tests/vm_tests.c
View
@@ -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; \
17 tests/void_tests.c
View
@@ -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);
+
Please sign in to comment.
Something went wrong with that request. Please try again.