1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-11 13:55:55 +03:00

c: Add Boehm garbage collector

By default, garbage collection is enabled.  You can run:

    make USE_GC=

to build the C implementation without garbage collection.
This commit is contained in:
Dov Murik 2015-12-09 15:41:41 -05:00
parent 35bc081fe7
commit 6b3ecaa769
20 changed files with 141 additions and 62 deletions

View File

@ -144,7 +144,8 @@ bash stepX_YYY.sh
### C
The C implementation of mal requires the following libraries (lib and
header packages): glib, libffi6 and either the libedit or GNU readline library.
header packages): glib, libffi6, libgc, and either the libedit or GNU readline
library.
```
cd c

View File

@ -25,4 +25,4 @@ WORKDIR /mal
RUN apt-get -y install g++
# Libraries needed for the C impl
RUN apt-get -y install libglib2.0 libglib2.0-dev libffi-dev
RUN apt-get -y install libglib2.0 libglib2.0-dev libffi-dev libgc-dev

View File

@ -1,4 +1,5 @@
USE_READLINE ?=
USE_GC ?= 1
CFLAGS += -g -O2
LDFLAGS += -g
@ -38,6 +39,12 @@ RL_LIBRARY ?= readline
CFLAGS += -DUSE_READLINE=1
endif
ifeq (,$(USE_GC))
else
CFLAGS += -DUSE_GC=1
LDFLAGS += -lgc
endif
CFLAGS += $(GLIB_CFLAGS)
LDFLAGS += -l$(RL_LIBRARY) $(GLIB_LDFLAGS) -ldl -lffi

View File

@ -96,8 +96,8 @@ MalVal *prn(MalVal *args) {
assert_type(args, MAL_LIST|MAL_VECTOR,
"prn called with non-sequential args");
char *repr = _pr_str_args(args, " ", 1);
g_print("%s\n", repr);
free(repr);
puts(repr);
MAL_GC_FREE(repr);
return &mal_nil;
}
@ -107,8 +107,8 @@ MalVal *println(MalVal *args) {
assert_type(args, MAL_LIST|MAL_VECTOR,
"println called with non-sequential args");
char *repr = _pr_str_args(args, " ", 0);
g_print("%s\n", repr);
free(repr);
puts(repr);
MAL_GC_FREE(repr);
return &mal_nil;
}
@ -135,7 +135,7 @@ char *slurp_raw(char *path) {
if (fstat(fd, &fst) < 0) {
abort("slurp failed to stat '%s'", path);
}
data = malloc(fst.st_size+1);
data = MAL_GC_MALLOC(fst.st_size+1);
sz = read(fd, data, fst.st_size);
if (sz < fst.st_size) {
abort("slurp failed to read '%s'", path);

View File

@ -4,7 +4,7 @@
// Env
Env *new_env(Env *outer, MalVal* binds, MalVal *exprs) {
Env *e = malloc(sizeof(Env));
Env *e = MAL_GC_MALLOC(sizeof(Env));
e->table = g_hash_table_new(g_str_hash, g_str_equal);
e->outer = outer;

View File

@ -29,13 +29,13 @@ char *_pr_str_hash_map(MalVal *obj, int print_readably) {
} else {
repr_tmp2 = repr;
repr = g_strdup_printf("%s %s %s", repr_tmp2, (char*)key2, repr_tmp1);
free(repr_tmp2);
MAL_GC_FREE(repr_tmp2);
}
free(repr_tmp1);
MAL_GC_FREE(repr_tmp1);
}
repr_tmp2 = repr;
repr = g_strdup_printf("%s}", repr_tmp2);
free(repr_tmp2);
MAL_GC_FREE(repr_tmp2);
return repr;
}
@ -51,13 +51,13 @@ char *_pr_str_list(MalVal *obj, int print_readably, char start, char end) {
} else {
repr_tmp2 = repr;
repr = g_strdup_printf("%s %s", repr_tmp2, repr_tmp1);
free(repr_tmp2);
MAL_GC_FREE(repr_tmp2);
}
free(repr_tmp1);
MAL_GC_FREE(repr_tmp1);
}
repr_tmp2 = repr;
repr = g_strdup_printf("%s%c", repr_tmp2, end);
free(repr_tmp2);
MAL_GC_FREE(repr_tmp2);
return repr;
}
@ -84,7 +84,7 @@ char *_pr_str(MalVal *obj, int print_readably) {
} else if (print_readably) {
char *repr_tmp = g_strescape(obj->val.string, "");
repr = g_strdup_printf("\"%s\"", repr_tmp);
free(repr_tmp);
MAL_GC_FREE(repr_tmp);
} else {
repr = g_strdup_printf("%s", obj->val.string);
}
@ -139,13 +139,16 @@ char *_pr_str_args(MalVal *args, char *sep, int print_readably) {
if (i != 0) {
repr2 = repr;
repr = g_strdup_printf("%s%s", repr2, sep);
free(repr2);
MAL_GC_FREE(repr2);
}
repr2 = repr;
repr = g_strdup_printf("%s%s",
repr2, _pr_str(obj, print_readably));
free(repr2);
MAL_GC_FREE(repr2);
}
return repr;
char* res = MAL_GC_STRDUP(repr);
MAL_GC_FREE(repr);
// TODO - check why STRDUP was needed here
return res;
}

View File

@ -13,7 +13,7 @@
MalVal *read_form(Reader *reader);
Reader *reader_new() {
Reader *reader = (Reader*)malloc(sizeof(Reader));
Reader *reader = (Reader*)MAL_GC_MALLOC(sizeof(Reader));
reader->array = g_array_sized_new(TRUE, FALSE, sizeof(char *), 8);
reader->position = 0;
return reader;
@ -39,10 +39,10 @@ char *reader_next(Reader *reader) {
void reader_free(Reader *reader) {
int i;
for(i=0; i < reader->array->len; i++) {
free(g_array_index(reader->array, char*, i));
MAL_GC_FREE(g_array_index(reader->array, char*, i));
}
g_array_free(reader->array, TRUE);
free(reader);
g_array_free(reader->array, TRUE);
MAL_GC_FREE(reader);
}
Reader *tokenize(char *line) {
@ -82,11 +82,10 @@ char *replace_str(const char *str, const char *old, const char *new)
{
GRegex *reg = g_regex_new (old, 0, 0, NULL);
char *str_tmp = g_regex_replace_literal(reg, str, -1, 0, new, 0, NULL);
free(reg);
MAL_GC_FREE(reg);
return str_tmp;
}
MalVal *read_atom(Reader *reader) {
char *token;
GRegex *regex;
@ -120,20 +119,21 @@ MalVal *read_atom(Reader *reader) {
//g_print("read_atom string: %s\n", token);
char *str_tmp = replace_str(g_match_info_fetch(matchInfo, 6), "\\\\\"", "\"");
char *str_tmp2 = replace_str(str_tmp, "\\\\n", "\n");
free(str_tmp);
MAL_GC_FREE(str_tmp);
char *str_tmp3 = replace_str(str_tmp2, "\\\\\\\\", "\\");
free(str_tmp2);
MAL_GC_FREE(str_tmp2);
atom = malval_new_string(str_tmp3);
} else if (g_match_info_fetch_pos(matchInfo, 7, &pos, NULL) && pos != -1) {
//g_print("read_atom keyword\n");
atom = malval_new_keyword(g_match_info_fetch(matchInfo, 7));
atom = malval_new_keyword(MAL_GC_STRDUP(g_match_info_fetch(matchInfo, 7)));
} else if (g_match_info_fetch_pos(matchInfo, 8, &pos, NULL) && pos != -1) {
//g_print("read_atom symbol\n");
atom = malval_new_symbol(g_match_info_fetch(matchInfo, 8));
atom = malval_new_symbol(MAL_GC_STRDUP(g_match_info_fetch(matchInfo, 8)));
} else {
malval_free(atom);
atom = NULL;
}
return atom;
}

View File

@ -37,7 +37,7 @@ int main()
ast = READ(prompt);
if (!ast) return 0;
exp = EVAL(ast, NULL);
g_print("%s\n", PRINT(exp));
puts(PRINT(exp));
free(ast); // Free input string
}

View File

@ -21,7 +21,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -62,6 +62,8 @@ int main()
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt
snprintf(prompt, sizeof(prompt), "user> ");
@ -74,8 +76,8 @@ int main()
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -24,7 +24,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -130,6 +130,8 @@ int main()
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env();
@ -143,8 +145,8 @@ int main()
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -24,7 +24,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -156,6 +156,8 @@ int main()
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env();
@ -169,8 +171,8 @@ int main()
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -195,6 +195,8 @@ int main()
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env();
@ -208,8 +210,8 @@ int main()
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -208,6 +208,8 @@ int main()
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env();
@ -221,8 +223,8 @@ int main()
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -222,6 +222,8 @@ int main(int argc, char *argv[])
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env(argc, argv);
@ -241,8 +243,8 @@ int main(int argc, char *argv[])
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -259,6 +259,8 @@ int main(int argc, char *argv[])
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env(argc, argv);
@ -278,8 +280,8 @@ int main(int argc, char *argv[])
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -26,7 +26,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -303,6 +303,8 @@ int main(int argc, char *argv[])
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env(argc, argv);
@ -322,8 +324,8 @@ int main(int argc, char *argv[])
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -27,7 +27,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -325,6 +325,8 @@ int main(int argc, char *argv[])
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env(argc, argv);
@ -344,8 +346,8 @@ int main(int argc, char *argv[])
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -27,7 +27,7 @@ MalVal *READ(char prompt[], char *str) {
}
}
ast = read_str(line);
if (!str) { free(line); }
if (!str) { MAL_GC_FREE(line); }
return ast;
}
@ -332,6 +332,8 @@ int main(int argc, char *argv[])
char *output;
char prompt[100];
MAL_GC_SETUP();
// Set the initial prompt and environment
snprintf(prompt, sizeof(prompt), "user> ");
init_repl_env(argc, argv);
@ -352,8 +354,8 @@ int main(int argc, char *argv[])
output = PRINT(exp);
if (output) {
g_print("%s\n", output);
free(output); // Free output string
puts(output);
MAL_GC_FREE(output); // Free output string
}
//malval_free(exp); // Free evaluated expression

View File

@ -5,6 +5,37 @@
#include "types.h"
#include "printer.h"
#ifdef USE_GC
void nop_free(void* ptr) {
(void)ptr; // Unused argument
}
static GMemVTable gc_gmem_vtable = {
.malloc = GC_malloc,
.realloc = GC_realloc,
.free = nop_free,
.calloc = NULL,
.try_malloc = NULL,
.try_realloc = NULL
};
void GC_setup() {
GC_INIT();
setenv("G_SLICE", "always-malloc", 1);
g_mem_gc_friendly = TRUE;
g_mem_set_vtable(&gc_gmem_vtable);
}
char* GC_strdup(const char *src) {
if (!src) {
return NULL;
}
char* dst = (char*)MAL_GC_MALLOC(strlen(src) + 1);
strcpy(dst, src);
return dst;
}
#endif
// Errors/Exceptions
@ -67,17 +98,16 @@ int _count(MalVal *obj) {
// Allocate a malval and set its type and value
MalVal *malval_new(MalType type, MalVal *metadata) {
MalVal *mv = (MalVal*)malloc(sizeof(MalVal));
MalVal *mv = (MalVal*)MAL_GC_MALLOC(sizeof(MalVal));
mv->type = type;
mv->metadata = metadata;
return mv;
}
//
void malval_free(MalVal *mv) {
// TODO: free collection items
if (!(mv->type & (MAL_NIL|MAL_TRUE|MAL_FALSE))) {
free(mv);
MAL_GC_FREE(mv);
}
}

View File

@ -3,6 +3,24 @@
#include <glib.h>
#ifdef USE_GC
#include <gc/gc.h>
char* GC_strdup(const char *src);
#define MAL_GC_SETUP() GC_setup()
#define MAL_GC_MALLOC GC_MALLOC
#define MAL_GC_FREE nop_free
#define MAL_GC_STRDUP GC_strdup
#else
#include <string.h>
#define MAL_GC_SETUP()
#define MAL_GC_MALLOC malloc
#define MAL_GC_FREE free
#define MAL_GC_STRDUP strdup
#endif
struct MalVal; // pre-declare