Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fix lots of memory leaks

  • Loading branch information...
commit a38767880e7d14dea1ebeb1305cde48045e50dca 1 parent 11ce217
Josep M. Bach authored
12 src/terror/call_frame.c
@@ -15,9 +15,21 @@ CallFrame_new(VALUE self, Function *fn, int *ret)
15 15 cf->ret = ret;
16 16 cf->locals = DArray_create(sizeof(VALUE), 10);
17 17 cf->parent = NULL;
  18 + cf->refcount = 0;
18 19 return cf;
19 20 }
20 21
  22 +void
  23 +CallFrame_destroy(CallFrame *frame)
  24 +{
  25 + if(frame->refcount <= 0) {
  26 + if(frame->parent) frame->parent->refcount--;
  27 + DArray_destroy(frame->locals);
  28 + free(frame);
  29 + }
  30 +}
  31 +
  32 +
21 33 VALUE
22 34 CallFrame_getlocal(CallFrame *frame, int idx)
23 35 {
2  src/terror/call_frame.h
@@ -12,12 +12,14 @@ struct call_frame_s {
12 12 DArray *locals;
13 13 Function *fn;
14 14 int *ret;
  15 + int refcount;
15 16 struct call_frame_s *parent;
16 17 };
17 18
18 19 typedef struct call_frame_s CallFrame;
19 20
20 21 CallFrame* CallFrame_new(struct val_s* self, Function *fn, int *ret);
  22 +void CallFrame_destroy(CallFrame *frame);
21 23
22 24 struct val_s* CallFrame_getlocal(CallFrame *frame, int idx);
23 25 void CallFrame_setlocal(CallFrame *frame, int idx, struct val_s* value);
8 src/terror/debugger.c
@@ -2,6 +2,7 @@
2 2 #include <terror/debugger.h>
3 3 #include <terror/file_utils.h>
4 4 #include <terror/vm.h>
  5 +#include <treadmill/gc.h>
5 6 #include "stdlib.h"
6 7 #include "stdio.h"
7 8
@@ -100,6 +101,7 @@ Debugger_prompt(STATE)
100 101 printf("\nd: show the stack");
101 102 printf("\nl: show locals");
102 103 printf("\nt: show backtrace");
  104 + printf("\ng: show GC stats");
103 105 printf("\nb: set breakpoint in a line. Example: b 30");
104 106 printf("\n\n");
105 107 break;
@@ -126,6 +128,12 @@ Debugger_prompt(STATE)
126 128 CallFrame_print_backtrace(CURR_FRAME);
127 129 break;
128 130 }
  131 + case 'g': {
  132 + printf("\nGC");
  133 + printf("\n--\n");
  134 + TmHeap_print(state->heap);
  135 + break;
  136 + }
129 137 case 'l': {
130 138 printf("\nLocals");
131 139 printf("\n------");
17 src/terror/function.c
@@ -18,14 +18,26 @@ Function_new(char *filename, int *code, DArray *literals)
18 18 return fn;
19 19 }
20 20
  21 +void
  22 +Function_destroy(Function *fn)
  23 +{
  24 + if(fn->filename) free(fn->filename);
  25 + if(fn->code) free(fn->code);
  26 + DArray_destroy(fn->literals);
  27 + free(fn);
  28 +}
  29 +
21 30 Function*
22 31 Function_native_new(native_fn c_fn)
23 32 {
24 33 Function *fn = calloc(1, sizeof(Function));
25   - fn->filename = "(native)";
  34 + char *name = malloc(9 * sizeof(char));
  35 + strcpy(name, "(native)");
  36 +
  37 + fn->filename = name;
26 38 fn->code = NULL;
27 39 fn->literals = NULL;
28   - fn->scope = NULL;
  40 + fn->scope = NULL;
29 41 fn->c_fn = c_fn;
30 42 return fn;
31 43 }
@@ -67,6 +79,7 @@ Function_call(
67 79 // If it is a closure, we nest the call frames.
68 80 if(fn->scope) {
69 81 new_frame->parent = fn->scope;
  82 + new_frame->parent->refcount++;
70 83 }
71 84
72 85 Stack_push(FRAMES, new_frame);
1  src/terror/function.h
@@ -20,6 +20,7 @@ struct function_s {
20 20 typedef struct function_s Function;
21 21
22 22 Function* Function_new(char*, int*, DArray*);
  23 +void Function_destroy(Function*);
23 24 Function* Function_native_new(native_fn);
24 25 struct val_s* Function_native_call(struct state_s*, Function*, struct val_s*, DArray*);
25 26 int* Function_call(struct state_s*, Function*, struct val_s*, DArray*, char* name);
8 src/terror/gc.c
@@ -20,7 +20,13 @@ GC_release(void *value)
20 20 void
21 21 GC_scan_pointers(TmHeap *heap, TmObjectHeader *object, TmCallbackFn callback)
22 22 {
23   - Value_each((VALUE)object, ^ void (VALUE key, VALUE val) {
  23 + VALUE val = (VALUE)object;
  24 +
  25 + for(int i = 0; i < DArray_count(val->fields); i++) {
  26 + callback(heap, (TmObjectHeader*)DArray_at(val->fields, i));
  27 + }
  28 +
  29 + Value_each(val, ^ void (VALUE key, VALUE val) {
24 30 callback(heap, (TmObjectHeader*)key);
25 31 callback(heap, (TmObjectHeader*)val);
26 32 });
8 src/terror/hashmap.c
@@ -58,16 +58,16 @@ Hashmap *Hashmap_create(Hashmap_compare compare, Hashmap_hash hash)
58 58 void Hashmap_destroy(Hashmap *map)
59 59 {
60 60 int i = 0;
61   - /* int j = 0; */
  61 + int j = 0;
62 62
63 63 if(map) {
64 64 if(map->buckets) {
65 65 for(i = 0; i < DArray_count(map->buckets); i++) {
66 66 DArray *bucket = DArray_get(map->buckets, i);
67 67 if(bucket) {
68   - /* for(j = 0; j < DArray_count(bucket); j++) { */
69   - /* free(DArray_get(bucket, j)); */
70   - /* } */
  68 + for(j = 0; j < DArray_count(bucket); j++) {
  69 + free(DArray_get(bucket, j));
  70 + }
71 71 DArray_destroy(bucket);
72 72 }
73 73 }
17 src/terror/input_reader.c
@@ -96,6 +96,8 @@ BytecodeFile *BytecodeFile_new(STATE, bstring compiled_filename)
96 96
97 97 bdestroy(buf);
98 98
  99 + DArray_push(state->files, file);
  100 +
99 101 return file;
100 102
101 103 error:
@@ -109,7 +111,20 @@ BytecodeFile_destroy(BytecodeFile *file)
109 111 {
110 112 if(file->filename) bdestroy(file->filename);
111 113 if(file->compiled_filename) bdestroy(file->compiled_filename);
112   - if(file->functions) Hashmap_destroy(file->functions);
  114 +
  115 + for(int i = 0; i < DArray_count(file->function_names); i++) {
  116 + bdestroy((bstring)DArray_at(file->function_names, i));
  117 + }
  118 + Hashmap_traverse(file->functions, Hashmap_Function_destroy);
  119 + Hashmap_destroy(file->functions);
113 120
114 121 free(file);
115 122 }
  123 +
  124 +int
  125 +Hashmap_Function_destroy(HashmapNode *node)
  126 +{
  127 + Function_destroy((Function*)node->data);
  128 + return 0;
  129 +}
  130 +
1  src/terror/input_reader.h
@@ -18,5 +18,6 @@ typedef struct {
18 18
19 19 BytecodeFile *BytecodeFile_new(struct state_s*, bstring filename);
20 20 void BytecodeFile_destroy(BytecodeFile *file);
  21 +int Hashmap_Function_destroy(HashmapNode *node);
21 22
22 23 #endif
20 src/terror/state.c
@@ -21,6 +21,8 @@ State_new()
21 21 State *state = calloc(1, sizeof(State));
22 22 state->functions = Hashmap_create(NULL, NULL);
23 23 state->frames = Stack_create();
  24 + state->files = DArray_create(sizeof(BytecodeFile*), 10);
  25 + state->native_fns = DArray_create(sizeof(Function*), 10);
24 26 state->stack = Stack_create();
25 27 state->dbg = Debugger_new();
26 28
@@ -41,9 +43,14 @@ State_new()
41 43 void
42 44 State_destroy(STATE)
43 45 {
  46 + while(Stack_count(state->frames) > 0) {
  47 + CallFrame_destroy((CallFrame*)Stack_pop(state->stack));
  48 + }
  49 +
44 50 Stack_destroy(state->frames);
45 51
46 52 while(Stack_count(state->stack) > 0) Stack_pop(state->stack);
  53 +
47 54 Stack_destroy(state->stack);
48 55
49 56 Debugger_destroy(state->dbg);
@@ -60,6 +67,15 @@ State_destroy(STATE)
60 67 Map_bp = NULL;
61 68 Closure_bp = NULL;
62 69
63   - // TODO destroy functions
64   -}
  70 + for(int i = 0; i < DArray_count(state->files); i++) {
  71 + BytecodeFile_destroy((BytecodeFile*)DArray_at(state->files, i));
  72 + }
  73 + DArray_destroy(state->files);
65 74
  75 + for(int i = 0; i < DArray_count(state->native_fns); i++) {
  76 + Function_destroy((Function*)DArray_at(state->native_fns, i));
  77 + }
  78 + DArray_destroy(state->native_fns);
  79 +
  80 + free(state);
  81 +}
2  src/terror/state.h
@@ -13,6 +13,8 @@ struct state_s {
13 13 Hashmap *functions;
14 14 Stack *frames;
15 15 Stack *stack;
  16 + DArray *files;
  17 + DArray *native_fns;
16 18 VALUE lobby;
17 19 int *ret;
18 20 TmHeap *heap;
15 src/terror/value.c
@@ -34,6 +34,13 @@ Value_from_prototype(STATE, ValueType type, VALUE prototype) {
34 34 return val;
35 35 }
36 36
  37 +static inline int
  38 +Hashmap_destroy_bstring_key(HashmapNode *node)
  39 +{
  40 + bdestroy(node->key);
  41 + return 0;
  42 +}
  43 +
37 44 void
38 45 Value_destroy(VALUE o)
39 46 {
@@ -49,7 +56,9 @@ Value_destroy(VALUE o)
49 56 break;
50 57 }
51 58 if(o->fields) DArray_destroy(o->fields);
52   - if(o->table) Hashmap_destroy(o->table);
  59 +
  60 + Hashmap_traverse(o->table, Hashmap_destroy_bstring_key);
  61 + Hashmap_destroy(o->table);
53 62
54 63 if(o) free(o);
55 64 }
@@ -180,6 +189,10 @@ Closure_new(STATE, Function *fn, CallFrame *scope)
180 189 {
181 190 VALUE val = Value_from_prototype(state, ClosureType, Closure_bp);
182 191 fn->scope = scope;
  192 +
  193 + // Keep track of native functions to deallocate them properly
  194 + if(fn->c_fn) DArray_push(state->native_fns, fn);
  195 +
183 196 val->data.as_data = fn;
184 197 return val;
185 198 }
5 src/terror/vm.c
@@ -334,6 +334,11 @@ VALUE VM_run(STATE)
334 334 CallFrame *old_frame = Stack_pop(FRAMES);
335 335
336 336 ip = old_frame->ret;
  337 +
  338 + printf("Destroying call frame...\n");
  339 + CallFrame_print_backtrace(old_frame);
  340 + CallFrame_destroy(old_frame);
  341 +
337 342 check(Stack_count(STACK) > 0, "Stack underflow.");
338 343
339 344 if (ip == NULL) return Stack_pop(STACK); // if there's nowhere to return, exit
40 tests/gc_tests.c
... ... @@ -0,0 +1,40 @@
  1 +#include "minunit.h"
  2 +#include <terror/runtime.h>
  3 +#include <terror/input_reader.h>
  4 +#include <terror/state.h>
  5 +#include <assert.h>
  6 +
  7 +// Extern global objects declared in runtime.h
  8 +VALUE TrueObject;
  9 +VALUE FalseObject;
  10 +VALUE NilObject;
  11 +
  12 +#define SETUP() \
  13 + Hashmap *fns = Hashmap_create(NULL, NULL); \
  14 + STATE = State_new(); \
  15 + Hashmap_destroy(state->functions); \
  16 + state->functions = fns; \
  17 + Runtime_init(state); \
  18 +
  19 +#define TEARDOWN() \
  20 + Hashmap_traverse(fns, Hashmap_Function_destroy); \
  21 + Hashmap_destroy(fns); \
  22 + State_destroy(state); \
  23 + return NULL; \
  24 +
  25 +char *test_empty()
  26 +{
  27 + SETUP();
  28 + TEARDOWN();
  29 +}
  30 +
  31 +
  32 +char *all_tests() {
  33 + mu_suite_start();
  34 +
  35 + mu_run_test(test_empty);
  36 +
  37 + return NULL;
  38 +}
  39 +
  40 +RUN_TESTS(all_tests);
3  tests/vm_tests.c
@@ -24,10 +24,13 @@ VALUE NilObject;
24 24 Hashmap *fns = Hashmap_create(NULL, NULL); \
25 25 DArray *locals = DArray_create(sizeof(VALUE), 10); \
26 26 STATE = State_new(); \
  27 + Hashmap_destroy(state->functions); \
27 28 state->functions = fns; \
28 29 Runtime_init(state); \
29 30
30 31 #define TEARDOWN() \
  32 + Hashmap_traverse(fns, Hashmap_Function_destroy); \
  33 + Hashmap_destroy(fns); \
31 34 State_destroy(state); \
32 35 return NULL; \
33 36
17 tests/void_tests.c
... ... @@ -0,0 +1,17 @@
  1 +#include "minunit.h"
  2 +
  3 +char *test_void()
  4 +{
  5 + return NULL;
  6 +}
  7 +
  8 +char *all_tests() {
  9 + mu_suite_start();
  10 +
  11 + mu_run_test(test_void);
  12 +
  13 + return NULL;
  14 +}
  15 +
  16 +RUN_TESTS(all_tests);
  17 +

0 comments on commit a387678

Please sign in to comment.
Something went wrong with that request. Please try again.