nitg: move the GC stuff in a runtime C libray `gc_chooser`
authorJean Privat <jean@pryen.org>
Thu, 4 Jul 2013 09:41:23 +0000 (11:41 +0200)
committerJean Privat <jean@pryen.org>
Wed, 10 Jul 2013 15:57:41 +0000 (17:57 +0200)
Signed-off-by: Jean Privat <jean@pryen.org>

clib/gc_chooser.c [new file with mode: 0644]
clib/gc_chooser.h [new file with mode: 0644]
src/abstract_compiler.nit
src/global_compiler.nit
src/separate_compiler.nit
src/separate_erasure_compiler.nit

diff --git a/clib/gc_chooser.c b/clib/gc_chooser.c
new file mode 100644 (file)
index 0000000..5a8cffe
--- /dev/null
@@ -0,0 +1,123 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+ *
+ * Copyright 2006-2009 Jean Privat <jean@pryen.org>
+ *
+ * This file is free software, which comes along with NIT.  This software is
+ * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A
+ * PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+ * is kept unaltered, and a notification of the changes is added.
+ * You  are  allowed  to  redistribute it and sell it, alone or is a part of
+ * another product.
+ */
+
+#include "gc_chooser.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef ANDROID
+       #include <android/log.h>
+       #define PRINT_ERROR(...) ((void)__android_log_print(ANDROID_LOG_WARN, "nit", __VA_ARGS__))
+#else
+       #define PRINT_ERROR(...) ((void)fprintf(stderr, __VA_ARGS__))
+#endif
+
+enum gc_option { gc_opt_large, gc_opt_malloc, gc_opt_boehm } gc_option;
+
+#ifdef WITH_LIBGC
+#define GC_DEBUG
+#include <gc/gc.h>
+#endif
+
+void *nit_raw_alloc(size_t s0)
+{
+       switch (gc_option) {
+       case gc_opt_malloc: return malloc(s0);
+#ifdef WITH_LIBGC
+       case gc_opt_boehm: return GC_MALLOC_ATOMIC(s0);
+#endif
+
+       default: return nit_alloc(s0);
+       }
+}
+
+static void *large_alloc(size_t s0)
+{
+       static char * alloc_pos = NULL;
+       static size_t alloc_size = 0;
+       void * res;
+       size_t s = ((s0+3)/4)*4;
+       if(alloc_size < s) {
+               alloc_size = s + 1024*1024;
+               alloc_pos = (char *)calloc(alloc_size, 1);
+       }
+       res = alloc_pos;
+       alloc_size -= s;
+       alloc_pos += s;
+       return res;
+}
+
+void nit_gcollect(void) {
+       switch (gc_option) {
+#ifdef WITH_LIBGC
+       case gc_opt_boehm: GC_gcollect(); break;
+#endif
+       }
+}
+
+void *nit_alloc(size_t s0)
+{
+       switch (gc_option) {
+#ifdef WITH_LIBGC
+       case gc_opt_boehm: return GC_MALLOC(s0);
+#endif
+       case gc_opt_malloc: return calloc(1, s0);
+       case gc_opt_large:
+       default: return large_alloc(s0);
+       }
+}
+
+void initialize_gc_option(void) {
+       /* GC default */
+       char *def;
+#ifdef WITH_LIBGC
+       gc_option = gc_opt_boehm;
+       def = "boehm";
+#else
+       gc_option = gc_opt_malloc;
+       def = "malloc";
+#endif
+
+       /* Process GC runtime selection */
+       if (getenv("NIT_GC_OPTION") != NULL) {
+               char *opt=getenv("NIT_GC_OPTION");
+               if (strcmp(opt, "boehm")==0) {
+#ifdef WITH_LIBGC
+                       gc_option = gc_opt_boehm;
+#else
+               PRINT_ERROR( "Compiled without Boehm GC support. Using default '%s'.\n", def);
+#endif
+               } else if (strcmp(opt, "malloc")==0) {
+                       gc_option = gc_opt_malloc;
+               } else if (strcmp(opt, "large")==0) {
+                       gc_option = gc_opt_large;
+               } else if (strcmp(opt, "help")==0) {
+                       PRINT_ERROR( "NIT_GC_OPTION accepts 'malloc', 'large'"
+#ifdef WITH_LIBGC
+                                       ", 'boehm'"
+#endif
+                                       ". Default is '%s'.\n", def);
+                       exit(1);
+               } else {
+                       PRINT_ERROR( "Invalid GC option in NIT_GC_OPTION environment variable. Using default '%s'.\n", def);
+               }
+       }
+
+       /* Initialize GC (if needed) */
+       switch(gc_option) {
+#ifdef WITH_LIBGC
+               case gc_opt_boehm: GC_INIT(); break;
+#endif
+               default: break; /* Nothing */
+       }
+}
diff --git a/clib/gc_chooser.h b/clib/gc_chooser.h
new file mode 100644 (file)
index 0000000..4d1d03a
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef NIT_GC_CHOOSER_H
+#define NIT_GC_CHOOSER_H
+
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+ *
+ * This file is free software, which comes along with NIT.  This software is
+ * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A
+ * PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+ * is kept unaltered, and a notification of the changes is added.
+ * You  are  allowed  to  redistribute it and sell it, alone or is a part of
+ * another product.
+ */
+
+#include <stdio.h>
+
+/* GC and memory management */
+void *nit_alloc(size_t); /* allocate memory to store an object with an object header */
+void *nit_raw_alloc(size_t); /* allocate raw memory to store a raw stram of byte */
+void nit_gcollect(void); /* force a garbage collection */
+void initialize_gc_option(void); /* Select the wanted GC using envvar `NIT_GC_OPTION` */
+
+#endif
index 36d7ed1..f312d24 100644 (file)
@@ -191,6 +191,11 @@ redef class ModelBuilder
                        makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
                        ofiles.add(o)
                end
+
+               # Add gc_choser.h to aditionnal bodies
+               var gc_chooser = new ExternCFile("{cc_paths.first}/gc_chooser.c", "-DWITH_LIBGC")
+               compiler.extern_bodies.add(gc_chooser)
+
                # Compile each required extern body into a specific .o
                for f in compiler.extern_bodies do
                        var basename = f.filename.basename(".c")
@@ -290,16 +295,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
-               self.header.add_decl("#ifndef NOBOEHM")
-               self.header.add_decl("#include <gc/gc.h>")
-               self.header.add_decl("#ifdef NOBOEHM_ATOMIC")
-               self.header.add_decl("#undef GC_MALLOC_ATOMIC")
-               self.header.add_decl("#define GC_MALLOC_ATOMIC(x) GC_MALLOC(x)")
-               self.header.add_decl("#endif /*NOBOEHM_ATOMIC*/")
-               self.header.add_decl("#else /*NOBOEHM*/")
-               self.header.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
-               self.header.add_decl("#define GC_MALLOC_ATOMIC(x) calloc(1, (x))")
-               self.header.add_decl("#endif /*NOBOEHM*/")
+               self.header.add_decl("#include <gc_chooser.h>")
 
                compile_header_structs
 
@@ -336,6 +332,7 @@ abstract class AbstractCompiler
                end
                v.add_decl("int main(int argc, char** argv) \{")
                v.add("glob_argc = argc; glob_argv = argv;")
+               v.add("initialize_gc_option();")
                var main_type = mainmodule.sys_type
                if main_type != null then
                        var mainmodule = v.compiler.mainmodule
@@ -1609,7 +1606,7 @@ redef class AInternMethPropdef
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return
                else if pname == "calloc_string" then
-                       v.ret(v.new_expr("(char*)GC_MALLOC_ATOMIC({arguments[1]})", ret.as(not null)))
+                       v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
                        return
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
@@ -1629,7 +1626,7 @@ redef class AInternMethPropdef
                        v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
                        return
                else if pname == "force_garbage_collection" then
-                       v.add("GC_gcollect();")
+                       v.add("nit_gcollect();")
                        return
                end
                v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
index fb91481..7b3c944 100644 (file)
@@ -212,9 +212,9 @@ class GlobalCompiler
                res.is_exact = true
                if is_native_array then
                        var mtype_elt = mtype.arguments.first
-                       v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
+                       v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
                else
-                       v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+                       v.add("{res} = nit_alloc(sizeof(struct {mtype.c_name}));")
                end
                v.add("{res}->classid = {self.classid(mtype)};")
 
@@ -245,7 +245,7 @@ class GlobalCompiler
                self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
                v.add_decl("/* allocate {mtype} */")
                v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
-               v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
+               v.add("struct {mtype.c_name}*res = nit_alloc(sizeof(struct {mtype.c_name}));")
                v.add("res->classid = {self.classid(mtype)};")
                v.add("res->value = value;")
                v.add("return (val*)res;")
index f6648c7..7bbbdeb 100644 (file)
@@ -654,7 +654,7 @@ class SeparateCompiler
                        self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
-                       v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
+                       v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
                        v.require_declaration("type_{c_name}")
                        v.add("res->type = &type_{c_name};")
                        v.require_declaration("class_{c_name}")
@@ -679,7 +679,7 @@ class SeparateCompiler
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
                        var mtype_elt = mtype.arguments.first
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
+                       v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
@@ -695,7 +695,7 @@ class SeparateCompiler
                v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
                var res = v.new_named_var(mtype, "self")
                res.is_exact = true
-               v.add("{res} = GC_MALLOC(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
                v.add("{res}->type = type;")
                hardening_live_type(v, "type")
                v.require_declaration("class_{c_name}")
index 304af71..d8bb170 100644 (file)
@@ -268,7 +268,7 @@ class SeparateErasureCompiler
                        self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
                        v.add_decl("/* allocate {mtype} */")
                        v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
-                       v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
+                       v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
                        v.require_declaration("class_{c_name}")
                        v.add("res->class = &class_{c_name};")
                        v.add("res->value = value;")
@@ -289,7 +289,7 @@ class SeparateErasureCompiler
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
                        var mtype_elt = mtype.arguments.first
-                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
+                       v.add("{res} = nit_alloc(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
                        v.add("return {res};")
@@ -303,7 +303,7 @@ class SeparateErasureCompiler
                v.add_decl("{mtype.ctype} NEW_{c_name}(void) \{")
                var res = v.new_named_var(mtype, "self")
                res.is_exact = true
-               v.add("{res} = GC_MALLOC(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
                v.require_declaration("class_{c_name}")
                v.add("{res}->class = &class_{c_name};")
                self.generate_init_attr(v, res, mtype)