From f8c8345a460e043ee5028fd230822cccb25237ac Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 7 Oct 2015 22:35:28 -0400 Subject: [PATCH 001/339] string_type fix --- runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 237de598..d5ffa156 100644 --- a/runtime.c +++ b/runtime.c @@ -2065,7 +2065,7 @@ char *transport(x, gcgen) char *x; int gcgen; dhallocp += len + 1; } forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type); + x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type); return (char *) nx;} case integer_tag: {register integer_type *nx = (integer_type *) allocp; From f73b508eafcfa7491c493e24f595c9c7bf8bd5b1 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 8 Oct 2015 22:00:39 -0400 Subject: [PATCH 002/339] Incorporated experimental changes for GC --- include/cyclone/types.h | 99 ++++++++++++---- runtime.c | 246 ++++++++++++++++++++-------------------- 2 files changed, 199 insertions(+), 146 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 333e7cf0..d5ea1083 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -17,8 +17,61 @@ #include #include -/* Debug GC flag */ -#define DEBUG_GC 0 +/* Define general object type. */ +typedef void *object; + +/* GC data structures */ + +typedef struct gc_free_list_t gc_free_list; +struct gc_free_list_t { + unsigned int size; + gc_free_list *next; +}; + +typedef struct gc_heap_t gc_heap; +struct gc_heap_t { + unsigned int size; + unsigned int chunk_size; // 0 for any size, other and heap will only alloc chunks of that size + unsigned int max_size; + gc_free_list *free_list; // TBD + gc_heap *next; // TBD, linked list is not very efficient, but easy to work with as a start + char *data; +}; + +typedef struct gc_header_type_t gc_header_type; +struct gc_header_type_t { + unsigned char mark; // mark bits (only need 2) + // TODO: forwarding address (probably not needed for mark/sweep), anything else??? +}; +#define is_marked(x) (is_object_type(x) && ((list)x)->hdr.mark) + +/* HEAP definitions */ +// experimenting with a heap based off of the one in Chibi scheme +#define gc_heap_first_block(h) ((object)(h->data + gc_heap_align(gc_free_chunk_size))) +#define gc_heap_last_block(h) ((object)((char*)h->data + h->size - gc_heap_align(gc_free_chunk_size))) +#define gc_heap_end(h) ((object)((char*)h->data + h->size)) +#define gc_free_chunk_size (sizeof(gc_free_list)) + +#define gc_align(n, bits) (((n)+(1<<(bits))-1)&(((unsigned int)-1)-((1<<(bits))-1))) +// 64-bit is 3, 32-bit is 2 +#define gc_word_align(n) gc_align((n), 2) +#define gc_heap_align(n) gc_align(n, 5) + +/* GC prototypes */ +gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); +int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); +void *gc_try_alloc(gc_heap *h, size_t size); +void *gc_alloc(gc_heap *h, size_t size); +size_t gc_allocated_bytes(object obj); +gc_heap *gc_heap_last(gc_heap *h); +size_t gc_heap_total_size(gc_heap *h); +void gc_mark(gc_heap *h, object obj); +size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); +//void gc_collect(gc_heap *h, size_t *sum_freed) + +/* GC debugging flags */ +//#define DEBUG_GC 0 +#define GC_DEBUG_PRINTFS 0 /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 @@ -78,10 +131,6 @@ typedef long tag_type; #define eq(x,y) (x == y) #define nullp(x) (x == NULL) -/* Define general object type. */ - -typedef void *object; - #define type_of(x) (((list) x)->tag) #define forward(x) (((list) x)->cons_car) @@ -105,19 +154,19 @@ typedef void (*function_type)(); typedef void (*function_type_va)(int, object, object, object, ...); /* Define C-variable integration type */ -typedef struct {tag_type tag; object *pvar;} cvar_type; +typedef struct {gc_header_type hdr; tag_type tag; object *pvar;} cvar_type; typedef cvar_type *cvar; #define make_cvar(n,v) cvar_type n; n.tag = cvar_tag; n.pvar = v; /* Define boolean type. */ -typedef struct {const tag_type tag; const char *pname;} boolean_type; +typedef struct {gc_header_type hdr; const tag_type tag; const char *pname;} boolean_type; typedef boolean_type *boolean; #define boolean_pname(x) (((boolean_type *) x)->pname) /* Define symbol type. */ -typedef struct {const tag_type tag; const char *pname; object plist;} symbol_type; +typedef struct {gc_header_type hdr; const tag_type tag; const char *pname; object plist;} symbol_type; typedef symbol_type *symbol; #define symbol_pname(x) (((symbol_type *) x)->pname) @@ -127,16 +176,20 @@ typedef symbol_type *symbol; static object quote_##name = nil; /* Define numeric types */ -typedef struct {tag_type tag; int value;} integer_type; +typedef struct {gc_header_type hdr; tag_type tag; int value;} integer_type; #define make_int(n,v) integer_type n; n.tag = integer_tag; n.value = v; -typedef struct {tag_type tag; double value;} double_type; +typedef struct {gc_header_type hdr; tag_type tag; double value;} double_type; #define make_double(n,v) double_type n; n.tag = double_tag; n.value = v; #define integer_value(x) (((integer_type *) x)->value) #define double_value(x) (((double_type *) x)->value) /* Define string type */ -typedef struct {tag_type tag; char *str;} string_type; +typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_type; +//#define make_cstring(cs, len, s) \ +// string_type cs; cs.tag = string_tag; cs.len = len; cs.str = s; +// TODO: all of the dhalloc below needs to go away for this GC. maybe +// just plan on having strings be allocated separately like vectors. #define make_string(cv,s) string_type cv; cv.tag = string_tag; \ { int len = strlen(s); cv.str = dhallocp; \ if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ @@ -157,19 +210,19 @@ typedef struct {tag_type tag; char *str;} string_type; // consider http://stackoverflow.com/questions/6206893/how-to-implement-char-ready-in-c // TODO: a simple wrapper around FILE may not be good enough long-term // TODO: how exactly mode will be used. need to know r/w, bin/txt -typedef struct {tag_type tag; FILE *fp; int mode;} port_type; +typedef struct {gc_header_type hdr; tag_type tag; FILE *fp; int mode;} port_type; #define make_port(p,f,m) port_type p; p.tag = port_tag; p.fp = f; p.mode = m; /* Vector type */ -typedef struct {tag_type tag; int num_elt; object *elts;} vector_type; +typedef struct {gc_header_type hdr; tag_type tag; int num_elt; object *elts;} vector_type; typedef vector_type *vector; #define make_empty_vector(v) vector_type v; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; /* Define cons type. */ -typedef struct {tag_type tag; object cons_car,cons_cdr;} cons_type; +typedef struct {gc_header_type hdr; tag_type tag; object cons_car,cons_cdr;} cons_type; typedef cons_type *list; #define car(x) (((list) x)->cons_car) @@ -208,13 +261,13 @@ cons_type n; n.tag = cons_tag; n.cons_car = a; n.cons_cdr = d; /* Closure types */ -typedef struct {tag_type tag; function_type fn; int num_args; } macro_type; -typedef struct {tag_type tag; function_type fn; int num_args; } closure0_type; -typedef struct {tag_type tag; function_type fn; int num_args; object elt1;} closure1_type; -typedef struct {tag_type tag; function_type fn; int num_args; object elt1,elt2;} closure2_type; -typedef struct {tag_type tag; function_type fn; int num_args; object elt1,elt2,elt3;} closure3_type; -typedef struct {tag_type tag; function_type fn; int num_args; object elt1,elt2,elt3,elt4;} closure4_type; -typedef struct {tag_type tag; function_type fn; int num_args; int num_elt; object *elts;} closureN_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; } macro_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; } closure0_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; object elt1;} closure1_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; object elt1,elt2;} closure2_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; object elt1,elt2,elt3;} closure3_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; object elt1,elt2,elt3,elt4;} closure4_type; +typedef struct {gc_header_type hdr; tag_type tag; function_type fn; int num_args; int num_elt; object *elts;} closureN_type; typedef closure0_type *closure0; typedef closure1_type *closure1; @@ -247,7 +300,7 @@ typedef closure0_type *macro; #define make_cell(n,a) make_cons(n,a,nil); /* Primitive types */ -typedef struct {tag_type tag; const char *pname; function_type fn;} primitive_type; +typedef struct {gc_header_type hdr; tag_type tag; const char *pname; function_type fn;} primitive_type; typedef primitive_type *primitive; #define defprimitive(name, pname, fnc) \ diff --git a/runtime.c b/runtime.c index d5ffa156..1abcb030 100644 --- a/runtime.c +++ b/runtime.c @@ -101,19 +101,19 @@ object Cyc_global_variables = nil; int _cyc_argc = 0; char **_cyc_argv = NULL; -static symbol_type __EOF = {eof_tag, "", nil}; // symbol_type in lieu of custom type +static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of custom type const object Cyc_EOF = &__EOF; object cell_get(object cell){ return car(cell); } -static boolean_type t_boolean = {boolean_tag, "t"}; -static boolean_type f_boolean = {boolean_tag, "f"}; +static boolean_type t_boolean = {{0}, boolean_tag, "t"}; +static boolean_type f_boolean = {{0}, boolean_tag, "f"}; const object boolean_t = &t_boolean; const object boolean_f = &f_boolean; -static symbol_type Cyc_void_symbol = {symbol_tag, "", nil}; +static symbol_type Cyc_void_symbol = {{0}, symbol_tag, "", nil}; const object quote_void = &Cyc_void_symbol; /* Stack Traces */ @@ -185,7 +185,7 @@ object add_symbol(symbol_type *psym) { } object add_symbol_by_name(const char *name) { - symbol_type sym = {symbol_tag, _strdup(name), nil}; + symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; symbol_type *psym = malloc(sizeof(symbol_type)); memcpy(psym, &sym, sizeof(symbol_type)); return add_symbol(psym); @@ -868,9 +868,9 @@ string_type Cyc_symbol2string(object sym) { object Cyc_string2symbol(object str) { object sym; Cyc_check_str(str); - sym = find_symbol_by_name(symbol_pname(str)); + sym = find_symbol_by_name(string_str(str)); if (!sym) { - sym = add_symbol_by_name(symbol_pname(str)); + sym = add_symbol_by_name(string_str(str)); } return sym; } @@ -2375,122 +2375,122 @@ void dispatch_va(int argc, function_type_va func, object clo, object cont, objec do_dispatch(argc, (function_type)func, clo, b); } -static primitive_type Cyc_91global_91vars_primitive = {primitive_tag, "Cyc-global-vars", &_Cyc_91global_91vars}; -static primitive_type Cyc_91get_91cvar_primitive = {primitive_tag, "Cyc-get-cvar", &_Cyc_91get_91cvar}; -static primitive_type Cyc_91set_91cvar_67_primitive = {primitive_tag, "Cyc-set-cvar!", &_Cyc_91set_91cvar_67}; -static primitive_type Cyc_91cvar_127_primitive = {primitive_tag, "Cyc-cvar?", &_Cyc_91cvar_127}; -static primitive_type Cyc_91has_91cycle_127_primitive = {primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; -static primitive_type _87_primitive = {primitive_tag, "+", &__87}; -static primitive_type _91_primitive = {primitive_tag, "-", &__91}; -static primitive_type _85_primitive = {primitive_tag, "*", &__85}; -static primitive_type _95_primitive = {primitive_tag, "/", &__95}; -static primitive_type _123_primitive = {primitive_tag, "=", &__123}; -static primitive_type _125_primitive = {primitive_tag, ">", &__125}; -static primitive_type _121_primitive = {primitive_tag, "<", &__121}; -static primitive_type _125_123_primitive = {primitive_tag, ">=", &__125_123}; -static primitive_type _121_123_primitive = {primitive_tag, "<=", &__121_123}; -static primitive_type apply_primitive = {primitive_tag, "apply", &_apply}; -static primitive_type _75halt_primitive = {primitive_tag, "%halt", &__75halt}; -static primitive_type exit_primitive = {primitive_tag, "exit", &_cyc_exit}; -static primitive_type Cyc_91current_91exception_91handler_primitive = {primitive_tag, "Cyc_current_exception_handler", &_Cyc_91current_91exception_91handler}; -static primitive_type Cyc_91default_91exception_91handler_primitive = {primitive_tag, "Cyc_default_exception_handler", &_Cyc_91default_91exception_91handler}; -static primitive_type cons_primitive = {primitive_tag, "cons", &_cons}; -static primitive_type cell_91get_primitive = {primitive_tag, "cell-get", &_cell_91get}; -static primitive_type set_91global_67_primitive = {primitive_tag, "set-global!", &_set_91global_67}; -static primitive_type set_91cell_67_primitive = {primitive_tag, "set-cell!", &_set_91cell_67}; -static primitive_type cell_primitive = {primitive_tag, "cell", &_cell}; -static primitive_type eq_127_primitive = {primitive_tag, "eq?", &_eq_127}; -static primitive_type eqv_127_primitive = {primitive_tag, "eqv?", &_eqv_127}; -static primitive_type equal_127_primitive = {primitive_tag, "equal?", &_equal_127}; -static primitive_type assoc_primitive = {primitive_tag, "assoc", &_assoc}; -static primitive_type assq_primitive = {primitive_tag, "assq", &_assq}; -static primitive_type assv_primitive = {primitive_tag, "assv", &_assv}; -static primitive_type member_primitive = {primitive_tag, "member", &_member}; -static primitive_type memq_primitive = {primitive_tag, "memq", &_memq}; -static primitive_type memv_primitive = {primitive_tag, "memv", &_memv}; -static primitive_type length_primitive = {primitive_tag, "length", &_length}; -static primitive_type vector_91length_primitive = {primitive_tag, "vector-length", &_vector_91length}; -static primitive_type set_91car_67_primitive = {primitive_tag, "set-car!", &_set_91car_67}; -static primitive_type set_91cdr_67_primitive = {primitive_tag, "set-cdr!", &_set_91cdr_67}; -static primitive_type car_primitive = {primitive_tag, "car", &_car}; -static primitive_type cdr_primitive = {primitive_tag, "cdr", &_cdr}; -static primitive_type caar_primitive = {primitive_tag, "caar", &_caar}; -static primitive_type cadr_primitive = {primitive_tag, "cadr", &_cadr}; -static primitive_type cdar_primitive = {primitive_tag, "cdar", &_cdar}; -static primitive_type cddr_primitive = {primitive_tag, "cddr", &_cddr}; -static primitive_type caaar_primitive = {primitive_tag, "caaar", &_caaar}; -static primitive_type caadr_primitive = {primitive_tag, "caadr", &_caadr}; -static primitive_type cadar_primitive = {primitive_tag, "cadar", &_cadar}; -static primitive_type caddr_primitive = {primitive_tag, "caddr", &_caddr}; -static primitive_type cdaar_primitive = {primitive_tag, "cdaar", &_cdaar}; -static primitive_type cdadr_primitive = {primitive_tag, "cdadr", &_cdadr}; -static primitive_type cddar_primitive = {primitive_tag, "cddar", &_cddar}; -static primitive_type cdddr_primitive = {primitive_tag, "cdddr", &_cdddr}; -static primitive_type caaaar_primitive = {primitive_tag, "caaaar", &_caaaar}; -static primitive_type caaadr_primitive = {primitive_tag, "caaadr", &_caaadr}; -static primitive_type caadar_primitive = {primitive_tag, "caadar", &_caadar}; -static primitive_type caaddr_primitive = {primitive_tag, "caaddr", &_caaddr}; -static primitive_type cadaar_primitive = {primitive_tag, "cadaar", &_cadaar}; -static primitive_type cadadr_primitive = {primitive_tag, "cadadr", &_cadadr}; -static primitive_type caddar_primitive = {primitive_tag, "caddar", &_caddar}; -static primitive_type cadddr_primitive = {primitive_tag, "cadddr", &_cadddr}; -static primitive_type cdaaar_primitive = {primitive_tag, "cdaaar", &_cdaaar}; -static primitive_type cdaadr_primitive = {primitive_tag, "cdaadr", &_cdaadr}; -static primitive_type cdadar_primitive = {primitive_tag, "cdadar", &_cdadar}; -static primitive_type cdaddr_primitive = {primitive_tag, "cdaddr", &_cdaddr}; -static primitive_type cddaar_primitive = {primitive_tag, "cddaar", &_cddaar}; -static primitive_type cddadr_primitive = {primitive_tag, "cddadr", &_cddadr}; -static primitive_type cdddar_primitive = {primitive_tag, "cdddar", &_cdddar}; -static primitive_type cddddr_primitive = {primitive_tag, "cddddr", &_cddddr}; -static primitive_type char_91_125integer_primitive = {primitive_tag, "char->integer", &_char_91_125integer}; -static primitive_type integer_91_125char_primitive = {primitive_tag, "integer->char", &_integer_91_125char}; -static primitive_type string_91_125number_primitive = {primitive_tag, "string->number", &_string_91_125number}; -static primitive_type string_91length_primitive = {primitive_tag, "string-length", &_string_91length}; -static primitive_type substring_primitive = {primitive_tag, "substring", &_cyc_substring}; -static primitive_type string_91ref_primitive = {primitive_tag, "string-ref", &_cyc_string_91ref}; -static primitive_type string_91set_67_primitive = {primitive_tag, "string-set!", &_cyc_string_91set_67}; -static primitive_type Cyc_91installation_91dir_primitive = {primitive_tag, "Cyc-installation-dir", &_Cyc_91installation_91dir}; -static primitive_type command_91line_91arguments_primitive = {primitive_tag, "command-line-arguments", &_command_91line_91arguments}; -static primitive_type system_primitive = {primitive_tag, "system", &_cyc_system}; -static primitive_type string_91cmp_primitive = {primitive_tag, "string-cmp", &_string_91cmp}; -static primitive_type string_91append_primitive = {primitive_tag, "string-append", &_string_91append}; -static primitive_type list_91_125string_primitive = {primitive_tag, "list->string", &_list_91_125string}; -static primitive_type string_91_125symbol_primitive = {primitive_tag, "string->symbol", &_string_91_125symbol}; -static primitive_type symbol_91_125string_primitive = {primitive_tag, "symbol->string", &_symbol_91_125string}; -static primitive_type number_91_125string_primitive = {primitive_tag, "number->string", &_number_91_125string}; -static primitive_type list_91_125vector_primitive = {primitive_tag, "list-vector", &_list_91_125vector}; -static primitive_type make_91vector_primitive = {primitive_tag, "make-vector", &_make_91vector}; -static primitive_type vector_91ref_primitive = {primitive_tag, "vector-ref", &_vector_91ref}; -static primitive_type vector_91set_67_primitive = {primitive_tag, "vector-set!", &_vector_91set_67}; -static primitive_type boolean_127_primitive = {primitive_tag, "boolean?", &_boolean_127}; -static primitive_type char_127_primitive = {primitive_tag, "char?", &_char_127}; -static primitive_type eof_91object_127_primitive = {primitive_tag, "eof-object?", &_eof_91object_127}; -static primitive_type null_127_primitive = {primitive_tag, "null?", &_null_127}; -static primitive_type number_127_primitive = {primitive_tag, "number?", &_number_127}; -static primitive_type real_127_primitive = {primitive_tag, "real?", &_real_127}; -static primitive_type integer_127_primitive = {primitive_tag, "integer?", &_integer_127}; -static primitive_type pair_127_primitive = {primitive_tag, "pair?", &_pair_127}; -static primitive_type procedure_127_primitive = {primitive_tag, "procedure?", &_procedure_127}; -static primitive_type macro_127_primitive = {primitive_tag, "macro?", &_macro_127}; -static primitive_type port_127_primitive = {primitive_tag, "port?", &_port_127}; -static primitive_type vector_127_primitive = {primitive_tag, "vector?", &_vector_127}; -static primitive_type string_127_primitive = {primitive_tag, "string?", &_string_127}; -static primitive_type symbol_127_primitive = {primitive_tag, "symbol?", &_symbol_127}; -static primitive_type open_91input_91file_primitive = {primitive_tag, "open-input-file", &_open_91input_91file}; -static primitive_type open_91output_91file_primitive = {primitive_tag, "open-output-file", &_open_91output_91file}; -static primitive_type close_91port_primitive = {primitive_tag, "close-port", &_close_91port}; -static primitive_type close_91input_91port_primitive = {primitive_tag, "close-input-port", &_close_91input_91port}; -static primitive_type close_91output_91port_primitive = {primitive_tag, "close-output-port", &_close_91output_91port}; -static primitive_type Cyc_91flush_91output_91port_primitive = {primitive_tag, "Cyc-flush-output-port", &_Cyc_91flush_91output_91port}; -static primitive_type file_91exists_127_primitive = {primitive_tag, "file-exists?", &_file_91exists_127}; -static primitive_type delete_91file_primitive = {primitive_tag, "delete-file", &_delete_91file}; -static primitive_type read_91char_primitive = {primitive_tag, "read-char", &_read_91char}; -static primitive_type peek_91char_primitive = {primitive_tag, "peek-char", &_peek_91char}; -static primitive_type Cyc_91read_91line_primitive = {primitive_tag, "Cyc-read-line", &_Cyc_91read_91line}; -static primitive_type Cyc_91write_primitive = {primitive_tag, "Cyc-write", &_Cyc_91write}; -static primitive_type Cyc_91write_91char_primitive = {primitive_tag, "Cyc-write-char", &_Cyc_91write_91char}; -static primitive_type Cyc_91display_primitive = {primitive_tag, "Cyc-display", &_display}; -static primitive_type call_95cc_primitive = {primitive_tag, "call/cc", &_call_95cc}; +static primitive_type Cyc_91global_91vars_primitive = {{0}, primitive_tag, "Cyc-global-vars", &_Cyc_91global_91vars}; +static primitive_type Cyc_91get_91cvar_primitive = {{0}, primitive_tag, "Cyc-get-cvar", &_Cyc_91get_91cvar}; +static primitive_type Cyc_91set_91cvar_67_primitive = {{0}, primitive_tag, "Cyc-set-cvar!", &_Cyc_91set_91cvar_67}; +static primitive_type Cyc_91cvar_127_primitive = {{0}, primitive_tag, "Cyc-cvar?", &_Cyc_91cvar_127}; +static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; +static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; +static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; +static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; +static primitive_type _95_primitive = {{0}, primitive_tag, "/", &__95}; +static primitive_type _123_primitive = {{0}, primitive_tag, "=", &__123}; +static primitive_type _125_primitive = {{0}, primitive_tag, ">", &__125}; +static primitive_type _121_primitive = {{0}, primitive_tag, "<", &__121}; +static primitive_type _125_123_primitive = {{0}, primitive_tag, ">=", &__125_123}; +static primitive_type _121_123_primitive = {{0}, primitive_tag, "<=", &__121_123}; +static primitive_type apply_primitive = {{0}, primitive_tag, "apply", &_apply}; +static primitive_type _75halt_primitive = {{0}, primitive_tag, "%halt", &__75halt}; +static primitive_type exit_primitive = {{0}, primitive_tag, "exit", &_cyc_exit}; +static primitive_type Cyc_91current_91exception_91handler_primitive = {{0}, primitive_tag, "Cyc_current_exception_handler", &_Cyc_91current_91exception_91handler}; +static primitive_type Cyc_91default_91exception_91handler_primitive = {{0}, primitive_tag, "Cyc_default_exception_handler", &_Cyc_91default_91exception_91handler}; +static primitive_type cons_primitive = {{0}, primitive_tag, "cons", &_cons}; +static primitive_type cell_91get_primitive = {{0}, primitive_tag, "cell-get", &_cell_91get}; +static primitive_type set_91global_67_primitive = {{0}, primitive_tag, "set-global!", &_set_91global_67}; +static primitive_type set_91cell_67_primitive = {{0}, primitive_tag, "set-cell!", &_set_91cell_67}; +static primitive_type cell_primitive = {{0}, primitive_tag, "cell", &_cell}; +static primitive_type eq_127_primitive = {{0}, primitive_tag, "eq?", &_eq_127}; +static primitive_type eqv_127_primitive = {{0}, primitive_tag, "eqv?", &_eqv_127}; +static primitive_type equal_127_primitive = {{0}, primitive_tag, "equal?", &_equal_127}; +static primitive_type assoc_primitive = {{0}, primitive_tag, "assoc", &_assoc}; +static primitive_type assq_primitive = {{0}, primitive_tag, "assq", &_assq}; +static primitive_type assv_primitive = {{0}, primitive_tag, "assv", &_assv}; +static primitive_type member_primitive = {{0}, primitive_tag, "member", &_member}; +static primitive_type memq_primitive = {{0}, primitive_tag, "memq", &_memq}; +static primitive_type memv_primitive = {{0}, primitive_tag, "memv", &_memv}; +static primitive_type length_primitive = {{0}, primitive_tag, "length", &_length}; +static primitive_type vector_91length_primitive = {{0}, primitive_tag, "vector-length", &_vector_91length}; +static primitive_type set_91car_67_primitive = {{0}, primitive_tag, "set-car!", &_set_91car_67}; +static primitive_type set_91cdr_67_primitive = {{0}, primitive_tag, "set-cdr!", &_set_91cdr_67}; +static primitive_type car_primitive = {{0}, primitive_tag, "car", &_car}; +static primitive_type cdr_primitive = {{0}, primitive_tag, "cdr", &_cdr}; +static primitive_type caar_primitive = {{0}, primitive_tag, "caar", &_caar}; +static primitive_type cadr_primitive = {{0}, primitive_tag, "cadr", &_cadr}; +static primitive_type cdar_primitive = {{0}, primitive_tag, "cdar", &_cdar}; +static primitive_type cddr_primitive = {{0}, primitive_tag, "cddr", &_cddr}; +static primitive_type caaar_primitive = {{0}, primitive_tag, "caaar", &_caaar}; +static primitive_type caadr_primitive = {{0}, primitive_tag, "caadr", &_caadr}; +static primitive_type cadar_primitive = {{0}, primitive_tag, "cadar", &_cadar}; +static primitive_type caddr_primitive = {{0}, primitive_tag, "caddr", &_caddr}; +static primitive_type cdaar_primitive = {{0}, primitive_tag, "cdaar", &_cdaar}; +static primitive_type cdadr_primitive = {{0}, primitive_tag, "cdadr", &_cdadr}; +static primitive_type cddar_primitive = {{0}, primitive_tag, "cddar", &_cddar}; +static primitive_type cdddr_primitive = {{0}, primitive_tag, "cdddr", &_cdddr}; +static primitive_type caaaar_primitive = {{0}, primitive_tag, "caaaar", &_caaaar}; +static primitive_type caaadr_primitive = {{0}, primitive_tag, "caaadr", &_caaadr}; +static primitive_type caadar_primitive = {{0}, primitive_tag, "caadar", &_caadar}; +static primitive_type caaddr_primitive = {{0}, primitive_tag, "caaddr", &_caaddr}; +static primitive_type cadaar_primitive = {{0}, primitive_tag, "cadaar", &_cadaar}; +static primitive_type cadadr_primitive = {{0}, primitive_tag, "cadadr", &_cadadr}; +static primitive_type caddar_primitive = {{0}, primitive_tag, "caddar", &_caddar}; +static primitive_type cadddr_primitive = {{0}, primitive_tag, "cadddr", &_cadddr}; +static primitive_type cdaaar_primitive = {{0}, primitive_tag, "cdaaar", &_cdaaar}; +static primitive_type cdaadr_primitive = {{0}, primitive_tag, "cdaadr", &_cdaadr}; +static primitive_type cdadar_primitive = {{0}, primitive_tag, "cdadar", &_cdadar}; +static primitive_type cdaddr_primitive = {{0}, primitive_tag, "cdaddr", &_cdaddr}; +static primitive_type cddaar_primitive = {{0}, primitive_tag, "cddaar", &_cddaar}; +static primitive_type cddadr_primitive = {{0}, primitive_tag, "cddadr", &_cddadr}; +static primitive_type cdddar_primitive = {{0}, primitive_tag, "cdddar", &_cdddar}; +static primitive_type cddddr_primitive = {{0}, primitive_tag, "cddddr", &_cddddr}; +static primitive_type char_91_125integer_primitive = {{0}, primitive_tag, "char->integer", &_char_91_125integer}; +static primitive_type integer_91_125char_primitive = {{0}, primitive_tag, "integer->char", &_integer_91_125char}; +static primitive_type string_91_125number_primitive = {{0}, primitive_tag, "string->number", &_string_91_125number}; +static primitive_type string_91length_primitive = {{0}, primitive_tag, "string-length", &_string_91length}; +static primitive_type substring_primitive = {{0}, primitive_tag, "substring", &_cyc_substring}; +static primitive_type string_91ref_primitive = {{0}, primitive_tag, "string-ref", &_cyc_string_91ref}; +static primitive_type string_91set_67_primitive = {{0}, primitive_tag, "string-set!", &_cyc_string_91set_67}; +static primitive_type Cyc_91installation_91dir_primitive = {{0}, primitive_tag, "Cyc-installation-dir", &_Cyc_91installation_91dir}; +static primitive_type command_91line_91arguments_primitive = {{0}, primitive_tag, "command-line-arguments", &_command_91line_91arguments}; +static primitive_type system_primitive = {{0}, primitive_tag, "system", &_cyc_system}; +static primitive_type string_91cmp_primitive = {{0}, primitive_tag, "string-cmp", &_string_91cmp}; +static primitive_type string_91append_primitive = {{0}, primitive_tag, "string-append", &_string_91append}; +static primitive_type list_91_125string_primitive = {{0}, primitive_tag, "list->string", &_list_91_125string}; +static primitive_type string_91_125symbol_primitive = {{0}, primitive_tag, "string->symbol", &_string_91_125symbol}; +static primitive_type symbol_91_125string_primitive = {{0}, primitive_tag, "symbol->string", &_symbol_91_125string}; +static primitive_type number_91_125string_primitive = {{0}, primitive_tag, "number->string", &_number_91_125string}; +static primitive_type list_91_125vector_primitive = {{0}, primitive_tag, "list-vector", &_list_91_125vector}; +static primitive_type make_91vector_primitive = {{0}, primitive_tag, "make-vector", &_make_91vector}; +static primitive_type vector_91ref_primitive = {{0}, primitive_tag, "vector-ref", &_vector_91ref}; +static primitive_type vector_91set_67_primitive = {{0}, primitive_tag, "vector-set!", &_vector_91set_67}; +static primitive_type boolean_127_primitive = {{0}, primitive_tag, "boolean?", &_boolean_127}; +static primitive_type char_127_primitive = {{0}, primitive_tag, "char?", &_char_127}; +static primitive_type eof_91object_127_primitive = {{0}, primitive_tag, "eof-object?", &_eof_91object_127}; +static primitive_type null_127_primitive = {{0}, primitive_tag, "null?", &_null_127}; +static primitive_type number_127_primitive = {{0}, primitive_tag, "number?", &_number_127}; +static primitive_type real_127_primitive = {{0}, primitive_tag, "real?", &_real_127}; +static primitive_type integer_127_primitive = {{0}, primitive_tag, "integer?", &_integer_127}; +static primitive_type pair_127_primitive = {{0}, primitive_tag, "pair?", &_pair_127}; +static primitive_type procedure_127_primitive = {{0}, primitive_tag, "procedure?", &_procedure_127}; +static primitive_type macro_127_primitive = {{0}, primitive_tag, "macro?", &_macro_127}; +static primitive_type port_127_primitive = {{0}, primitive_tag, "port?", &_port_127}; +static primitive_type vector_127_primitive = {{0}, primitive_tag, "vector?", &_vector_127}; +static primitive_type string_127_primitive = {{0}, primitive_tag, "string?", &_string_127}; +static primitive_type symbol_127_primitive = {{0}, primitive_tag, "symbol?", &_symbol_127}; +static primitive_type open_91input_91file_primitive = {{0}, primitive_tag, "open-input-file", &_open_91input_91file}; +static primitive_type open_91output_91file_primitive = {{0}, primitive_tag, "open-output-file", &_open_91output_91file}; +static primitive_type close_91port_primitive = {{0}, primitive_tag, "close-port", &_close_91port}; +static primitive_type close_91input_91port_primitive = {{0}, primitive_tag, "close-input-port", &_close_91input_91port}; +static primitive_type close_91output_91port_primitive = {{0}, primitive_tag, "close-output-port", &_close_91output_91port}; +static primitive_type Cyc_91flush_91output_91port_primitive = {{0}, primitive_tag, "Cyc-flush-output-port", &_Cyc_91flush_91output_91port}; +static primitive_type file_91exists_127_primitive = {{0}, primitive_tag, "file-exists?", &_file_91exists_127}; +static primitive_type delete_91file_primitive = {{0}, primitive_tag, "delete-file", &_delete_91file}; +static primitive_type read_91char_primitive = {{0}, primitive_tag, "read-char", &_read_91char}; +static primitive_type peek_91char_primitive = {{0}, primitive_tag, "peek-char", &_peek_91char}; +static primitive_type Cyc_91read_91line_primitive = {{0}, primitive_tag, "Cyc-read-line", &_Cyc_91read_91line}; +static primitive_type Cyc_91write_primitive = {{0}, primitive_tag, "Cyc-write", &_Cyc_91write}; +static primitive_type Cyc_91write_91char_primitive = {{0}, primitive_tag, "Cyc-write-char", &_Cyc_91write_91char}; +static primitive_type Cyc_91display_primitive = {{0}, primitive_tag, "Cyc-display", &_display}; +static primitive_type call_95cc_primitive = {{0}, primitive_tag, "call/cc", &_call_95cc}; const object primitive_Cyc_91global_91vars = &Cyc_91global_91vars_primitive; const object primitive_Cyc_91get_91cvar = &Cyc_91get_91cvar_primitive; From 4f74b0c3f707b4be18195cc033400cb981bfa069 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 8 Oct 2015 22:31:42 -0400 Subject: [PATCH 003/339] Added experimental GC code --- Makefile | 5 +- gc.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 gc.c diff --git a/Makefile b/Makefile index f0abc72e..2d285843 100644 --- a/Makefile +++ b/Makefile @@ -45,10 +45,11 @@ libcyclone.so.1: runtime.c include/cyclone/runtime.h gcc -g -c -fPIC runtime.c -o runtime.o gcc -shared -Wl,-soname,libcyclone.so.1 -o libcyclone.so.1.0.1 runtime.o -libcyclone.a: runtime.c include/cyclone/runtime.h include/cyclone/types.h dispatch.c +libcyclone.a: runtime.c include/cyclone/runtime.h include/cyclone/types.h gc.c dispatch.c $(CC) -g -c -Iinclude dispatch.c -o dispatch.o + $(CC) -g -c -Iinclude gc.c -o gc.o $(CC) -g -c -Iinclude -DCYC_INSTALL_DIR=\"$(PREFIX)\" -DCYC_INSTALL_LIB=\"$(LIBDIR)\" -DCYC_INSTALL_INC=\"$(INCDIR)\" -DCYC_INSTALL_SLD=\"$(DATADIR)\" runtime.c -o runtime.o - $(AR) rcs libcyclone.a runtime.o dispatch.o + $(AR) rcs libcyclone.a runtime.o gc.o dispatch.o # Instructions from: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html # Note compiler will have to link to this, eg: #Linking against static library diff --git a/gc.c b/gc.c new file mode 100644 index 00000000..14f84d3a --- /dev/null +++ b/gc.c @@ -0,0 +1,323 @@ +/* TODO: a basic mark-sweep GC + As of now, the GC code is based off the implementation from chibi scheme + + Goals of this project: + - write algorithms + - add test cases + - integrate with types + - integrate with cyclone + - extend to tri-color marking an on-the-fly collection + - etc... + */ + +#include "cyclone/types.h" + +gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) +{ + gc_free_list *free, *next; + gc_heap *h; + // TODO: mmap? + h = malloc(size); + if (!h) return NULL; + h->size = size; + h->chunk_size = chunk_size; + h->max_size = max_size; +printf("DEBUG h->data addr: %p\n", &(h->data)); + h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); +printf("DEBUG h->data addr: %p\n", h->data); + h->next = NULL; + free = h->free_list = (gc_free_list *)h->data; + next = (gc_free_list *)(((char *) free) + gc_heap_align(gc_free_chunk_size)); + free->size = 0; // First one is just a dummy record + free->next = next; + next->size = size - gc_heap_align(gc_free_chunk_size); + next->next = NULL; + return h; +} + +int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) +{ + size_t cur_size, new_size; + gc_heap *h_last = gc_heap_last(h); + cur_size = h_last->size; + new_size = gc_heap_align(((cur_size > size) ? cur_size : size) * 2); + h->next = gc_heap_create(new_size, h->max_size, chunk_size); + return (h->next != NULL); +} + +void *gc_try_alloc(gc_heap *h, size_t size) +{ + gc_free_list *f1, *f2, *f3; + for (; h; h = h->next) { // All heaps + // TODO: chunk size (ignoring for now) + + for (f1 = h->free_list, f2 = f1->next; f2; f1 = f2, f2 = f2->next) { // all free in this heap + if (f2->size > size) { // Big enough for request + // TODO: take whole chunk or divide up f2 (using f3)? + if (f2->size >= (size + gc_heap_align(1) /* min obj size */)) { + f3 = (gc_free_list *) (((char *)f2) + size); + f3->size = f2->size - size; + f3->next = f2->next; + f1->next = f3; + } else { /* Take the whole chunk */ + f1->next = f2->next; + } + // zero-out the header + memset((object)f2, 0, sizeof(gc_header_type)); + return f2; + } + } + } + return NULL; +} + +void *gc_alloc(gc_heap *h, size_t size) +{ + void *result = NULL; + size_t max_freed, sum_freed, total_size; + // TODO: check return value, if null (could not alloc) then + // run a collection and check how much free space there is. if less + // the allowed ratio, try growing heap. + // then try realloc. if cannot alloc now, then throw out of memory error + size = gc_heap_align(size); + //return gc_try_alloc(h, size); + result = gc_try_alloc(h, size); + if (!result) { + // TODO: may want to consider not doing this now, and implementing gc_collect as + // part of the runtime, since we would have all of the roots, stack args, + // etc available there. +// max_freed = gc_collect(h); TODO: this does not work yet! +max_freed = 0; + + total_size = gc_heap_total_size(h); + if (((max_freed < size) || + ((total_size > sum_freed) && + (total_size - sum_freed) > (total_size * 0.75))) // Grow ratio + && ((!h->max_size) || (total_size < h->max_size))) { + gc_grow_heap(h, size, 0); + } + result = gc_try_alloc(h, size); + if (!result) { + fprintf(stderr, "out of memory error allocating %d bytes\n", size); + exit(1); // TODO: throw error??? + } + } +#if GC_DEBUG_PRINTFS + fprintf(stdout, "alloc %p\n", result); +#endif + return result; +} + +size_t gc_allocated_bytes(object obj) +{ + tag_type t; + if (is_value_type(obj)) + return gc_heap_align(1); + t = type_of(obj); + if (t == cons_tag) return gc_heap_align(sizeof(cons_type)); + if (t == integer_tag) return gc_heap_align(sizeof(integer_type)); + +#if GC_DEBUG_PRINTFS + fprintf(stderr, "cannot get size of object %ld\n", t); +#endif + return 0; +} + +gc_heap *gc_heap_last(gc_heap *h) +{ + while (h->next) + h = h->next; + return h; +} + +size_t gc_heap_total_size(gc_heap *h) +{ + size_t total_size = 0; + while(h) { + total_size += h->size; + h = h->next; + } + return total_size; +} + +void gc_mark(gc_heap *h, object obj) +{ + if (!obj || is_marked(obj)) + return; + +#if GC_DEBUG_PRINTFS + fprintf(stdout, "gc_mark %p\n", obj); +#endif + ((list)obj)->hdr.mark = 1; + // TODO: mark heap saves (??) + // could this be a write barrier? + + // Mark objects this one references + if (type_of(obj) == cons_tag) { + gc_mark(h, car(obj)); + gc_mark(h, cdr(obj)); + } + // TODO: will be more work in here the "real" implementation +} + +size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) +{ + // TODO: scan entire heap, freeing objects that have not been marked + size_t freed, max_freed=0, sum_freed=0, size; + object p, end; + gc_free_list *q, *r, *s; + for (; h; h = h->next) { // All heaps + p = gc_heap_first_block(h); + q = h->free_list; + end = gc_heap_end(h); + while (p < end) { + // find preceding/succeeding free list pointers for p + for (r = q->next; r && ((char *)r < (char *)p); q=r, r=r->next); + + if ((char *)r == (char *)p) { // this is a free block, skip it + p = (object) (((char *)p) + r->size); + continue; + } + size = gc_heap_align(gc_allocated_bytes(p)); + +#if GC_DEBUG_PRINTFS + // DEBUG + if (!is_object_type(p)) + fprintf(stderr, "sweep: invalid object at %p", p); + if ((char *)q + q->size > (char *)p) + fprintf(stderr, "bad size at %p < %p + %u", p, q, q->size); + if (r && ((char *)p) + size > (char *)r) + fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); + // END DEBUG +#endif + + if (!is_marked(p)) { +#if GC_DEBUG_PRINTFS + fprintf(stdout, "sweep: object is not marked %p\n", p); +#endif + // free p + sum_freed += size; + if (((((char *)q) + q->size) == (char *)p) && (q != h->free_list)) { + /* merge q with p */ + if (r && r->size && ((((char *)p)+size) == (char *)r)) { + // ... and with r + q->next = r->next; + freed = q->size + size + r->size; + p = (object) (((char *)p) + size + r->size); + } else { + freed = q->size + size; + p = (object) (((char *)p) + size); + } + q->size = freed; + } else { + s = (gc_free_list *)p; + if (r && r->size && ((((char *)p) + size) == (char *)r)) { + // merge p with r + s->size = size + r->size; + s->next = r->next; + q->next = s; + freed = size + r->size; + } else { + s->size = size; + s->next = r; + q->next = s; + freed = size; + } + p = (object) (((char *)p) + freed); + } + if (freed > max_freed) + max_freed = freed; + } else { +#if GC_DEBUG_PRINTFS + fprintf(stdout, "sweep: object is marked %p\n", p); +#endif + ((list)p)->hdr.mark = 0; + p = (object)(((char *)p) + size); + } + } + } + if (sum_freed_ptr) *sum_freed_ptr = sum_freed; + return max_freed; +} + +void gc_collect(gc_heap *h, size_t *sum_freed) +{ + printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + // TODO: mark globals + // TODO: gc_mark(h, h); + // conservative mark? + // weak refs? + // finalize? + gc_sweep(h, sum_freed); + // debug print free stats + // return value from sweep?? +} + +// void gc_init() +// { +// } +// END heap definitions + +/* tri-color GC stuff, we will care about this later... +int colorWhite = 0; +int colorGray = 1; +int colorBlack = 2; +int colorBlue = 3; + +typedef enum {STATUS_ASYNC, STATUS_SYNC1, STATUS_SYNC2} status_type; + +// DLG globals +static void *swept; +static int dirty; +static void *scanned; + +// TODO: mutator actions +// TODO: collector +// TODO: extentions +// TODO: proofs, etc +// TODO: revist design using content from kolodner +*/ + +// int main(int argc, char **argv) { +// int i; +// size_t freed = 0, max_freed = 0; +// gc_heap *h = gc_heap_create(8 * 1024 * 1024, 0, 0); +// void *obj1 = gc_alloc(h, sizeof(cons_type)); +// void *obj2 = gc_alloc(h, sizeof(cons_type)); +// void *objI = gc_alloc(h, sizeof(integer_type)); +// +// for (i = 0; i < 1000000; i++) { +// gc_alloc(h, sizeof(integer_type)); +// gc_alloc(h, sizeof(integer_type)); +// } +// +// // Build up an object graph to test collection... +// ((integer_type *)objI)->hdr.mark = 0; +// ((integer_type *)objI)->tag = integer_tag; +// ((integer_type *)objI)->value = 42; +// +// ((list)obj2)->hdr.mark = 0; +// ((list)obj2)->tag = cons_tag; +// ((list)obj2)->cons_car = objI; +// ((list)obj2)->cons_cdr = NULL; +// +// ((list)obj1)->hdr.mark = 0; +// ((list)obj1)->tag = cons_tag; +// ((list)obj1)->cons_car = obj2; +// ((list)obj1)->cons_cdr = NULL; +// +// printf("(heap: %p size: %d)", h, (unsigned int)gc_heap_total_size(h)); +// gc_mark(h, obj1); +// max_freed = gc_sweep(h, &freed); +// printf("done, freed = %d, max_freed = %d\n", freed, max_freed); +// for (i = 0; i < 10; i++) { +// gc_alloc(h, sizeof(integer_type)); +// gc_alloc(h, sizeof(integer_type)); +// } +// printf("(heap: %p size: %d)", h, (unsigned int)gc_heap_total_size(h)); +// gc_mark(h, obj1); +// max_freed = gc_sweep(h, &freed); +// printf("done, freed = %d, max_freed = %d\n", freed, max_freed); +// +// return 0; +// } From e6b538f5943831db2f7cc7cc08785195675ec970 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 9 Oct 2015 22:11:30 -0400 Subject: [PATCH 004/339] Remove strings from common_type --- include/cyclone/types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index d5ea1083..d05b63fa 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -318,7 +318,6 @@ typedef union { primitive_type primitive_t; integer_type integer_t; double_type double_t; - string_type string_t; } common_type; From 9579a803bfd8a95c42f0f1691af53a2cd27b5e3a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 9 Oct 2015 22:39:21 -0400 Subject: [PATCH 005/339] WIP, changing how strings are allocated --- include/cyclone/types.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index d05b63fa..3380b882 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -186,10 +186,13 @@ typedef struct {gc_header_type hdr; tag_type tag; double value;} double_type; /* Define string type */ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_type; -//#define make_cstring(cs, len, s) \ -// string_type cs; cs.tag = string_tag; cs.len = len; cs.str = s; -// TODO: all of the dhalloc below needs to go away for this GC. maybe -// just plan on having strings be allocated separately like vectors. +// TODO: new way to allocate strings, but this requires changes to +// all functions that allocate strings, the GC, cgen, and maybe more. +#define make_string(cs, len, s) string_type cs; \ +{ cs.tag = string_tag; cs.len = len; \ + cs.str = alloca(sizeof(char) * (len + 1)); \ + strcpy(cs.str, s);} +// TODO: all of the dhalloc below needs to go away... #define make_string(cv,s) string_type cv; cv.tag = string_tag; \ { int len = strlen(s); cv.str = dhallocp; \ if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ From b7d13e6899c934197ced4d27c13e09a3117149da Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 10 Oct 2015 02:21:10 -0400 Subject: [PATCH 006/339] WIP --- include/cyclone/types.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 3380b882..5b3b65b7 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -186,12 +186,13 @@ typedef struct {gc_header_type hdr; tag_type tag; double value;} double_type; /* Define string type */ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_type; -// TODO: new way to allocate strings, but this requires changes to -// all functions that allocate strings, the GC, cgen, and maybe more. -#define make_string(cs, len, s) string_type cs; \ -{ cs.tag = string_tag; cs.len = len; \ - cs.str = alloca(sizeof(char) * (len + 1)); \ - strcpy(cs.str, s);} +//// TODO: new way to allocate strings, but this requires changes to +//// all functions that allocate strings, the GC, cgen, and maybe more. +//// Because these strings are (at least for now) allocaed on the stack. +//#define make_string(cs, len, s) string_type cs; \ +//{ cs.tag = string_tag; cs.len = len; \ +// cs.str = alloca(sizeof(char) * (len + 1)); \ +// strcpy(cs.str, s);} // TODO: all of the dhalloc below needs to go away... #define make_string(cv,s) string_type cv; cv.tag = string_tag; \ { int len = strlen(s); cv.str = dhallocp; \ From d027b85a64d24e5cab4e9963de0575a0e6bb4b12 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 10 Oct 2015 02:22:14 -0400 Subject: [PATCH 007/339] Setting stage to change how strings are stored --- include/cyclone/types.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 5b3b65b7..eb12103d 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -189,23 +189,24 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty //// TODO: new way to allocate strings, but this requires changes to //// all functions that allocate strings, the GC, cgen, and maybe more. //// Because these strings are (at least for now) allocaed on the stack. -//#define make_string(cs, len, s) string_type cs; \ -//{ cs.tag = string_tag; cs.len = len; \ -// cs.str = alloca(sizeof(char) * (len + 1)); \ -// strcpy(cs.str, s);} +#define make_string(cs, len, s) string_type cs; \ +{ cs.tag = string_tag; cs.len = len; \ + cs.str = alloca(sizeof(char) * (len + 1)); \ + strcpy(cs.str, s);} // TODO: all of the dhalloc below needs to go away... -#define make_string(cv,s) string_type cv; cv.tag = string_tag; \ -{ int len = strlen(s); cv.str = dhallocp; \ - if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ - printf("Fatal error: data heap overflow\n"); exit(1); } \ - memcpy(dhallocp, s, len + 1); dhallocp += len + 1; } -#define make_stringn(cv,s,len) string_type cv; cv.tag = string_tag; \ -{ cv.str = dhallocp; \ - if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ - printf("Fatal error: data heap overflow\n"); exit(1); } \ - memcpy(dhallocp, s, len); dhallocp += len; \ - *dhallocp = '\0'; dhallocp += 1;} +//#define make_string(cv,s) string_type cv; cv.tag = string_tag; \ +//{ int len = strlen(s); cv.str = dhallocp; \ +// if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ +// printf("Fatal error: data heap overflow\n"); exit(1); } \ +// memcpy(dhallocp, s, len + 1); dhallocp += len + 1; } +//#define make_stringn(cv,s,len) string_type cv; cv.tag = string_tag; \ +//{ cv.str = dhallocp; \ +// if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ +// printf("Fatal error: data heap overflow\n"); exit(1); } \ +// memcpy(dhallocp, s, len); dhallocp += len; \ +// *dhallocp = '\0'; dhallocp += 1;} +#define string_len(x) (((string_type *) x)->len) #define string_str(x) (((string_type *) x)->str) /* I/O types */ From 72917f4fbb97d0b0c6811cf861a34d38529f3823 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 9 Oct 2015 22:24:43 -0400 Subject: [PATCH 008/339] Converting make_string functions --- include/cyclone/runtime.h | 6 +++--- include/cyclone/types.h | 4 ++++ runtime.c | 32 +++++++++++++++----------------- scheme/cyclone/cgen.sld | 9 +++++++-- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index ee83caa3..acc1492f 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -122,10 +122,10 @@ object Cyc_vector_ref(object v, object k); object Cyc_vector_set(object v, object k, object obj); object Cyc_make_vector(object cont, object len, object fill); object Cyc_list2vector(object cont, object l); -string_type Cyc_number2string(object n) ; -string_type Cyc_symbol2string(object sym) ; +object Cyc_number2string(object cont, object n); +object Cyc_symbol2string(object cont, object sym) ; object Cyc_string2symbol(object str); -string_type Cyc_list2string(object lst); +object Cyc_list2string(object cont, object lst); common_type Cyc_string2number(object str); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); string_type Cyc_string_append(int argc, object str1, ...); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index eb12103d..54c26127 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -193,6 +193,10 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty { cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ strcpy(cs.str, s);} +TODO: make_string_with_len, remove len from above args +#define make_string_noalloc(cs, len, s) string_type cs \ +{ cs.tag = string_tag; cs.len = len; \ + cs.str = s; } // TODO: all of the dhalloc below needs to go away... //#define make_string(cv,s) string_type cv; cv.tag = string_tag; \ //{ int len = strlen(s); cv.str = dhallocp; \ diff --git a/runtime.c b/runtime.c index 1abcb030..7d7e6d0b 100644 --- a/runtime.c +++ b/runtime.c @@ -286,7 +286,7 @@ void Cyc_rt_raise(object err) { exit(1); } void Cyc_rt_raise2(const char *msg, object err) { - make_string(s, msg); + make_string(s, strlen(msg), msg); make_cons(c3, err, nil); make_cons(c2, &s, &c3); make_cons(c1, boolean_f, &c2); @@ -297,7 +297,7 @@ void Cyc_rt_raise2(const char *msg, object err) { exit(1); } void Cyc_rt_raise_msg(const char *err) { - make_string(s, err); + make_string(s, strlen(err), err); Cyc_rt_raise(&s); } /* END exception handler */ @@ -846,7 +846,7 @@ integer_type Cyc_length(object l){ return len; } -string_type Cyc_number2string(object n) { +object Cyc_number2string(object cont, object n) { char buffer[1024]; Cyc_check_num(n); if (type_of(n) == integer_tag) { @@ -856,14 +856,15 @@ string_type Cyc_number2string(object n) { } else { Cyc_rt_raise2("number->string - Unexpected object", n); } - make_string(str, buffer); - return str; + make_string_noalloc(str, strlen(buffer), buffer); + return_closcall1(cont, str); } -string_type Cyc_symbol2string(object sym) { +object Cyc_symbol2string(object cont, object sym) { Cyc_check_sym(sym); - { make_string(str, symbol_pname(sym)); - return str; }} + { char *pname = symbol_pname(sym); + make_string(str, strlen(pname), pname); + return_closcall1(cont, str); }} object Cyc_string2symbol(object str) { object sym; @@ -875,7 +876,7 @@ object Cyc_string2symbol(object str) { return sym; } -string_type Cyc_list2string(object lst){ +object Cyc_list2string(object cont, object lst){ char *buf; int i = 0; integer_type len; @@ -890,8 +891,8 @@ string_type Cyc_list2string(object lst){ } buf[i] = '\0'; - make_string(str, buf); - return str; + { make_string_noalloc(str, i - 1, buf); + return_closcall1(cont, &str);} } common_type Cyc_string2number(object str){ @@ -1773,19 +1774,16 @@ void _list_91_125vector(object cont, object args) { Cyc_list2vector(cont, car(args));} void _list_91_125string(object cont, object args) { Cyc_check_num_args("list->string", 1, args); - { string_type s = Cyc_list2string(car(args)); - return_closcall1(cont, &s);}} + Cyc_list2string(cont, car(args));} void _string_91_125symbol(object cont, object args) { Cyc_check_num_args("string->symbol", 1, args); return_closcall1(cont, Cyc_string2symbol(car(args)));} void _symbol_91_125string(object cont, object args) { Cyc_check_num_args("symbol->string", 1, args); - { string_type s = Cyc_symbol2string(car(args)); - return_closcall1(cont, &s);}} + Cyc_symbol2string(cont, car(args));} void _number_91_125string(object cont, object args) { Cyc_check_num_args("number->string", 1, args); - { string_type s = Cyc_number2string(car(args)); - return_closcall1(cont, &s);}} + Cyc_number2string(cont, car(args));} void _open_91input_91file(object cont, object args) { Cyc_check_num_args("open-input-file", 1, args); { port_type p = Cyc_io_open_input_file(car(args)); diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index b3beba69..cfb52b7d 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -584,7 +584,10 @@ ((eq? p 'apply) "object") ((eq? p 'Cyc-read-line) "object") ((eq? p 'command-line-arguments) "object") + ((eq? p 'number->string) "object") + ((eq? p 'symbol->string) "object") ((eq? p 'make-vector) "object") + ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") (else #f))) @@ -613,12 +616,14 @@ ;; Pass continuation as the function's first parameter? (define (prim:cont? exp) (and (prim? exp) - (member exp '(Cyc-read-line apply command-line-arguments make-vector list->vector)))) + (member exp '(Cyc-read-line apply command-line-arguments number->string + symbol->string list->string make-vector list->vector)))) ;; TODO: this is a hack, right answer is to include information about ;; how many args each primitive is supposed to take (define (prim:cont-has-args? exp) (and (prim? exp) - (member exp '(Cyc-read-line apply make-vector list->vector)))) + (member exp '(Cyc-read-line apply number->string symbol->string + list->string make-vector list->vector)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) From 11d15842ba004e551c4324a2621151cff8ba8c72 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 9 Oct 2015 23:30:47 -0400 Subject: [PATCH 009/339] Added more make string macros and fixed related bugs --- include/cyclone/types.h | 13 ++++++++----- runtime.c | 12 ++++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 54c26127..660ab958 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -189,13 +189,16 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty //// TODO: new way to allocate strings, but this requires changes to //// all functions that allocate strings, the GC, cgen, and maybe more. //// Because these strings are (at least for now) allocaed on the stack. -#define make_string(cs, len, s) string_type cs; \ -{ cs.tag = string_tag; cs.len = len; \ +#define make_string(cs, s) string_type cs; \ +{ int len = strlen(s); cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ strcpy(cs.str, s);} -TODO: make_string_with_len, remove len from above args -#define make_string_noalloc(cs, len, s) string_type cs \ -{ cs.tag = string_tag; cs.len = len; \ +#define make_string_with_len(cs, length, s) string_type cs; \ +{ cs.tag = string_tag; cs.len = length; \ + cs.str = alloca(sizeof(char) * (len + 1)); \ + strcpy(cs.str, s);} +#define make_string_noalloc(cs, length, s) string_type cs; \ +{ cs.tag = string_tag; cs.len = length; \ cs.str = s; } // TODO: all of the dhalloc below needs to go away... //#define make_string(cv,s) string_type cv; cv.tag = string_tag; \ diff --git a/runtime.c b/runtime.c index 7d7e6d0b..cd4de26f 100644 --- a/runtime.c +++ b/runtime.c @@ -286,7 +286,7 @@ void Cyc_rt_raise(object err) { exit(1); } void Cyc_rt_raise2(const char *msg, object err) { - make_string(s, strlen(msg), msg); + make_string(s, msg); make_cons(c3, err, nil); make_cons(c2, &s, &c3); make_cons(c1, boolean_f, &c2); @@ -297,7 +297,7 @@ void Cyc_rt_raise2(const char *msg, object err) { exit(1); } void Cyc_rt_raise_msg(const char *err) { - make_string(s, strlen(err), err); + make_string(s, err); Cyc_rt_raise(&s); } /* END exception handler */ @@ -857,14 +857,14 @@ object Cyc_number2string(object cont, object n) { Cyc_rt_raise2("number->string - Unexpected object", n); } make_string_noalloc(str, strlen(buffer), buffer); - return_closcall1(cont, str); + return_closcall1(cont, &str); } object Cyc_symbol2string(object cont, object sym) { Cyc_check_sym(sym); - { char *pname = symbol_pname(sym); - make_string(str, strlen(pname), pname); - return_closcall1(cont, str); }} + { const char *pname = symbol_pname(sym); + make_string(str, pname); + return_closcall1(cont, &str); }} object Cyc_string2symbol(object str) { object sym; From 09515b2141f5710e885c79a39ea318e468305014 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 10 Oct 2015 22:04:36 -0400 Subject: [PATCH 010/339] Converted substring --- include/cyclone/runtime.h | 2 +- include/cyclone/types.h | 4 ++-- runtime.c | 13 ++++++------- scheme/cyclone/cgen.sld | 7 +++++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index acc1492f..b2e52ec9 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -131,7 +131,7 @@ void dispatch_string_91append(int argc, object clo, object cont, object str1, .. string_type Cyc_string_append(int argc, object str1, ...); string_type Cyc_string_append_va_list(int argc, object str1, va_list ap); integer_type Cyc_string_length(object str); -string_type Cyc_substring(object str, object start, object end); +object Cyc_substring(object cont, object str, object start, object end); object Cyc_string_ref(object str, object k); object Cyc_string_set(object str, object k, object chr); string_type Cyc_installation_dir(); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 660ab958..6ceb3c33 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -193,11 +193,11 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty { int len = strlen(s); cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ strcpy(cs.str, s);} -#define make_string_with_len(cs, length, s) string_type cs; \ +#define make_string_with_len(cs, s, length) string_type cs; \ { cs.tag = string_tag; cs.len = length; \ cs.str = alloca(sizeof(char) * (len + 1)); \ strcpy(cs.str, s);} -#define make_string_noalloc(cs, length, s) string_type cs; \ +#define make_string_noalloc(cs, s, length) string_type cs; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } // TODO: all of the dhalloc below needs to go away... diff --git a/runtime.c b/runtime.c index cd4de26f..5b5ddb0d 100644 --- a/runtime.c +++ b/runtime.c @@ -856,7 +856,7 @@ object Cyc_number2string(object cont, object n) { } else { Cyc_rt_raise2("number->string - Unexpected object", n); } - make_string_noalloc(str, strlen(buffer), buffer); + make_string_noalloc(str, buffer, strlen(buffer)); return_closcall1(cont, &str); } @@ -891,7 +891,7 @@ object Cyc_list2string(object cont, object lst){ } buf[i] = '\0'; - { make_string_noalloc(str, i - 1, buf); + { make_string_noalloc(str, buf, i - 1); return_closcall1(cont, &str);} } @@ -1029,7 +1029,7 @@ object Cyc_string_ref(object str, object k) { return obj_char2obj(raw[idx]); } -string_type Cyc_substring(object str, object start, object end) { +object Cyc_substring(object cont, object str, object start, object end) { const char *raw; int s, e, len; @@ -1053,8 +1053,8 @@ string_type Cyc_substring(object str, object start, object end) { } { - make_stringn(sub, raw + s, e - s); - return sub; + make_string_with_len(sub, raw + s, e - s); + return_closcall1(cont, sub); } } @@ -1716,8 +1716,7 @@ void _string_91length(object cont, object args) { return_closcall1(cont, &i);}} void _cyc_substring(object cont, object args) { Cyc_check_num_args("substring", 3, args); - { string_type s = Cyc_substring(car(args), cadr(args), caddr(args)); - return_closcall1(cont, &s);}} + Cyc_substring(cont, car(args), cadr(args), caddr(args));} void _cyc_string_91set_67(object cont, object args) { Cyc_check_num_args("string-set!", 3, args); { object s = Cyc_string_set(car(args), cadr(args), caddr(args)); diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index cfb52b7d..f0f1d899 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -586,6 +586,7 @@ ((eq? p 'command-line-arguments) "object") ((eq? p 'number->string) "object") ((eq? p 'symbol->string) "object") + ((eq? p 'substring) "object") ((eq? p 'make-vector) "object") ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") @@ -617,13 +618,15 @@ (define (prim:cont? exp) (and (prim? exp) (member exp '(Cyc-read-line apply command-line-arguments number->string - symbol->string list->string make-vector list->vector)))) + symbol->string list->string substring + make-vector list->vector)))) ;; TODO: this is a hack, right answer is to include information about ;; how many args each primitive is supposed to take (define (prim:cont-has-args? exp) (and (prim? exp) (member exp '(Cyc-read-line apply number->string symbol->string - list->string make-vector list->vector)))) + list->string substring + make-vector list->vector)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) From 53aad98d710c8cd0d4f9596232826c74484e9c8c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 10 Oct 2015 22:18:54 -0400 Subject: [PATCH 011/339] Converted Cyc-installation-dir --- include/cyclone/runtime.h | 4 +--- runtime.c | 15 +++++++-------- scheme/cyclone/cgen.sld | 5 +++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index b2e52ec9..9141b406 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -92,8 +92,6 @@ object apply(object cont, object func, object args); void Cyc_apply(int argc, closure cont, object prim, ...); integer_type Cyc_string_cmp(object str1, object str2); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); -string_type Cyc_string_append(int argc, object str1, ...); -string_type Cyc_string_append_va_list(int, object, va_list); list mcons(object,object); cvar_type *mcvar(object *var); object Cyc_display(object, FILE *port); @@ -134,7 +132,7 @@ integer_type Cyc_string_length(object str); object Cyc_substring(object cont, object str, object start, object end); object Cyc_string_ref(object str, object k); object Cyc_string_set(object str, object k, object chr); -string_type Cyc_installation_dir(); +object Cyc_installation_dir(object cont, object type); object Cyc_command_line_arguments(object cont); integer_type Cyc_system(object cmd); integer_type Cyc_char2integer(object chr); diff --git a/runtime.c b/runtime.c index 5b5ddb0d..fb4cb665 100644 --- a/runtime.c +++ b/runtime.c @@ -1054,7 +1054,7 @@ object Cyc_substring(object cont, object str, object start, object end) { { make_string_with_len(sub, raw + s, e - s); - return_closcall1(cont, sub); + return_closcall1(cont, &sub); } } @@ -1062,28 +1062,28 @@ object Cyc_substring(object cont, object str, object start, object end) { * Return directory where cyclone is installed. * This is configured via the makefile during a build. */ -string_type Cyc_installation_dir(object type) { +object Cyc_installation_dir(object cont, object type) { if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "sld", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_SLD); make_string(str, buf); - return str; + return_closcall1(cont, &str); } else if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "lib", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_LIB); make_string(str, buf); - return str; + return_closcall1(cont, &str); } else if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "inc", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_INC); make_string(str, buf); - return str; + return_closcall1(cont, &str); } else { make_string(str, CYC_INSTALL_DIR); - return str; + return_closcall1(cont, &str); } } @@ -1727,8 +1727,7 @@ void _cyc_string_91ref(object cont, object args) { return_closcall1(cont, c); }} void _Cyc_91installation_91dir(object cont, object args) { Cyc_check_num_args("Cyc-installation-dir", 1, args); - { string_type dir = Cyc_installation_dir(car(args)); - return_closcall1(cont, &dir);}} + Cyc_installation_dir(cont, car(args));} void _command_91line_91arguments(object cont, object args) { object cmdline = Cyc_command_line_arguments(cont); return_closcall1(cont, cmdline); } diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index f0f1d899..7d5075d7 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -590,6 +590,7 @@ ((eq? p 'make-vector) "object") ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") + ((eq? p 'Cyc-installation-dir) "object") (else #f))) ;; Determine if primitive creates a C variable @@ -619,14 +620,14 @@ (and (prim? exp) (member exp '(Cyc-read-line apply command-line-arguments number->string symbol->string list->string substring - make-vector list->vector)))) + make-vector list->vector Cyc-installation-dir)))) ;; TODO: this is a hack, right answer is to include information about ;; how many args each primitive is supposed to take (define (prim:cont-has-args? exp) (and (prim? exp) (member exp '(Cyc-read-line apply number->string symbol->string list->string substring - make-vector list->vector)))) + make-vector list->vector Cyc-installation-dir)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) From ce95299919dd4197583e8d8a0969872bc0269221 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 10 Oct 2015 23:28:55 -0400 Subject: [PATCH 012/339] Removed old type mappings --- scheme/cyclone/cgen.sld | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 7d5075d7..74cb0454 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -567,20 +567,15 @@ ((eq? p 'length) "integer_type") ((eq? p 'vector-length) "integer_type") ((eq? p 'char->integer) "integer_type") - ((eq? p 'Cyc-installation-dir) "string_type") ((eq? p 'system) "integer_type") ((eq? p '+) "common_type") ((eq? p '-) "common_type") ((eq? p '*) "common_type") ((eq? p '/) "common_type") ((eq? p 'string->number) "common_type") - ((eq? p 'list->string) "string_type") ((eq? p 'string-cmp) "integer_type") ((eq? p 'string-append) "string_type") - ((eq? p 'symbol->string) "string_type") - ((eq? p 'number->string) "string_type") ((eq? p 'string-length) "integer_type") - ((eq? p 'substring) "string_type") ((eq? p 'apply) "object") ((eq? p 'Cyc-read-line) "object") ((eq? p 'command-line-arguments) "object") From 57ebc43e562cd1e3918c93b998e5db0c27e3258e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 12 Oct 2015 22:38:09 -0400 Subject: [PATCH 013/339] Fix off-by-one error --- runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index fb4cb665..1c7a81f8 100644 --- a/runtime.c +++ b/runtime.c @@ -891,7 +891,7 @@ object Cyc_list2string(object cont, object lst){ } buf[i] = '\0'; - { make_string_noalloc(str, buf, i - 1); + { make_string_noalloc(str, buf, i); return_closcall1(cont, &str);} } From 2a058a5204fe1854ff780fb62c5c5a155ed32534 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 12 Oct 2015 22:39:29 -0400 Subject: [PATCH 014/339] WIP - compile string_type changes --- TODO | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/TODO b/TODO index 93ced0d0..d3976d22 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,13 @@ +Instructions to rebuild cyclone after changing string_type returns to object returns: +sudo ls ; cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ +make clean ; make && sudo make install +sudo make install-includes +cp ../cyclone-bootstrap/dispatch.c . +make libcyclone.a +sudo make install-libs +make clean ; make && sudo make install + + Roadmap: - Add macro support, ideally including some level of hygiene - Code cleanup - need to take care of accumulated cruft before release. also, can we profile to make things any faster? From ba167dfcd3b261845f44c1e7f3b5c05b1ec519a4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 02:33:42 -0400 Subject: [PATCH 015/339] notes --- TODO | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index d3976d22..25235323 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,13 @@ Instructions to rebuild cyclone after changing string_type returns to object returns: -sudo ls ; cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ -make clean ; make && sudo make install -sudo make install-includes -cp ../cyclone-bootstrap/dispatch.c . -make libcyclone.a -sudo make install-libs -make clean ; make && sudo make install +shouldn't it just be a matter of compiling cgen and dumping that and the includes/libs into bootstrap?? +;sudo ls ; cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ +;make clean ; make && sudo make install +;sudo make install-includes +;cp ../cyclone-bootstrap/dispatch.c . +;make libcyclone.a +;sudo make install-libs +;make clean ; make && sudo make install +at this point, cyclone crashes when compiling the test suite. I think there may be a problem with there being a disconnect between the old/new versions of compiled code, runtime libs, etc. however, the generated c files have the change. so it should be possible to bootstrap using them... Roadmap: From 85cff010b618479d59710da13c1bfda4a8be3d92 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 02:41:35 -0400 Subject: [PATCH 016/339] Added TODO's for GC of strings, now that storage has changed --- runtime.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runtime.c b/runtime.c index 1c7a81f8..8eaf2e2b 100644 --- a/runtime.c +++ b/runtime.c @@ -2050,6 +2050,9 @@ char *transport(x, gcgen) char *x; int gcgen; case string_tag: {register string_type *nx = (string_type *) allocp; type_of(nx) = string_tag; +TODO: below is changing, now we will need to always copy the cstring +along with the string_type. need to be careful of any off-by-one errors +here... if (gcgen == 0) { // Minor, data heap is not relocated nx->str = ((string_type *)x)->str; @@ -2278,6 +2281,10 @@ void GC_loop(int major, closure cont, object *ans, int num_ans) printf("DEBUG transport string \n"); #endif scanp += sizeof(string_type); break; +TODO: cstring is now after string_type, so need to skip that, too. +stack allocations should be OK since we are only scanning the newspace here, +but should double-check that... (though we are not able to even scan the +stack so should be fine) case integer_tag: #if DEBUG_GC printf("DEBUG transport integer \n"); From e6880850bc12f2732c67fe4dff875890a714d757 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 12 Oct 2015 21:57:30 -0400 Subject: [PATCH 017/339] Update how GC handles strings in memory --- include/cyclone/types.h | 3 ++- runtime.c | 48 ++++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 6ceb3c33..1e92c558 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -40,7 +40,8 @@ struct gc_heap_t { typedef struct gc_header_type_t gc_header_type; struct gc_header_type_t { - unsigned char mark; // mark bits (only need 2) + //unsigned char mark; // mark bits (only need 2) + unsigned int mark; // mark bits (only need 2) // TODO: forwarding address (probably not needed for mark/sweep), anything else??? }; #define is_marked(x) (is_object_type(x) && ((list)x)->hdr.mark) diff --git a/runtime.c b/runtime.c index 8eaf2e2b..828475d7 100644 --- a/runtime.c +++ b/runtime.c @@ -2049,22 +2049,26 @@ char *transport(x, gcgen) char *x; int gcgen; return (char *) nx;} case string_tag: {register string_type *nx = (string_type *) allocp; + int str_size = gc_word_align(((string_type *)x)->len + 1); type_of(nx) = string_tag; -TODO: below is changing, now we will need to always copy the cstring -along with the string_type. need to be careful of any off-by-one errors -here... - if (gcgen == 0) { - // Minor, data heap is not relocated - nx->str = ((string_type *)x)->str; - } else { - // Major collection, data heap is moving - nx->str = dhallocp; - int len = strlen(((string_type *) x)->str); - memcpy(dhallocp, ((string_type *) x)->str, len + 1); - dhallocp += len + 1; - } + nx->len = ((string_type *)x)->len; + nx->str = ((char *)nx) + sizeof(string_type); + memcpy(nx->str, ((string_type *)x)->str, nx->len + 1); +//TODO: below is changing, now we will need to always copy the cstring +//along with the string_type. need to be careful of any off-by-one errors +//here... +// if (gcgen == 0) { +// // Minor, data heap is not relocated +// nx->str = ((string_type *)x)->str; +// } else { +// // Major collection, data heap is moving +// nx->str = dhallocp; +// int len = strlen(((string_type *) x)->str); +// memcpy(dhallocp, ((string_type *) x)->str, len + 1); +// dhallocp += len + 1; +// } forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type); + x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size; return (char *) nx;} case integer_tag: {register integer_type *nx = (integer_type *) allocp; @@ -2276,15 +2280,19 @@ void GC_loop(int major, closure cont, object *ans, int num_ans) scanp += sizeof(vector_type) + sizeof(object) * n; } break; - case string_tag: + case string_tag: { #if DEBUG_GC printf("DEBUG transport string \n"); #endif - scanp += sizeof(string_type); break; -TODO: cstring is now after string_type, so need to skip that, too. -stack allocations should be OK since we are only scanning the newspace here, -but should double-check that... (though we are not able to even scan the -stack so should be fine) + string_type *x = (string_type *)scanp; + scanp += sizeof(string_type); + scanp += gc_word_align(x->len + 1); + break; + } +//TODO: cstring is now after string_type, so need to skip that, too. +//stack allocations should be OK since we are only scanning the newspace here, +//but should double-check that... (though we are not able to even scan the +//stack so should be fine) case integer_tag: #if DEBUG_GC printf("DEBUG transport integer \n"); From 1bc65d99cdd2f37d2c74c592876f86bc17ab67e9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 12 Oct 2015 22:49:31 -0400 Subject: [PATCH 018/339] Working on converting string_append to call into cont --- include/cyclone/runtime.h | 3 +- runtime.c | 78 +++++++++++++++++---------------------- scheme/cyclone/cgen.sld | 6 +-- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 9141b406..10291097 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -126,8 +126,7 @@ object Cyc_string2symbol(object str); object Cyc_list2string(object cont, object lst); common_type Cyc_string2number(object str); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); -string_type Cyc_string_append(int argc, object str1, ...); -string_type Cyc_string_append_va_list(int argc, object str1, va_list ap); +object Cyc_string_append(int argc, object cont, object str1, ...); integer_type Cyc_string_length(object str); object Cyc_substring(object cont, object str, object start, object end); object Cyc_string_ref(object str, object k); diff --git a/runtime.c b/runtime.c index 828475d7..5b87b259 100644 --- a/runtime.c +++ b/runtime.c @@ -930,59 +930,47 @@ integer_type Cyc_string_cmp(object str1, object str2) { } } -void dispatch_string_91append(int argc, object clo, object cont, object str1, ...) { +#define Cyc_string_append_va_list(argc) { \ + int i = 0, total_len = 1; \ + int *len = alloca(sizeof(int) * argc); \ + char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); \ + object tmp; \ + if (argc > 0) { \ + Cyc_check_str(str1); \ + str[i] = ((string_type *)str1)->str; \ + len[i] = strlen(str[i]); \ + total_len += len[i]; \ + } \ + for (i = 1; i < argc; i++) { \ + tmp = va_arg(ap, object); \ + Cyc_check_str(tmp); \ + str[i] = ((string_type *)tmp)->str; \ + len[i] = strlen(str[i]); \ + total_len += len[i]; \ + } \ + buffer = bufferp = alloca(sizeof(char) * total_len); \ + for (i = 0; i < argc; i++) { \ + memcpy(bufferp, str[i], len[i]); \ + bufferp += len[i]; \ + } \ + *bufferp = '\0'; \ + make_string(result, buffer); \ + va_end(ap); \ + return_closcall1(cont, &result); \ +} + +void dispatch_string_91append(int _argc, object clo, object cont, object str1, ...) { string_type result; va_list ap; va_start(ap, str1); - result = Cyc_string_append_va_list(argc - 1, str1, ap); - va_end(ap); - return_closcall1(cont, &result); + Cyc_string_append_va_list(_argc - 1); } -string_type Cyc_string_append(int argc, object str1, ...) { +object Cyc_string_append(int _argc, object cont, object str1, ...) { string_type result; va_list ap; va_start(ap, str1); - result = Cyc_string_append_va_list(argc, str1, ap); - va_end(ap); - return result; -} - -string_type Cyc_string_append_va_list(int argc, object str1, va_list ap) { - // TODO: one way to do this, perhaps not the most efficient: - // compute lengths of the strings, - // store lens and str ptrs - // allocate buffer, memcpy each str to buffer - // make_string using buffer - - int i = 0, total_len = 1; // for null char - int *len = alloca(sizeof(int) * argc); - char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); - object tmp; - - if (argc > 0) { - Cyc_check_str(str1); - str[i] = ((string_type *)str1)->str; - len[i] = strlen(str[i]); - total_len += len[i]; - } - - for (i = 1; i < argc; i++) { - tmp = va_arg(ap, object); - Cyc_check_str(tmp); - str[i] = ((string_type *)tmp)->str; - len[i] = strlen(str[i]); - total_len += len[i]; - } - - buffer = bufferp = alloca(sizeof(char) * total_len); - for (i = 0; i < argc; i++) { - memcpy(bufferp, str[i], len[i]); - bufferp += len[i]; - } - *bufferp = '\0'; - make_string(result, buffer); - return result; + Cyc_string_append_va_list(_argc); } integer_type Cyc_string_length(object str) { diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 74cb0454..b1d7be0d 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -574,7 +574,7 @@ ((eq? p '/) "common_type") ((eq? p 'string->number) "common_type") ((eq? p 'string-cmp) "integer_type") - ((eq? p 'string-append) "string_type") + ((eq? p 'string-append) "object") ((eq? p 'string-length) "integer_type") ((eq? p 'apply) "object") ((eq? p 'Cyc-read-line) "object") @@ -614,14 +614,14 @@ (define (prim:cont? exp) (and (prim? exp) (member exp '(Cyc-read-line apply command-line-arguments number->string - symbol->string list->string substring + symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) ;; TODO: this is a hack, right answer is to include information about ;; how many args each primitive is supposed to take (define (prim:cont-has-args? exp) (and (prim? exp) (member exp '(Cyc-read-line apply number->string symbol->string - list->string substring + list->string substring string-append make-vector list->vector Cyc-installation-dir)))) ;; Pass an integer arg count as the function's first parameter? From 94366294da1aa461b8483eb687a843cbea2c8b22 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 12 Oct 2015 22:56:51 -0400 Subject: [PATCH 019/339] Added TODO --- scheme/cyclone/cgen.sld | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index b1d7be0d..c8a79ee4 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -610,6 +610,13 @@ Cyc-read-line cons length vector-length cell)))) +TODO: how to fix this up to generate argc after cont? +or alternatively, maybe we say screw it and just reverse the order of +args in the runtime function... but that's not ideal since we do it differently +everywhere else. will it cause problems to have a special case????? +object c_732612 = Cyc_string_append((closure)&c_732599, 2,&c_732613, r_73276); +return_closcall1((closure)&c_732599, c_732612);; + ;; Pass continuation as the function's first parameter? (define (prim:cont? exp) (and (prim? exp) From c332e84eacb63a785ec1598a6e75ababc8734627 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 21:50:06 -0400 Subject: [PATCH 020/339] Switched order of parameters in Cyc_string_append --- include/cyclone/runtime.h | 2 +- runtime.c | 2 +- scheme/cyclone/cgen.sld | 7 ------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 10291097..78b2d12c 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -126,7 +126,7 @@ object Cyc_string2symbol(object str); object Cyc_list2string(object cont, object lst); common_type Cyc_string2number(object str); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); -object Cyc_string_append(int argc, object cont, object str1, ...); +object Cyc_string_append(object cont, int argc, object str1, ...); integer_type Cyc_string_length(object str); object Cyc_substring(object cont, object str, object start, object end); object Cyc_string_ref(object str, object k); diff --git a/runtime.c b/runtime.c index 5b87b259..d4658cf9 100644 --- a/runtime.c +++ b/runtime.c @@ -966,7 +966,7 @@ void dispatch_string_91append(int _argc, object clo, object cont, object str1, . Cyc_string_append_va_list(_argc - 1); } -object Cyc_string_append(int _argc, object cont, object str1, ...) { +object Cyc_string_append(object cont, int _argc, object str1, ...) { string_type result; va_list ap; va_start(ap, str1); diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index c8a79ee4..b1d7be0d 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -610,13 +610,6 @@ Cyc-read-line cons length vector-length cell)))) -TODO: how to fix this up to generate argc after cont? -or alternatively, maybe we say screw it and just reverse the order of -args in the runtime function... but that's not ideal since we do it differently -everywhere else. will it cause problems to have a special case????? -object c_732612 = Cyc_string_append((closure)&c_732599, 2,&c_732613, r_73276); -return_closcall1((closure)&c_732599, c_732612);; - ;; Pass continuation as the function's first parameter? (define (prim:cont? exp) (and (prim? exp) From 338d46ac9ec8f3bd0a1635c3454b756c2b39297a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 22:32:17 -0400 Subject: [PATCH 021/339] Added notes --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 25235323..6136b57c 100644 --- a/TODO +++ b/TODO @@ -11,6 +11,7 @@ at this point, cyclone crashes when compiling the test suite. I think there may Roadmap: + - Make it easier to work with multiple copies of cyclone. for example, maybe an env variable could be used to point a local copy of cyclone to the current directory for resources, instead of /usr/local/ - Add macro support, ideally including some level of hygiene - Code cleanup - need to take care of accumulated cruft before release. also, can we profile to make things any faster? - Target r7rs support (coordinate with feature list) From 722b303bb73ef9f33ecd493ca52e61e42f53d1cf Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 22:46:51 -0400 Subject: [PATCH 022/339] Bugfixes --- include/cyclone/types.h | 8 +++++--- runtime.c | 16 +++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 1e92c558..4b55a1d6 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -193,11 +193,13 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty #define make_string(cs, s) string_type cs; \ { int len = strlen(s); cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ - strcpy(cs.str, s);} + memcpy(cs.str, s, len + 1);} #define make_string_with_len(cs, s, length) string_type cs; \ -{ cs.tag = string_tag; cs.len = length; \ +{ int len = length; \ + cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ - strcpy(cs.str, s);} + memcpy(cs.str, s, len); \ + cs.str[len] = '\0';} #define make_string_noalloc(cs, s, length) string_type cs; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } diff --git a/runtime.c b/runtime.c index 5b87b259..5047ce03 100644 --- a/runtime.c +++ b/runtime.c @@ -856,7 +856,8 @@ object Cyc_number2string(object cont, object n) { } else { Cyc_rt_raise2("number->string - Unexpected object", n); } - make_string_noalloc(str, buffer, strlen(buffer)); + //make_string_noalloc(str, buffer, strlen(buffer)); + make_string(str, buffer); return_closcall1(cont, &str); } @@ -891,7 +892,8 @@ object Cyc_list2string(object cont, object lst){ } buf[i] = '\0'; - { make_string_noalloc(str, buf, i); + //{ make_string_noalloc(str, buf, i); + { make_string(str, buf); return_closcall1(cont, &str);} } @@ -960,14 +962,12 @@ integer_type Cyc_string_cmp(object str1, object str2) { } void dispatch_string_91append(int _argc, object clo, object cont, object str1, ...) { - string_type result; va_list ap; va_start(ap, str1); Cyc_string_append_va_list(_argc - 1); } -object Cyc_string_append(int _argc, object cont, object str1, ...) { - string_type result; +object Cyc_string_append(object cont, int _argc, object str1, ...) { va_list ap; va_start(ap, str1); Cyc_string_append_va_list(_argc); @@ -1042,6 +1042,12 @@ object Cyc_substring(object cont, object str, object start, object end) { { make_string_with_len(sub, raw + s, e - s); +//string_type sub; +//{ int len = e - s; +// sub.tag = string_tag; sub.len = len; +// sub.str = alloca(sizeof(char) * (len + 1)); +// memcpy(sub.str, raw + s, len); +// sub.str[len + 1] = '\0';} return_closcall1(cont, &sub); } } From 738fe0439ec5027bad549851e2a0a2b6bc12e905 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 13 Oct 2015 22:51:25 -0400 Subject: [PATCH 023/339] Bug fixes --- include/cyclone/types.h | 8 +++++--- runtime.c | 14 ++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 1e92c558..9d9ce1df 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -193,11 +193,13 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty #define make_string(cs, s) string_type cs; \ { int len = strlen(s); cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ - strcpy(cs.str, s);} + memcpy(cs.str, s, len + 1);} #define make_string_with_len(cs, s, length) string_type cs; \ -{ cs.tag = string_tag; cs.len = length; \ +{ int len = length; \ + cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ - strcpy(cs.str, s);} + memcpy(cs.str, s, len); \ + cs.str[len + 1] = '\0';} #define make_string_noalloc(cs, s, length) string_type cs; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } diff --git a/runtime.c b/runtime.c index d4658cf9..5047ce03 100644 --- a/runtime.c +++ b/runtime.c @@ -856,7 +856,8 @@ object Cyc_number2string(object cont, object n) { } else { Cyc_rt_raise2("number->string - Unexpected object", n); } - make_string_noalloc(str, buffer, strlen(buffer)); + //make_string_noalloc(str, buffer, strlen(buffer)); + make_string(str, buffer); return_closcall1(cont, &str); } @@ -891,7 +892,8 @@ object Cyc_list2string(object cont, object lst){ } buf[i] = '\0'; - { make_string_noalloc(str, buf, i); + //{ make_string_noalloc(str, buf, i); + { make_string(str, buf); return_closcall1(cont, &str);} } @@ -960,14 +962,12 @@ integer_type Cyc_string_cmp(object str1, object str2) { } void dispatch_string_91append(int _argc, object clo, object cont, object str1, ...) { - string_type result; va_list ap; va_start(ap, str1); Cyc_string_append_va_list(_argc - 1); } object Cyc_string_append(object cont, int _argc, object str1, ...) { - string_type result; va_list ap; va_start(ap, str1); Cyc_string_append_va_list(_argc); @@ -1042,6 +1042,12 @@ object Cyc_substring(object cont, object str, object start, object end) { { make_string_with_len(sub, raw + s, e - s); +//string_type sub; +//{ int len = e - s; +// sub.tag = string_tag; sub.len = len; +// sub.str = alloca(sizeof(char) * (len + 1)); +// memcpy(sub.str, raw + s, len); +// sub.str[len + 1] = '\0';} return_closcall1(cont, &sub); } } From e99301024a164774a48a70b2eb0ad082eee29fa6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 14 Oct 2015 22:56:25 -0400 Subject: [PATCH 024/339] Added notes for switching GC's --- runtime.c | 864 +++++++++++++++++++++++++++++------------------------- 1 file changed, 471 insertions(+), 393 deletions(-) diff --git a/runtime.c b/runtime.c index 5047ce03..b957465b 100644 --- a/runtime.c +++ b/runtime.c @@ -1946,406 +1946,484 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { apply(cont, prim, (object)&args[0]); } -/** - * Copy an object to the GC heap - */ -char *transport(x, gcgen) char *x; int gcgen; -{ - if (nullp(x)) return x; - if (obj_is_char(x)) return x; -#if DEBUG_GC - printf("entered transport "); - printf("transport %ld\n", type_of(x)); -#endif - switch (type_of(x)) - {case cons_tag: - {register list nx = (list) allocp; - type_of(nx) = cons_tag; car(nx) = car(x); cdr(nx) = cdr(x); - forward(x) = nx; type_of(x) = forward_tag; - allocp = ((char *) nx)+sizeof(cons_type); - return (char *) nx;} - case macro_tag: - {register macro nx = (macro) allocp; - type_of(nx) = macro_tag; nx->fn = ((macro) x)->fn; - nx->num_args = ((macro) x)->num_args; - forward(x) = nx; type_of(x) = forward_tag; - allocp = ((char *) nx)+sizeof(macro_type); - return (char *) nx;} - case closure0_tag: - {register closure0 nx = (closure0) allocp; - type_of(nx) = closure0_tag; nx->fn = ((closure0) x)->fn; - nx->num_args = ((closure0) x)->num_args; - forward(x) = nx; type_of(x) = forward_tag; - allocp = ((char *) nx)+sizeof(closure0_type); - return (char *) nx;} - case closure1_tag: - {register closure1 nx = (closure1) allocp; - type_of(nx) = closure1_tag; nx->fn = ((closure1) x)->fn; - nx->num_args = ((closure1) x)->num_args; - nx->elt1 = ((closure1) x)->elt1; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(closure1_type); - return (char *) nx;} - case closure2_tag: - {register closure2 nx = (closure2) allocp; - type_of(nx) = closure2_tag; nx->fn = ((closure2) x)->fn; - nx->num_args = ((closure2) x)->num_args; - nx->elt1 = ((closure2) x)->elt1; - nx->elt2 = ((closure2) x)->elt2; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(closure2_type); - return (char *) nx;} - case closure3_tag: - {register closure3 nx = (closure3) allocp; - type_of(nx) = closure3_tag; nx->fn = ((closure3) x)->fn; - nx->num_args = ((closure3) x)->num_args; - nx->elt1 = ((closure3) x)->elt1; - nx->elt2 = ((closure3) x)->elt2; - nx->elt3 = ((closure3) x)->elt3; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(closure3_type); - return (char *) nx;} - case closure4_tag: - {register closure4 nx = (closure4) allocp; - type_of(nx) = closure4_tag; nx->fn = ((closure4) x)->fn; - nx->num_args = ((closure4) x)->num_args; - nx->elt1 = ((closure4) x)->elt1; - nx->elt2 = ((closure4) x)->elt2; - nx->elt3 = ((closure4) x)->elt3; - nx->elt4 = ((closure4) x)->elt4; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(closure4_type); - return (char *) nx;} - case closureN_tag: - {register closureN nx = (closureN) allocp; - int i; - type_of(nx) = closureN_tag; nx->fn = ((closureN) x)->fn; - nx->num_args = ((closureN) x)->num_args; - nx->num_elt = ((closureN) x)->num_elt; - nx->elts = (object *)(((char *)nx) + sizeof(closureN_type)); - for (i = 0; i < nx->num_elt; i++) { - nx->elts[i] = ((closureN) x)->elts[i]; - } - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(closureN_type) + sizeof(object) * nx->num_elt; - return (char *) nx;} - case vector_tag: - {register vector nx = (vector) allocp; - int i; - type_of(nx) = vector_tag; - nx->num_elt = ((vector) x)->num_elt; - nx->elts = (object *)(((char *)nx) + sizeof(vector_type)); - for (i = 0; i < nx->num_elt; i++) { - nx->elts[i] = ((vector) x)->elts[i]; - } - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(vector_type) + sizeof(object) * nx->num_elt; - return (char *) nx;} - case string_tag: - {register string_type *nx = (string_type *) allocp; - int str_size = gc_word_align(((string_type *)x)->len + 1); - type_of(nx) = string_tag; - nx->len = ((string_type *)x)->len; - nx->str = ((char *)nx) + sizeof(string_type); - memcpy(nx->str, ((string_type *)x)->str, nx->len + 1); -//TODO: below is changing, now we will need to always copy the cstring -//along with the string_type. need to be careful of any off-by-one errors -//here... -// if (gcgen == 0) { -// // Minor, data heap is not relocated -// nx->str = ((string_type *)x)->str; -// } else { -// // Major collection, data heap is moving -// nx->str = dhallocp; -// int len = strlen(((string_type *) x)->str); -// memcpy(dhallocp, ((string_type *) x)->str, len + 1); -// dhallocp += len + 1; +///** +// * Copy an object to the GC heap +// */ +//char *transport(x, gcgen) char *x; int gcgen; +//{ +// if (nullp(x)) return x; +// if (obj_is_char(x)) return x; +//#if DEBUG_GC +// printf("entered transport "); +// printf("transport %ld\n", type_of(x)); +//#endif +// switch (type_of(x)) +// {case cons_tag: +// {register list nx = (list) allocp; +// type_of(nx) = cons_tag; car(nx) = car(x); cdr(nx) = cdr(x); +// forward(x) = nx; type_of(x) = forward_tag; +// allocp = ((char *) nx)+sizeof(cons_type); +// return (char *) nx;} +// case macro_tag: +// {register macro nx = (macro) allocp; +// type_of(nx) = macro_tag; nx->fn = ((macro) x)->fn; +// nx->num_args = ((macro) x)->num_args; +// forward(x) = nx; type_of(x) = forward_tag; +// allocp = ((char *) nx)+sizeof(macro_type); +// return (char *) nx;} +// case closure0_tag: +// {register closure0 nx = (closure0) allocp; +// type_of(nx) = closure0_tag; nx->fn = ((closure0) x)->fn; +// nx->num_args = ((closure0) x)->num_args; +// forward(x) = nx; type_of(x) = forward_tag; +// allocp = ((char *) nx)+sizeof(closure0_type); +// return (char *) nx;} +// case closure1_tag: +// {register closure1 nx = (closure1) allocp; +// type_of(nx) = closure1_tag; nx->fn = ((closure1) x)->fn; +// nx->num_args = ((closure1) x)->num_args; +// nx->elt1 = ((closure1) x)->elt1; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure1_type); +// return (char *) nx;} +// case closure2_tag: +// {register closure2 nx = (closure2) allocp; +// type_of(nx) = closure2_tag; nx->fn = ((closure2) x)->fn; +// nx->num_args = ((closure2) x)->num_args; +// nx->elt1 = ((closure2) x)->elt1; +// nx->elt2 = ((closure2) x)->elt2; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure2_type); +// return (char *) nx;} +// case closure3_tag: +// {register closure3 nx = (closure3) allocp; +// type_of(nx) = closure3_tag; nx->fn = ((closure3) x)->fn; +// nx->num_args = ((closure3) x)->num_args; +// nx->elt1 = ((closure3) x)->elt1; +// nx->elt2 = ((closure3) x)->elt2; +// nx->elt3 = ((closure3) x)->elt3; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure3_type); +// return (char *) nx;} +// case closure4_tag: +// {register closure4 nx = (closure4) allocp; +// type_of(nx) = closure4_tag; nx->fn = ((closure4) x)->fn; +// nx->num_args = ((closure4) x)->num_args; +// nx->elt1 = ((closure4) x)->elt1; +// nx->elt2 = ((closure4) x)->elt2; +// nx->elt3 = ((closure4) x)->elt3; +// nx->elt4 = ((closure4) x)->elt4; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure4_type); +// return (char *) nx;} +// case closureN_tag: +// {register closureN nx = (closureN) allocp; +// int i; +// type_of(nx) = closureN_tag; nx->fn = ((closureN) x)->fn; +// nx->num_args = ((closureN) x)->num_args; +// nx->num_elt = ((closureN) x)->num_elt; +// nx->elts = (object *)(((char *)nx) + sizeof(closureN_type)); +// for (i = 0; i < nx->num_elt; i++) { +// nx->elts[i] = ((closureN) x)->elts[i]; // } - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size; - return (char *) nx;} - case integer_tag: - {register integer_type *nx = (integer_type *) allocp; - type_of(nx) = integer_tag; nx->value = ((integer_type *) x)->value; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type); - return (char *) nx;} - case double_tag: - {register double_type *nx = (double_type *) allocp; - type_of(nx) = double_tag; nx->value = ((double_type *) x)->value; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(double_type); - return (char *) nx;} - case port_tag: - {register port_type *nx = (port_type *) allocp; - type_of(nx) = port_tag; nx->fp = ((port_type *) x)->fp; - nx->mode = ((port_type *) x)->mode; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(port_type); - return (char *) nx;} - case cvar_tag: - {register cvar_type *nx = (cvar_type *) allocp; - type_of(nx) = cvar_tag; nx->pvar = ((cvar_type *) x)->pvar; - forward(x) = nx; type_of(x) = forward_tag; - x = (char *) nx; allocp = ((char *) nx)+sizeof(cvar_type); - return (char *) nx;} - case forward_tag: - return (char *) forward(x); - case eof_tag: break; - case primitive_tag: break; - case boolean_tag: break; - case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag) - default: - printf("transport: bad tag x=%p x.tag=%ld\n",(void *)x,type_of(x)); exit(0);} - return x;} - -/* Use overflow macro which already knows which way the stack goes. */ -/* Major collection, transport objects on stack or old heap */ -#define transp(p) \ -temp = (p); \ -if ((check_overflow(low_limit,temp) && \ - check_overflow(temp,high_limit)) || \ - (check_overflow(old_heap_low_limit - 1, temp) && \ - check_overflow(temp,old_heap_high_limit + 1))) \ - (p) = (object) transport(temp,major); - -void GC_loop(int major, closure cont, object *ans, int num_ans) -{char foo; - int i; - register object temp; - register object low_limit = &foo; /* Move live data above us. */ - register object high_limit = stack_begin; - register char *scanp = allocp; /* Cheney scan pointer. */ - register object old_heap_low_limit = low_limit; // Minor-GC default - register object old_heap_high_limit = high_limit; // Minor-GC default - - char *tmp_bottom = bottom; /* Bottom of tospace. */ - char *tmp_allocp = allocp; /* Cheney allocate pointer. */ - char *tmp_alloc_end = alloc_end; - char *tmp_dhbottom = dhbottom; - char *tmp_dhallocp = dhallocp; - char *tmp_dhallocp_end = dhalloc_end; - - if (dhallocp > dhalloc_limit) { - // Upgrade to major GC - major = 1; - no_major_gcs++; - no_gcs--; - } - - if (major) { - // Initialize new heap (TODO: make a function for this) - bottom = calloc(1,global_heap_size); - allocp = (char *) ((((long) bottom)+7) & -8); - alloc_end = allocp + global_heap_size - 8; - scanp = allocp; - old_heap_low_limit = tmp_bottom; - old_heap_high_limit = tmp_alloc_end; - - dhallocp = dhbottom = calloc(1, global_heap_size); - dhalloc_limit = dhallocp + (long)((global_heap_size - 8) * 0.90); - dhalloc_end = dhallocp + global_heap_size - 8; - } - -#if DEBUG_GC - printf("\n=== started GC type = %d === \n", major); -#endif - /* Transport GC's continuation and its argument. */ - transp(cont); - gc_cont = cont; - gc_num_ans = num_ans; -#if DEBUG_GC - printf("DEBUG done transporting cont\n"); -#endif - - /* Prevent overrunning buffer */ - if (num_ans > NUM_GC_ANS) { - printf("Fatal error - too many arguments (%d) to GC\n", num_ans); - exit(1); - } - - for (i = 0; i < num_ans; i++){ - transp(ans[i]); - gc_ans[i] = ans[i]; - } -#if DEBUG_GC - printf("DEBUG done transporting gc_ans\n"); -#endif - - /* Transport mutations. */ - { - list l; - for (l = mutation_table; !nullp(l); l = cdr(l)) { - object o = car(l); - if (type_of(o) == cons_tag) { - // Transport, if necessary - // TODO: need to test this with major GC, and - // GC's of list/car-cdr from same generation - transp(car(o)); - transp(cdr(o)); - } else if (type_of(o) == vector_tag) { - int i; - // TODO: probably too inefficient, try collecting single index - for (i = 0; i < ((vector)o)->num_elt; i++) { - transp(((vector)o)->elts[i]); - } - } else if (type_of(o) == forward_tag) { - // Already transported, skip - } else { - printf("Unexpected type %ld transporting mutation\n", type_of(o)); - exit(1); - } - } - } - clear_mutations(); /* Reset for next time */ - - /* Transport global variables. */ - transp(Cyc_global_variables); /* Internal global used by the runtime */ - { - list l = global_table; - for(; !nullp(l); l = cdr(l)){ - cvar_type *c = (cvar_type *)car(l); - transp(*(c->pvar)); // GC global, not the pvar - } - } - while (scanpelt1); - scanp += sizeof(closure1_type); break; - case closure2_tag: -#if DEBUG_GC - printf("DEBUG transport closure2 \n"); -#endif - transp(((closure2) scanp)->elt1); transp(((closure2) scanp)->elt2); - scanp += sizeof(closure2_type); break; - case closure3_tag: -#if DEBUG_GC - printf("DEBUG transport closure3 \n"); -#endif - transp(((closure3) scanp)->elt1); transp(((closure3) scanp)->elt2); - transp(((closure3) scanp)->elt3); - scanp += sizeof(closure3_type); break; - case closure4_tag: -#if DEBUG_GC - printf("DEBUG transport closure4 \n"); -#endif - transp(((closure4) scanp)->elt1); transp(((closure4) scanp)->elt2); - transp(((closure4) scanp)->elt3); transp(((closure4) scanp)->elt4); - scanp += sizeof(closure4_type); break; - case closureN_tag: -#if DEBUG_GC - printf("DEBUG transport closureN \n"); -#endif - {int i; int n = ((closureN) scanp)->num_elt; - for (i = 0; i < n; i++) { - transp(((closureN) scanp)->elts[i]); - } - scanp += sizeof(closureN_type) + sizeof(object) * n; - } - break; - case vector_tag: -#if DEBUG_GC - printf("DEBUG transport vector \n"); -#endif - {int i; int n = ((vector) scanp)->num_elt; - for (i = 0; i < n; i++) { - transp(((vector) scanp)->elts[i]); - } - scanp += sizeof(vector_type) + sizeof(object) * n; - } - break; - case string_tag: { -#if DEBUG_GC - printf("DEBUG transport string \n"); -#endif - string_type *x = (string_type *)scanp; - scanp += sizeof(string_type); - scanp += gc_word_align(x->len + 1); - break; - } -//TODO: cstring is now after string_type, so need to skip that, too. -//stack allocations should be OK since we are only scanning the newspace here, -//but should double-check that... (though we are not able to even scan the -//stack so should be fine) - case integer_tag: -#if DEBUG_GC - printf("DEBUG transport integer \n"); -#endif - scanp += sizeof(integer_type); break; - case double_tag: -#if DEBUG_GC - printf("DEBUG transport double \n"); -#endif - scanp += sizeof(double_type); break; - case port_tag: -#if DEBUG_GC - printf("DEBUG transport port \n"); -#endif - scanp += sizeof(port_type); break; - case cvar_tag: -#if DEBUG_GC - printf("DEBUG transport cvar \n"); -#endif - scanp += sizeof(cvar_type); break; - case eof_tag: - case primitive_tag: - case symbol_tag: - case boolean_tag: - default: - printf("GC: bad tag scanp=%p scanp.tag=%ld\n",(void *)scanp,type_of(scanp)); - exit(0);} - - if (major) { - free(tmp_bottom); - free(tmp_dhbottom); - } -} +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(closureN_type) + sizeof(object) * nx->num_elt; +// return (char *) nx;} +// case vector_tag: +// {register vector nx = (vector) allocp; +// int i; +// type_of(nx) = vector_tag; +// nx->num_elt = ((vector) x)->num_elt; +// nx->elts = (object *)(((char *)nx) + sizeof(vector_type)); +// for (i = 0; i < nx->num_elt; i++) { +// nx->elts[i] = ((vector) x)->elts[i]; +// } +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(vector_type) + sizeof(object) * nx->num_elt; +// return (char *) nx;} +// case string_tag: +// {register string_type *nx = (string_type *) allocp; +// int str_size = gc_word_align(((string_type *)x)->len + 1); +// type_of(nx) = string_tag; +// nx->len = ((string_type *)x)->len; +// nx->str = ((char *)nx) + sizeof(string_type); +// memcpy(nx->str, ((string_type *)x)->str, nx->len + 1); +////TODO: below is changing, now we will need to always copy the cstring +////along with the string_type. need to be careful of any off-by-one errors +////here... +//// if (gcgen == 0) { +//// // Minor, data heap is not relocated +//// nx->str = ((string_type *)x)->str; +//// } else { +//// // Major collection, data heap is moving +//// nx->str = dhallocp; +//// int len = strlen(((string_type *) x)->str); +//// memcpy(dhallocp, ((string_type *) x)->str, len + 1); +//// dhallocp += len + 1; +//// } +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size; +// return (char *) nx;} +// case integer_tag: +// {register integer_type *nx = (integer_type *) allocp; +// type_of(nx) = integer_tag; nx->value = ((integer_type *) x)->value; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type); +// return (char *) nx;} +// case double_tag: +// {register double_type *nx = (double_type *) allocp; +// type_of(nx) = double_tag; nx->value = ((double_type *) x)->value; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(double_type); +// return (char *) nx;} +// case port_tag: +// {register port_type *nx = (port_type *) allocp; +// type_of(nx) = port_tag; nx->fp = ((port_type *) x)->fp; +// nx->mode = ((port_type *) x)->mode; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(port_type); +// return (char *) nx;} +// case cvar_tag: +// {register cvar_type *nx = (cvar_type *) allocp; +// type_of(nx) = cvar_tag; nx->pvar = ((cvar_type *) x)->pvar; +// forward(x) = nx; type_of(x) = forward_tag; +// x = (char *) nx; allocp = ((char *) nx)+sizeof(cvar_type); +// return (char *) nx;} +// case forward_tag: +// return (char *) forward(x); +// case eof_tag: break; +// case primitive_tag: break; +// case boolean_tag: break; +// case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag) +// default: +// printf("transport: bad tag x=%p x.tag=%ld\n",(void *)x,type_of(x)); exit(0);} +// return x;} +// +///* Use overflow macro which already knows which way the stack goes. */ +///* Major collection, transport objects on stack or old heap */ +//#define transp(p) \ +//temp = (p); \ +//if ((check_overflow(low_limit,temp) && \ +// check_overflow(temp,high_limit)) || \ +// (check_overflow(old_heap_low_limit - 1, temp) && \ +// check_overflow(temp,old_heap_high_limit + 1))) \ +// (p) = (object) transport(temp,major); +// +//void GC_loop(int major, closure cont, object *ans, int num_ans) +//{char foo; +// int i; +// register object temp; +// register object low_limit = &foo; /* Move live data above us. */ +// register object high_limit = stack_begin; +// register char *scanp = allocp; /* Cheney scan pointer. */ +// register object old_heap_low_limit = low_limit; // Minor-GC default +// register object old_heap_high_limit = high_limit; // Minor-GC default +// +// char *tmp_bottom = bottom; /* Bottom of tospace. */ +// char *tmp_allocp = allocp; /* Cheney allocate pointer. */ +// char *tmp_alloc_end = alloc_end; +// char *tmp_dhbottom = dhbottom; +// char *tmp_dhallocp = dhallocp; +// char *tmp_dhallocp_end = dhalloc_end; +// +// if (dhallocp > dhalloc_limit) { +// // Upgrade to major GC +// major = 1; +// no_major_gcs++; +// no_gcs--; +// } +// +// if (major) { +// // Initialize new heap (TODO: make a function for this) +// bottom = calloc(1,global_heap_size); +// allocp = (char *) ((((long) bottom)+7) & -8); +// alloc_end = allocp + global_heap_size - 8; +// scanp = allocp; +// old_heap_low_limit = tmp_bottom; +// old_heap_high_limit = tmp_alloc_end; +// +// dhallocp = dhbottom = calloc(1, global_heap_size); +// dhalloc_limit = dhallocp + (long)((global_heap_size - 8) * 0.90); +// dhalloc_end = dhallocp + global_heap_size - 8; +// } +// +//#if DEBUG_GC +// printf("\n=== started GC type = %d === \n", major); +//#endif +// /* Transport GC's continuation and its argument. */ +// transp(cont); +// gc_cont = cont; +// gc_num_ans = num_ans; +//#if DEBUG_GC +// printf("DEBUG done transporting cont\n"); +//#endif +// +// /* Prevent overrunning buffer */ +// if (num_ans > NUM_GC_ANS) { +// printf("Fatal error - too many arguments (%d) to GC\n", num_ans); +// exit(1); +// } +// +// for (i = 0; i < num_ans; i++){ +// transp(ans[i]); +// gc_ans[i] = ans[i]; +// } +//#if DEBUG_GC +// printf("DEBUG done transporting gc_ans\n"); +//#endif +// +// /* Transport mutations. */ +// { +// list l; +// for (l = mutation_table; !nullp(l); l = cdr(l)) { +// object o = car(l); +// if (type_of(o) == cons_tag) { +// // Transport, if necessary +// // TODO: need to test this with major GC, and +// // GC's of list/car-cdr from same generation +// transp(car(o)); +// transp(cdr(o)); +// } else if (type_of(o) == vector_tag) { +// int i; +// // TODO: probably too inefficient, try collecting single index +// for (i = 0; i < ((vector)o)->num_elt; i++) { +// transp(((vector)o)->elts[i]); +// } +// } else if (type_of(o) == forward_tag) { +// // Already transported, skip +// } else { +// printf("Unexpected type %ld transporting mutation\n", type_of(o)); +// exit(1); +// } +// } +// } +// clear_mutations(); /* Reset for next time */ +// +// /* Transport global variables. */ +// transp(Cyc_global_variables); /* Internal global used by the runtime */ +// { +// list l = global_table; +// for(; !nullp(l); l = cdr(l)){ +// cvar_type *c = (cvar_type *)car(l); +// transp(*(c->pvar)); // GC global, not the pvar +// } +// } +// while (scanpelt1); +// scanp += sizeof(closure1_type); break; +// case closure2_tag: +//#if DEBUG_GC +// printf("DEBUG transport closure2 \n"); +//#endif +// transp(((closure2) scanp)->elt1); transp(((closure2) scanp)->elt2); +// scanp += sizeof(closure2_type); break; +// case closure3_tag: +//#if DEBUG_GC +// printf("DEBUG transport closure3 \n"); +//#endif +// transp(((closure3) scanp)->elt1); transp(((closure3) scanp)->elt2); +// transp(((closure3) scanp)->elt3); +// scanp += sizeof(closure3_type); break; +// case closure4_tag: +//#if DEBUG_GC +// printf("DEBUG transport closure4 \n"); +//#endif +// transp(((closure4) scanp)->elt1); transp(((closure4) scanp)->elt2); +// transp(((closure4) scanp)->elt3); transp(((closure4) scanp)->elt4); +// scanp += sizeof(closure4_type); break; +// case closureN_tag: +//#if DEBUG_GC +// printf("DEBUG transport closureN \n"); +//#endif +// {int i; int n = ((closureN) scanp)->num_elt; +// for (i = 0; i < n; i++) { +// transp(((closureN) scanp)->elts[i]); +// } +// scanp += sizeof(closureN_type) + sizeof(object) * n; +// } +// break; +// case vector_tag: +//#if DEBUG_GC +// printf("DEBUG transport vector \n"); +//#endif +// {int i; int n = ((vector) scanp)->num_elt; +// for (i = 0; i < n; i++) { +// transp(((vector) scanp)->elts[i]); +// } +// scanp += sizeof(vector_type) + sizeof(object) * n; +// } +// break; +// case string_tag: { +//#if DEBUG_GC +// printf("DEBUG transport string \n"); +//#endif +// string_type *x = (string_type *)scanp; +// scanp += sizeof(string_type); +// scanp += gc_word_align(x->len + 1); +// break; +// } +////TODO: cstring is now after string_type, so need to skip that, too. +////stack allocations should be OK since we are only scanning the newspace here, +////but should double-check that... (though we are not able to even scan the +////stack so should be fine) +// case integer_tag: +//#if DEBUG_GC +// printf("DEBUG transport integer \n"); +//#endif +// scanp += sizeof(integer_type); break; +// case double_tag: +//#if DEBUG_GC +// printf("DEBUG transport double \n"); +//#endif +// scanp += sizeof(double_type); break; +// case port_tag: +//#if DEBUG_GC +// printf("DEBUG transport port \n"); +//#endif +// scanp += sizeof(port_type); break; +// case cvar_tag: +//#if DEBUG_GC +// printf("DEBUG transport cvar \n"); +//#endif +// scanp += sizeof(cvar_type); break; +// case eof_tag: +// case primitive_tag: +// case symbol_tag: +// case boolean_tag: +// default: +// printf("GC: bad tag scanp=%p scanp.tag=%ld\n",(void *)scanp,type_of(scanp)); +// exit(0);} +// +// if (major) { +// free(tmp_bottom); +// free(tmp_dhbottom); +// } +//} +// +//void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; +//{ +// /* Only room for one more minor-GC, so do a major one. +// * Not sure this is the best strategy, it may be better to do major +// * ones sooner, perhaps after every x minor GC's. +// * +// * Also may need to consider dynamically increasing heap size, but +// * by how much (1.3x, 1.5x, etc) and when? I suppose when heap usage +// * after a collection is above a certain percentage, then it would be +// * necessary to increase heap size the next time. +// */ +// if (allocp >= (bottom + (global_heap_size - global_stack_size))) { +// //printf("Possibly only room for one more minor GC. no_gcs = %ld\n", no_gcs); +// no_major_gcs++; +// GC_loop(1, cont, ans, num_ans); +// } else { +// no_gcs++; /* Count the number of minor GC's. */ +// GC_loop(0, cont, ans, num_ans); +// } +// +// /* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind... */ +// longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ +//} void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; -{ - /* Only room for one more minor-GC, so do a major one. - * Not sure this is the best strategy, it may be better to do major - * ones sooner, perhaps after every x minor GC's. - * - * Also may need to consider dynamically increasing heap size, but - * by how much (1.3x, 1.5x, etc) and when? I suppose when heap usage - * after a collection is above a certain percentage, then it would be - * necessary to increase heap size the next time. - */ - if (allocp >= (bottom + (global_heap_size - global_stack_size))) { - //printf("Possibly only room for one more minor GC. no_gcs = %ld\n", no_gcs); - no_major_gcs++; - GC_loop(1, cont, ans, num_ans); - } else { - no_gcs++; /* Count the number of minor GC's. */ - GC_loop(0, cont, ans, num_ans); - } + // TODO: take 'live' objects from the stack and allocate them on the heap + /* + note fwd pointers are only ever placed on the stack, never the heap + + we now have 2 GC's: + - Stack GC, a minor collection where we move live stack objs to heap + - Heap GC, a major collection where we do mark&sweep - /* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind... */ + when replacing an object, + - only need to do this for objects on 'this' stack + - if object is a fwd pointer, return it's forwarding address + - otherwise, + * allocate them on the heap + * return the new address + * leave a forwarding pointer on the stack with the new address + - may be able to modify transp macro to do this part + + can still use write buffer to ensure any heap->stack references are handled + + need to transport: + - stack closure/args + - mutation write barrier + - globals + + after transport is complete, we will not be scanning newspace but + do need to transport any stack objects referenced by the above + a couple of ideas: + - create a list of allocated objects, and pass over them in much + the same way the cheney algorithm does (2 "fingers"??). I think + this could actually just be a list of pointers since we want to + copy to the heap not the scan space. the goal is just to ensure + all live stack references are moved to the heap. trick here is to + ensure scan space is large enough, although if it runs out + we can just allocate a new space (of say double the size), + memcpy the old one, and update scanp/allocp accordingly. + * can use a bump pointer to build the list, so it should be + fairly efficient, especially if we don't have to resize too much + * will be writing all of this code from scratch, but can use + existing scan code as a guide + - or, during transport recursively transport objects that could + contain references (closures, lists, etc). This may be more + convenient to code, although it requires stack space to traverse + the structures. I think it might also get stuck processing circular + structures (!!!), so this approach is not an option + TBD how (or even if) this can scale to multiple threads... + is is possible to use write barrier(s) to detect if one thread is + working with another's data during GC? This will be an important + point to keep in mind as the code is being written + +!!! +IMPORTANT - does the timing of GC matter? for example, if we GC before +scanning all the stack space, there might be an object referenced by +a live stack object that would get freed because we haven't gotten to +it yet! + +so I think we have to scan all the stack space before doing a GC. +alternatively, can we use a write barrier to keep track of when a +stack object references one on the heap? that would effectively make +the heap object into a root until stack GC + +Originally thought this, but now not so sure because it seems the above +has to be taken into account: + + Do not have to explicitly GC until heap is full enough for one to + be initiated. do need to code gc_collect though, and ensure it is + called at the appropriate time. + +I think everything else will work as written, but not quite sure how +to handle this detail yet. and it is very important to get right +!!!! + + thoughts: + - worth having a write barrier for globals? that is, only GC those that + were modified. just an idea... + */ longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ } - /** * Receive a list of arguments and apply them to the given function */ From 057c40eba8239d804eb9bb5c8f2e1cad1e3a1b6d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 14 Oct 2015 23:15:58 -0400 Subject: [PATCH 025/339] Added more notes --- gc-notes.txt | 2 ++ runtime.c | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 gc-notes.txt diff --git a/gc-notes.txt b/gc-notes.txt new file mode 100644 index 00000000..c704c36b --- /dev/null +++ b/gc-notes.txt @@ -0,0 +1,2 @@ +Phase 1 (gc-dev) - Add gc.h, make sure it compiles. +Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and be compatible with a new GC algorithm. diff --git a/runtime.c b/runtime.c index b957465b..deb7260d 100644 --- a/runtime.c +++ b/runtime.c @@ -2420,6 +2420,14 @@ to handle this detail yet. and it is very important to get right thoughts: - worth having a write barrier for globals? that is, only GC those that were modified. just an idea... + - KEEP IN MIND AN OVERALL GOAL, that this should try to be as close as + possible to the cheney algorithm in terms of performance. so obviously we + want to try and do as little work as necessary during each minor GC. + since we will use a write barrier to keep track of the heap's stack refs, + it seems reasonable that we could skip globals that live on the heap. + - To some extent, it should be possible to test changes that improve performance + by coding something inefficient (but guaranteed to work) and then modifying it to + be more efficient (but not quite sure if idea will work). */ longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ } From 3a68ce5a329bc284cf28eab26145923e5332d542 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 14 Oct 2015 22:48:38 -0400 Subject: [PATCH 026/339] WIP, integrating directly with cyclone --- gc.c | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/gc.c b/gc.c index 14f84d3a..d5062a56 100644 --- a/gc.c +++ b/gc.c @@ -1,4 +1,4 @@ -/* TODO: a basic mark-sweep GC +/* A basic mark-sweep GC As of now, the GC code is based off the implementation from chibi scheme Goals of this project: @@ -146,23 +146,45 @@ void gc_mark(gc_heap *h, object obj) return; #if GC_DEBUG_PRINTFS - fprintf(stdout, "gc_mark %p\n", obj); + fprintf(stdout, "gc_mark %p\n", obj); #endif - ((list)obj)->hdr.mark = 1; + ((list)obj)->hdr.mark = 1; // TODO: mark heap saves (??) // could this be a write barrier? // Mark objects this one references - if (type_of(obj) == cons_tag) { - gc_mark(h, car(obj)); - gc_mark(h, cdr(obj)); - } - // TODO: will be more work in here the "real" implementation + if (type_of(obj) == cons_tag) { + gc_mark(h, car(obj)); + gc_mark(h, cdr(obj)); + } else if (type_of(obj) == closure1_tag) { + gc_mark(h, ((closure1) obj)->elt1); + } else if (type_of(obj) == closure2_tag) { + gc_mark(h, ((closure2) obj)->elt1); + gc_mark(h, ((closure2) obj)->elt2); + } else if (type_of(obj) == closure3_tag) { + gc_mark(h, ((closure3) obj)->elt1); + gc_mark(h, ((closure3) obj)->elt2); + gc_mark(h, ((closure3) obj)->elt3); + } else if (type_of(obj) == closure4_tag) { + gc_mark(h, ((closure4) obj)->elt1); + gc_mark(h, ((closure4) obj)->elt2); + gc_mark(h, ((closure4) obj)->elt3); + gc_mark(h, ((closure4) obj)->elt4); + } else if (type_of(obj) == closureN_tag) { + int i, n = ((closureN) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_mark(h, ((closureN) obj)->elts[i]); + } + } else if (type_of(obj) == vector_tag) { + int i, n = ((vector) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_mark(h, ((vector) obj)->elts[i]); + } + } } size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) { - // TODO: scan entire heap, freeing objects that have not been marked size_t freed, max_freed=0, sum_freed=0, size; object p, end; gc_free_list *q, *r, *s; @@ -240,19 +262,6 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) return max_freed; } -void gc_collect(gc_heap *h, size_t *sum_freed) -{ - printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); - // TODO: mark globals - // TODO: gc_mark(h, h); - // conservative mark? - // weak refs? - // finalize? - gc_sweep(h, sum_freed); - // debug print free stats - // return value from sweep?? -} - // void gc_init() // { // } From 2db7a2e86c27b99a616af80ae75920347c5e6cc0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 14 Oct 2015 23:01:58 -0400 Subject: [PATCH 027/339] WIP --- include/cyclone/types.h | 2 +- runtime.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 4b55a1d6..92ff5ae7 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -68,7 +68,7 @@ gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); void gc_mark(gc_heap *h, object obj); size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); -//void gc_collect(gc_heap *h, size_t *sum_freed) +void gc_collect(gc_heap *h, size_t *sum_freed); /* GC debugging flags */ //#define DEBUG_GC 0 diff --git a/runtime.c b/runtime.c index deb7260d..12f50bad 100644 --- a/runtime.c +++ b/runtime.c @@ -2345,6 +2345,27 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} +// NEW GC algorithm +void gc_collect(gc_heap *h, size_t *sum_freed) +{ + printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + // Mark global variables + gc_mark(h, Cyc_global_variables); /* Internal global used by the runtime */ + { + list l = global_table; + for(; !nullp(l); l = cdr(l)){ + cvar_type *c = (cvar_type *)car(l); + gc_mark(h, *(c->pvar)); // Mark global, not the pvar + } + } + // TODO: what else to mark? gc_mark( + // conservative mark? + // weak refs? + // finalize? + gc_sweep(h, sum_freed); + // debug print free stats + // return value from sweep?? +} void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; // TODO: take 'live' objects from the stack and allocate them on the heap /* From fba366c7f9d33180656a1f1064b152ac78b5de1a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 15 Oct 2015 18:39:48 -0400 Subject: [PATCH 028/339] Added notes --- runtime.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtime.c b/runtime.c index 12f50bad..84f51b65 100644 --- a/runtime.c +++ b/runtime.c @@ -2385,6 +2385,11 @@ void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; - may be able to modify transp macro to do this part can still use write buffer to ensure any heap->stack references are handled + - also want to use this barrier to handle any globals that are re-assigned to + locations on the stack, to ensure they are moved to the heap during GC. + - write barrier really should be per-stack, since OK to leave those items until + stack is collected + - TBD how this works with multiple threads, each with its own stack need to transport: - stack closure/args From e2f8a9343986f810c5b8b172ac98082c5e249b50 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 15 Oct 2015 22:38:27 -0400 Subject: [PATCH 029/339] WIP --- runtime.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/runtime.c b/runtime.c index 84f51b65..713d9a20 100644 --- a/runtime.c +++ b/runtime.c @@ -2346,6 +2346,11 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { //} // NEW GC algorithm +// +// TODO: not quite sure when to call this function. might want to set a flag +// if the heap was expanded during alloc, and after all the allocs are done +// after a minor GC (or during the minor GC), call into this function to +// free up unused space void gc_collect(gc_heap *h, size_t *sum_freed) { printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); @@ -2366,9 +2371,66 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // debug print free stats // return value from sweep?? } -void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; - // TODO: take 'live' objects from the stack and allocate them on the heap - /* + +// TODO: move globals to thread-specific structures. +// for example - gc_cont, gc_ans, gc_num_ans + +void GC(cont,ans,num_ans) closure cont; object *args; int num_args; +{ + int i; + int moveBufLen = 128, mbIdx = 0; + void **moved = alloca(sizeof(void *) * moveBufLen); + + // Prevent overrunning buffer + if (num_ans > NUM_GC_ANS) { + printf("Fatal error - too many arguments (%d) to GC\n", num_ans); + exit(1); + } + + cp2heap(cont); + gc_cont = cont; + gc_num_ans = num_args; + + for (i = 0; i < num_args; i++){ + cp2heap(args[i]); + gc_ans[i] = args[i]; + } + + // TODO: move mutations to heap (any stack-allocated globals must be here, too) + { + list l; + for (l = mutation_table; !nullp(l); l = cdr(l)) { + object o = car(l); + if (type_of(o) == cons_tag) { + cp2heap(car(o)); + cp2heap(cdr(o)); + } else if (type_of(o) == vector_tag) { + int i; + // TODO: probably too inefficient, try collecting single index + for (i = 0; i < ((vector)o)->num_elt; i++) { + cp2heap(((vector)o)->elts[i]); + } + } else if (type_of(o) == forward_tag) { + // Already transported, skip + } else { + printf("Unexpected type %ld transporting mutation\n", type_of(o)); + exit(1); + } + } + } + clear_mutations(); // Reset for next time + + // TODO: use a bump pointer to keep track of who was moved + // probably need to do this as part of cp2heap + + // TODO: scan bump pointer space, moving additional objects as needed + // TODO: at some point during all of this, check the 'major GC' flag + // to see if we need to do a gc_collect + + longjmp(jmp_main,1); // Return globals gc_cont, gc_ans +} + + /* Overall GC notes: note fwd pointers are only ever placed on the stack, never the heap we now have 2 GC's: @@ -2455,8 +2517,6 @@ to handle this detail yet. and it is very important to get right by coding something inefficient (but guaranteed to work) and then modifying it to be more efficient (but not quite sure if idea will work). */ - longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ -} /** * Receive a list of arguments and apply them to the given function From 3363bf477d7ce77a2609fcc3b0eddcc50f01d313 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 02:18:09 -0400 Subject: [PATCH 030/339] Working on gc_move2heap --- runtime.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/runtime.c b/runtime.c index 713d9a20..5d616eb6 100644 --- a/runtime.c +++ b/runtime.c @@ -2375,8 +2375,20 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // TODO: move globals to thread-specific structures. // for example - gc_cont, gc_ans, gc_num_ans +#define gc_move2heap(obj) { \ + temp = obj; \ + if (check_overflow(low_limit, temp) && \ + check_overflow(temp, high_limit)){ \ + (obj) = TODO: allocate on heap, return new address, replace old w/fwd ptr \ + } \ +} + void GC(cont,ans,num_ans) closure cont; object *args; int num_args; { + char tmp; + object temp; + object low_limit = &tmp; // This is one end of the stack... + object high_limit = stack_begin; // TODO: move to thread-specific struct int i; int moveBufLen = 128, mbIdx = 0; void **moved = alloca(sizeof(void *) * moveBufLen); @@ -2387,12 +2399,12 @@ void GC(cont,ans,num_ans) closure cont; object *args; int num_args; exit(1); } - cp2heap(cont); + gc_move2heap(cont); gc_cont = cont; gc_num_ans = num_args; for (i = 0; i < num_args; i++){ - cp2heap(args[i]); + gc_move2heap(args[i]); gc_ans[i] = args[i]; } @@ -2402,13 +2414,13 @@ void GC(cont,ans,num_ans) closure cont; object *args; int num_args; for (l = mutation_table; !nullp(l); l = cdr(l)) { object o = car(l); if (type_of(o) == cons_tag) { - cp2heap(car(o)); - cp2heap(cdr(o)); + gc_move2heap(car(o)); + gc_move2heap(cdr(o)); } else if (type_of(o) == vector_tag) { int i; // TODO: probably too inefficient, try collecting single index for (i = 0; i < ((vector)o)->num_elt; i++) { - cp2heap(((vector)o)->elts[i]); + gc_move2heap(((vector)o)->elts[i]); } } else if (type_of(o) == forward_tag) { // Already transported, skip @@ -2421,7 +2433,7 @@ void GC(cont,ans,num_ans) closure cont; object *args; int num_args; clear_mutations(); // Reset for next time // TODO: use a bump pointer to keep track of who was moved - // probably need to do this as part of cp2heap + // probably need to do this as part of gc_move2heap // TODO: scan bump pointer space, moving additional objects as needed // TODO: at some point during all of this, check the 'major GC' flag From d7640c988b74fe0d1ee5876e3c7165c2ffbdc995 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 15 Oct 2015 22:52:38 -0400 Subject: [PATCH 031/339] Added gc_move, but still need to build it out --- include/cyclone/runtime-main.h | 5 +++++ runtime.c | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index f7914f8b..a07e1535 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -13,6 +13,7 @@ long global_stack_size = 0; long global_heap_size = 0; +gc_heap *Cyc_heap; static void c_entry_pt(int,closure,closure); static void Cyc_main(long stack_size,long heap_size,char *stack_base); @@ -56,6 +57,10 @@ static void Cyc_main (stack_size,heap_size,stack_base) #if DEBUG_SHOW_DIAG printf("main: Allocating and initializing heap...\n"); #endif + + Cyc_heap = gc_heap_create(heap_size, 0); + + // JAE TODO: clean up below (and all of this old code, really) bottom = calloc(1,heap_size); allocp = (char *) ((((long) bottom)+7) & -8); alloc_end = allocp + heap_size - 8; diff --git a/runtime.c b/runtime.c index 5d616eb6..65afe17d 100644 --- a/runtime.c +++ b/runtime.c @@ -2375,11 +2375,33 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // TODO: move globals to thread-specific structures. // for example - gc_cont, gc_ans, gc_num_ans +char *gc_move(char *obj) { + if (!is_object_type(obj)) return obj; + + switch(type_of(obj)){ + case cons_tag: { + list hobj = gc_alloc(Cyc_heap, sizeof(cons_type)); + hobj->hdr.mark = 0; + type_of(hobj) = cons_tag; + car(hobj) = car(obj); + cdr(hobj) = cdr(hobj); + forward(obj) = hobj; + type_of(obj) = forward_tag; +// TODO: add hobj to bump pointer, so we can scan/move the whole live object 'tree' +// will require we pass the 'bump' space to this function, +// and will require us to check somewhere for overflow of this space, and +// realloc/expand it if necessary + return (char *)hobj; + } + // TODO: other types + } +} + #define gc_move2heap(obj) { \ temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = TODO: allocate on heap, return new address, replace old w/fwd ptr \ + (obj) = (object) gc_move(temp); \ } \ } From e941b19db410913dd7dbd52c51b94e18a5713a60 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 22:14:52 -0400 Subject: [PATCH 032/339] Added moveBuf and helper functions --- gc.c | 13 +++++++++++++ include/cyclone/runtime-main.h | 5 ++++- include/cyclone/types.h | 8 ++++++++ runtime.c | 5 ++++- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index d5062a56..7716ea8c 100644 --- a/gc.c +++ b/gc.c @@ -262,6 +262,19 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) return max_freed; } +void gc_thr_grow_move_buffer(gc_thread_data *d){ + if (!d) return; + + if (d->moveBufLen == 0) { // Special case + d->moveBufLen = 128; + d->moveBuf = NULL; + } else { + d->moveBufLen *= 2; + } + + d->moveBuf = realloc(d->moveBuf, d->moveBufLen); +} + // void gc_init() // { // } diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index a07e1535..012ece81 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -13,7 +13,6 @@ long global_stack_size = 0; long global_heap_size = 0; -gc_heap *Cyc_heap; static void c_entry_pt(int,closure,closure); static void Cyc_main(long stack_size,long heap_size,char *stack_base); @@ -59,6 +58,10 @@ static void Cyc_main (stack_size,heap_size,stack_base) #endif Cyc_heap = gc_heap_create(heap_size, 0); + Cyc_thread = (gc_thread_data *)malloc(sizeof(gc_thread_data)); + Cyc_thread->moveBufLen = 0; + gc_thr_grow_move_buffer(Cyc_thread); // Initialize the buffer + // JAE TODO: clean up below (and all of this old code, really) bottom = calloc(1,heap_size); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 92ff5ae7..29352735 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -20,6 +20,13 @@ /* Define general object type. */ typedef void *object; +/* Thread data structures */ +typedef struct gc_thread_data_t gc_thread_data; +struct gc_thread_data_t { + char *moveBuf; /* list of objects moved to heap during GC */ + int moveBufLen; +}; + /* GC data structures */ typedef struct gc_free_list_t gc_free_list; @@ -69,6 +76,7 @@ size_t gc_heap_total_size(gc_heap *h); void gc_mark(gc_heap *h, object obj); size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); void gc_collect(gc_heap *h, size_t *sum_freed); +void gc_thr_grow_move_buffer(gc_thread_data *d); /* GC debugging flags */ //#define DEBUG_GC 0 diff --git a/runtime.c b/runtime.c index 65afe17d..88ed51a0 100644 --- a/runtime.c +++ b/runtime.c @@ -9,6 +9,9 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" +gc_heap *Cyc_heap; +gc_thread_data *Cyc_thread; + /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ const char *tag_names[21] = { \ @@ -2405,7 +2408,7 @@ char *gc_move(char *obj) { } \ } -void GC(cont,ans,num_ans) closure cont; object *args; int num_args; +void GC(cont, args, num_args) closure cont; object *args; int num_args; { char tmp; object temp; From 076a9316e02a40dbe3f03df701935343b1bcd4ce Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 22:44:42 -0400 Subject: [PATCH 033/339] Added notes --- runtime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime.c b/runtime.c index 88ed51a0..d31c16c0 100644 --- a/runtime.c +++ b/runtime.c @@ -2417,6 +2417,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; int i; int moveBufLen = 128, mbIdx = 0; void **moved = alloca(sizeof(void *) * moveBufLen); + int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work // Prevent overrunning buffer if (num_ans > NUM_GC_ANS) { From dfdfd52a54f645c2c3354d9791dcf51076527bc8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 17 Oct 2015 02:02:55 -0400 Subject: [PATCH 034/339] Added move to buffer function --- gc.c | 15 +++++++++++++-- include/cyclone/types.h | 3 ++- runtime.c | 17 +++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/gc.c b/gc.c index 7716ea8c..630381ca 100644 --- a/gc.c +++ b/gc.c @@ -262,7 +262,8 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) return max_freed; } -void gc_thr_grow_move_buffer(gc_thread_data *d){ +void gc_thr_grow_move_buffer(gc_thread_data *d) +{ if (!d) return; if (d->moveBufLen == 0) { // Special case @@ -272,7 +273,17 @@ void gc_thr_grow_move_buffer(gc_thread_data *d){ d->moveBufLen *= 2; } - d->moveBuf = realloc(d->moveBuf, d->moveBufLen); + d->moveBuf = realloc(d->moveBuf, d->moveBufLen * sizeof(void *)); +} + +void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) +{ + if (*alloci == d->moveBufLen) { + gc_thr_grow_move_buffer(d); + } + + d->moveBuf[*alloci] = obj; + (*alloci)++; } // void gc_init() diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 29352735..10e88a35 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -23,7 +23,7 @@ typedef void *object; /* Thread data structures */ typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { - char *moveBuf; /* list of objects moved to heap during GC */ + void **moveBuf; /* list of objects moved to heap during GC */ int moveBufLen; }; @@ -77,6 +77,7 @@ void gc_mark(gc_heap *h, object obj); size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); void gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); +void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); /* GC debugging flags */ //#define DEBUG_GC 0 diff --git a/runtime.c b/runtime.c index d31c16c0..4350f534 100644 --- a/runtime.c +++ b/runtime.c @@ -2378,7 +2378,7 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // TODO: move globals to thread-specific structures. // for example - gc_cont, gc_ans, gc_num_ans -char *gc_move(char *obj) { +char *gc_move(char *obj, gc_thread_data *thd, int *alloci) { if (!is_object_type(obj)) return obj; switch(type_of(obj)){ @@ -2390,10 +2390,9 @@ char *gc_move(char *obj) { cdr(hobj) = cdr(hobj); forward(obj) = hobj; type_of(obj) = forward_tag; -// TODO: add hobj to bump pointer, so we can scan/move the whole live object 'tree' -// will require we pass the 'bump' space to this function, -// and will require us to check somewhere for overflow of this space, and -// realloc/expand it if necessary + // keep track of each allocation so we can scan/move + // the whole live object 'tree' + gc_thr_add_to_move_buffer(thd, alloci, hobj); return (char *)hobj; } // TODO: other types @@ -2404,7 +2403,7 @@ char *gc_move(char *obj) { temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp); \ + (obj) = (object) gc_move(temp, Cyc_thread, &alloci); \ } \ } @@ -2415,13 +2414,11 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; object low_limit = &tmp; // This is one end of the stack... object high_limit = stack_begin; // TODO: move to thread-specific struct int i; - int moveBufLen = 128, mbIdx = 0; - void **moved = alloca(sizeof(void *) * moveBufLen); int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work // Prevent overrunning buffer - if (num_ans > NUM_GC_ANS) { - printf("Fatal error - too many arguments (%d) to GC\n", num_ans); + if (num_args > NUM_GC_ANS) { + printf("Fatal error - too many arguments (%d) to GC\n", num_args); exit(1); } From 5ed84d5332f18b2bd271e92329707ca7c339c730 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 17 Oct 2015 02:14:01 -0400 Subject: [PATCH 035/339] Loop over allocated space --- runtime.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/runtime.c b/runtime.c index 4350f534..1be5d1c8 100644 --- a/runtime.c +++ b/runtime.c @@ -2455,10 +2455,23 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; } clear_mutations(); // Reset for next time - // TODO: use a bump pointer to keep track of who was moved - // probably need to do this as part of gc_move2heap + // Check allocated objects, moving additional objects as needed + while (scani < alloci) { + object obj = Cyc_thread->moveBuf[scani]; + switch(type_of(obj)) { + case cons_tag: { + gc_move2heap(car(obj)); + gc_move2heap(cdr(obj)); + } + // TODO: other types to move + default: + fprintf(stderr, + "GC: unexpected object type %ld for object %p\n", type_of(obj), obj); + exit(1); + } + scani++; + } - // TODO: scan bump pointer space, moving additional objects as needed // TODO: at some point during all of this, check the 'major GC' flag // to see if we need to do a gc_collect From b08f68cf52e38c3bd60308857b7b3f4abbcf69ae Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 17 Oct 2015 02:25:22 -0400 Subject: [PATCH 036/339] Perform major GC if necessary --- gc.c | 3 ++- include/cyclone/types.h | 2 +- runtime.c | 16 +++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index 630381ca..f0021df9 100644 --- a/gc.c +++ b/gc.c @@ -71,7 +71,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) return NULL; } -void *gc_alloc(gc_heap *h, size_t size) +void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) { void *result = NULL; size_t max_freed, sum_freed, total_size; @@ -95,6 +95,7 @@ max_freed = 0; (total_size - sum_freed) > (total_size * 0.75))) // Grow ratio && ((!h->max_size) || (total_size < h->max_size))) { gc_grow_heap(h, size, 0); + *heap_grown = 1; } result = gc_try_alloc(h, size); if (!result) { diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 10e88a35..bc9ecc91 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -69,7 +69,7 @@ struct gc_header_type_t { gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); void *gc_try_alloc(gc_heap *h, size_t size); -void *gc_alloc(gc_heap *h, size_t size); +void *gc_alloc(gc_heap *h, size_t size, int *heap_grown); size_t gc_allocated_bytes(object obj); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); diff --git a/runtime.c b/runtime.c index 1be5d1c8..8b5bc315 100644 --- a/runtime.c +++ b/runtime.c @@ -2378,12 +2378,12 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // TODO: move globals to thread-specific structures. // for example - gc_cont, gc_ans, gc_num_ans -char *gc_move(char *obj, gc_thread_data *thd, int *alloci) { +char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; switch(type_of(obj)){ case cons_tag: { - list hobj = gc_alloc(Cyc_heap, sizeof(cons_type)); + list hobj = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); hobj->hdr.mark = 0; type_of(hobj) = cons_tag; car(hobj) = car(obj); @@ -2403,7 +2403,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci) { temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp, Cyc_thread, &alloci); \ + (obj) = (object) gc_move(temp, Cyc_thread, &alloci, &heap_grown); \ } \ } @@ -2415,6 +2415,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; object high_limit = stack_begin; // TODO: move to thread-specific struct int i; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work + int heap_grown = 0; // Prevent overrunning buffer if (num_args > NUM_GC_ANS) { @@ -2472,8 +2473,13 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; scani++; } - // TODO: at some point during all of this, check the 'major GC' flag - // to see if we need to do a gc_collect + // Check if we need to do a major GC + if (heap_grown) { + size_t freed = 0; + // TODO: not good enough, need to pass current cont/args + // what about mutation barrier, do we care at this point??? + gc_collect(Cyc_heap, &freed); + } longjmp(jmp_main,1); // Return globals gc_cont, gc_ans } From 9895029a9094de5fec49736f03e1570cde72cf1b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 21:53:26 -0400 Subject: [PATCH 037/339] Added remaining types to scanning section --- runtime.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 8b5bc315..c3dd016a 100644 --- a/runtime.c +++ b/runtime.c @@ -2463,8 +2463,52 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; case cons_tag: { gc_move2heap(car(obj)); gc_move2heap(cdr(obj)); + break; } - // TODO: other types to move + case closure1_tag: + gc_move2heap(((closure1) obj)->elt1); + break; + case closure2_tag: + gc_move2heap(((closure2) obj)->elt1); + gc_move2heap(((closure2) obj)->elt2); + case closure3_tag: + gc_move2heap(((closure3) obj)->elt1); + gc_move2heap(((closure3) obj)->elt2); + gc_move2heap(((closure3) obj)->elt3); + case closure4_tag: + gc_move2heap(((closure4) obj)->elt1); + gc_move2heap(((closure4) obj)->elt2); + gc_move2heap(((closure4) obj)->elt3); + gc_move2heap(((closure4) obj)->elt4); + break; + case closureN_tag: { + int i, n = ((closureN) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_move2heap(((closureN) obj)->elts[i]); + } + break; + } + case vector_tag: { + int i, n = ((vector) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_move2heap(((vector) obj)->elts[i]); + } + break; + } + // No child objects to move + case closure0_tag: + case macro_tag: + case string_tag: + case integer_tag: + case double_tag: + case port_tag: + case cvar_tag: + break; + // These types are not heap-allocated + case eof_tag: + case primitive_tag: + case symbol_tag: + case boolean_tag: default: fprintf(stderr, "GC: unexpected object type %ld for object %p\n", type_of(obj), obj); From 7e37e1710d4510f47f755d9005e956e03d3bb470 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 23:04:40 -0400 Subject: [PATCH 038/339] Build-out of most of the GC move cases --- include/cyclone/types.h | 1 + runtime.c | 164 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 164 insertions(+), 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index bc9ecc91..f773535a 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -52,6 +52,7 @@ struct gc_header_type_t { // TODO: forwarding address (probably not needed for mark/sweep), anything else??? }; #define is_marked(x) (is_object_type(x) && ((list)x)->hdr.mark) +#define mark(x) (((list) x)->hdr.mark) /* HEAP definitions */ // experimenting with a heap based off of the one in Chibi scheme diff --git a/runtime.c b/runtime.c index c3dd016a..a366413d 100644 --- a/runtime.c +++ b/runtime.c @@ -2395,8 +2395,170 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { gc_thr_add_to_move_buffer(thd, alloci, hobj); return (char *)hobj; } - // TODO: other types + case macro_tag: { + macro_type *hobj = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = macro_tag; + hobj->fn = ((macro) obj)->fn; + hobj->num_args = ((macro) obj)->num_args; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closure0_tag: { + closure0_type *hobj = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = closure0_tag; + hobj->fn = ((closure0) obj)->fn; + hobj->num_args = ((closure0) obj)->num_args; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closure1_tag: { + closure1_type *hobj = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = closure1_tag; + hobj->fn = ((closure1) obj)->fn; + hobj->num_args = ((closure1) obj)->num_args; + hobj->elt1 = ((closure1) obj)->elt1; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closure2_tag: { + closure2_type *hobj = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = closure2_tag; + hobj->fn = ((closure2) obj)->fn; + hobj->num_args = ((closure2) obj)->num_args; + hobj->elt1 = ((closure2) obj)->elt1; + hobj->elt2 = ((closure2) obj)->elt2; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closure3_tag: { + closure3_type *hobj = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = closure3_tag; + hobj->fn = ((closure3) obj)->fn; + hobj->num_args = ((closure3) obj)->num_args; + hobj->elt1 = ((closure3) obj)->elt1; + hobj->elt2 = ((closure3) obj)->elt2; + hobj->elt3 = ((closure3) obj)->elt3; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closure4_tag: { + closure4_type *hobj = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = closure4_tag; + hobj->fn = ((closure4) obj)->fn; + hobj->num_args = ((closure4) obj)->num_args; + hobj->elt1 = ((closure4) obj)->elt1; + hobj->elt2 = ((closure4) obj)->elt2; + hobj->elt3 = ((closure4) obj)->elt3; + hobj->elt4 = ((closure4) obj)->elt4; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case closureN_tag: { + int i; + closureN_type *hobj = gc_alloc(Cyc_heap, + sizeof(closureN_type) + sizeof(object) * hobj->num_elt, + heap_grown); + mark(hobj) = 0; + type_of(hobj) = closureN_tag; + hobj->fn = ((closureN) obj)->fn; + hobj->num_args = ((closureN) obj)->num_args; + hobj->num_elt = ((closureN) obj)-> num_elt; + for (i = 0; i < hobj->num_elt; i++) { + hobj->elts[i] = ((closureN) obj)->elts[i]; + } + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case vector_tag: { + int i; + vector_type *hobj = gc_alloc(Cyc_heap, + sizeof(vector_type) + sizeof(object) * hobj->num_elt, + heap_grown); + mark(hobj) = 0; + type_of(hobj) = vector_tag; + hobj->num_elt = ((vector) obj)-> num_elt; + for (i = 0; i < hobj->num_elt; i++) { + hobj->elts[i] = ((vector) obj)->elts[i]; + } + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } +// TODO case string_tag: { +// } + case integer_tag: { + integer_type *hobj = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = integer_tag; + hobj->value = ((integer_type *) obj)->value; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case double_tag: { + double_type *hobj = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = double_tag; + hobj->value = ((double_type *) obj)->value; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case port_tag: { + port_type *hobj = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = port_tag; + hobj->fp = ((port_type *) obj)->fp; + hobj->mode = ((port_type *) obj)->mode; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case cvar_tag: { + cvar_type *hobj = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown); + mark(hobj) = 0; + type_of(hobj) = cvar_tag; + hobj->pvar = ((cvar_type *) obj)->pvar; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; + } + case forward_tag: + return (char *)forward(obj); + case eof_tag: break; + case primitive_tag: break; + case boolean_tag: break; + case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag) + default: + fprintf(stderr, "gc_move: bad tag x=%p x.tag=%ld\n",(object) obj, type_of(obj)); + exit(1); } + return (char *)obj; } #define gc_move2heap(obj) { \ From 0f9ab2670d4fec68df53e5c39040bcafbfca767d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 16 Oct 2015 23:05:22 -0400 Subject: [PATCH 039/339] Added TODO --- runtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime.c b/runtime.c index a366413d..1121ec70 100644 --- a/runtime.c +++ b/runtime.c @@ -2505,8 +2505,8 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { gc_thr_add_to_move_buffer(thd, alloci, hobj); return (char *)hobj; } -// TODO case string_tag: { -// } + TODO case string_tag: { + } case integer_tag: { integer_type *hobj = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); mark(hobj) = 0; From 90e2fdb1f5dbf7d7593f63eb7d5bc496cccdf889 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 19 Oct 2015 22:41:28 -0400 Subject: [PATCH 040/339] Finished adding types to new GC functions --- gc.c | 20 +++++++++++++++++++- runtime.c | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index f0021df9..fd657823 100644 --- a/gc.c +++ b/gc.c @@ -116,10 +116,28 @@ size_t gc_allocated_bytes(object obj) return gc_heap_align(1); t = type_of(obj); if (t == cons_tag) return gc_heap_align(sizeof(cons_type)); + if (t == macro_tag) return gc_heap_align(sizeof(macro_type)); + if (t == closure0_tag) return gc_heap_align(sizeof(closure0_type)); + if (t == closure1_tag) return gc_heap_align(sizeof(closure1_type)); + if (t == closure2_tag) return gc_heap_align(sizeof(closure2_type)); + if (t == closure3_tag) return gc_heap_align(sizeof(closure3_type)); + if (t == closure4_tag) return gc_heap_align(sizeof(closure4_type)); + if (t == closureN_tag){ + return gc_heap_align(sizeof(closureN_type) + sizeof(object) * ((closureN_type *)obj)->num_elt); + } + if (t == vector_tag){ + return gc_heap_align(sizeof(vector_type) + sizeof(object) * ((vector_type *)obj)->num_elt); + } + if (t == string_tag){ + return gc_heap_align(sizeof(string_type) + string_len(obj) + 1); + } if (t == integer_tag) return gc_heap_align(sizeof(integer_type)); + if (t == double_tag) return gc_heap_align(sizeof(double_type)); + if (t == port_tag) return gc_heap_align(sizeof(port_type)); + if (t == cvar_tag) return gc_heap_align(sizeof(cvar_type)); #if GC_DEBUG_PRINTFS - fprintf(stderr, "cannot get size of object %ld\n", t); + fprintf(stderr, "gc_allocated_bytes: unexpected object %p of type %ld\n", obj, t); #endif return 0; } diff --git a/runtime.c b/runtime.c index 1121ec70..a9ecdaef 100644 --- a/runtime.c +++ b/runtime.c @@ -2505,7 +2505,21 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { gc_thr_add_to_move_buffer(thd, alloci, hobj); return (char *)hobj; } - TODO case string_tag: { + case string_tag: { + char *s; + string_type *hobj = gc_alloc(Cyc_heap, + sizeof(string_type) + ((string_len(obj) + 1)), + heap_grown); + s = ((char *)hobj) + sizeof(string_type); + memcpy(s, string_str(obj), string_len(obj) + 1); + mark(hobj) = 0; + type_of(hobj) = string_tag; + string_len(hobj) = string_len(obj); + string_str(hobj) = s; + forward(obj) = hobj; + type_of(obj) = forward_tag; + gc_thr_add_to_move_buffer(thd, alloci, hobj); + return (char *)hobj; } case integer_tag: { integer_type *hobj = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); From cc4b3f36b4d2829b43b3a9fcb509a2da0665fa6a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 19 Oct 2015 22:44:47 -0400 Subject: [PATCH 041/339] Added TODO --- runtime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index a9ecdaef..a774bc97 100644 --- a/runtime.c +++ b/runtime.c @@ -2608,7 +2608,9 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; gc_ans[i] = args[i]; } - // TODO: move mutations to heap (any stack-allocated globals must be here, too) +TODO: move mutations to heap (any stack-allocated globals must be here, too) +but that complicates the block below. is there a better way to do this? +ideally want to minimize changes to scheme code as well... { list l; for (l = mutation_table; !nullp(l); l = cdr(l)) { From 15052746401fff8c7b6c90d4d6fc4421b16dd007 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 00:17:53 -0400 Subject: [PATCH 042/339] Explicit GC of globals during minor collection, at least for now --- runtime.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/runtime.c b/runtime.c index a774bc97..65e4d0ab 100644 --- a/runtime.c +++ b/runtime.c @@ -2608,9 +2608,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; gc_ans[i] = args[i]; } -TODO: move mutations to heap (any stack-allocated globals must be here, too) -but that complicates the block below. is there a better way to do this? -ideally want to minimize changes to scheme code as well... + // Transport mutations { list l; for (l = mutation_table; !nullp(l); l = cdr(l)) { @@ -2634,6 +2632,16 @@ ideally want to minimize changes to scheme code as well... } clear_mutations(); // Reset for next time + // Transport globals + gc_move2heap(Cyc_global_variables); // Internal global used by the runtime + { + list l = global_table; + for(; !nullp(l); l = cdr(l)){ + cvar_type *c = (cvar_type *)car(l); + gc_move2heap(*(c->pvar)); // Transport underlying global, not the pvar + } + } + // Check allocated objects, moving additional objects as needed while (scani < alloci) { object obj = Cyc_thread->moveBuf[scani]; From 87def0fc67edbb852e5bafe147bc17552fe98b59 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 00:33:42 -0400 Subject: [PATCH 043/339] Noted TODO --- runtime.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime.c b/runtime.c index 65e4d0ab..ef2baf1b 100644 --- a/runtime.c +++ b/runtime.c @@ -2593,6 +2593,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work int heap_grown = 0; +fprintf("DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer if (num_args > NUM_GC_ANS) { printf("Fatal error - too many arguments (%d) to GC\n", num_args); @@ -2706,11 +2707,14 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; // Check if we need to do a major GC if (heap_grown) { size_t freed = 0; - // TODO: not good enough, need to pass current cont/args - // what about mutation barrier, do we care at this point??? +fprintf("DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG + TODO: not good enough, need to pass current cont/args + what about mutation barrier, do we care at this point??? + I don't think so because those are just updates to globals gc_collect(Cyc_heap, &freed); } +fprintf("DEBUG, finished minor GC\n"); // JAE DEBUG longjmp(jmp_main,1); // Return globals gc_cont, gc_ans } From 20e71fff3ba60f344df5ca1d10c93394df2f8026 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 01:54:15 -0400 Subject: [PATCH 044/339] Bug fixes --- include/cyclone/runtime.h | 2 ++ runtime.c | 16 +++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 78b2d12c..45e75e1a 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -209,6 +209,8 @@ void dispatch_va(int argc, function_type_va func, object clo, object cont, objec void do_dispatch(int argc, function_type func, object clo, object *buffer); /* Global variables. */ +extern gc_heap *Cyc_heap; +extern gc_thread_data *Cyc_thread; extern clock_t start; /* Starting time. */ extern char *stack_begin; /* Initialized by main. */ extern char *stack_limit1; /* Initialized by main. */ diff --git a/runtime.c b/runtime.c index ef2baf1b..e3cb758a 100644 --- a/runtime.c +++ b/runtime.c @@ -9,9 +9,6 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" -gc_heap *Cyc_heap; -gc_thread_data *Cyc_thread; - /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ const char *tag_names[21] = { \ @@ -2593,7 +2590,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work int heap_grown = 0; -fprintf("DEBUG, started minor GC\n"); // JAE DEBUG +fprintf(stderr, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer if (num_args > NUM_GC_ANS) { printf("Fatal error - too many arguments (%d) to GC\n", num_args); @@ -2707,14 +2704,15 @@ fprintf("DEBUG, started minor GC\n"); // JAE DEBUG // Check if we need to do a major GC if (heap_grown) { size_t freed = 0; -fprintf("DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG - TODO: not good enough, need to pass current cont/args - what about mutation barrier, do we care at this point??? - I don't think so because those are just updates to globals +fprintf(stderr, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG + gc_mark(Cyc_heap, cont); + for (i = 0; i < num_args; i++){ + gc_mark(Cyc_heap, args[i]); + } gc_collect(Cyc_heap, &freed); } -fprintf("DEBUG, finished minor GC\n"); // JAE DEBUG +fprintf(stderr, "DEBUG, finished minor GC\n"); // JAE DEBUG longjmp(jmp_main,1); // Return globals gc_cont, gc_ans } From fb389a019f298a844d755f2ae341af207c7dc9a3 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 01:57:16 -0400 Subject: [PATCH 045/339] More bug fixes --- include/cyclone/runtime-main.h | 2 +- runtime.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 012ece81..c26a0f81 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -57,7 +57,7 @@ static void Cyc_main (stack_size,heap_size,stack_base) printf("main: Allocating and initializing heap...\n"); #endif - Cyc_heap = gc_heap_create(heap_size, 0); + Cyc_heap = gc_heap_create(heap_size, 0, 0); Cyc_thread = (gc_thread_data *)malloc(sizeof(gc_thread_data)); Cyc_thread->moveBufLen = 0; gc_thr_grow_move_buffer(Cyc_thread); // Initialize the buffer diff --git a/runtime.c b/runtime.c index e3cb758a..a60e70a8 100644 --- a/runtime.c +++ b/runtime.c @@ -76,6 +76,8 @@ void Cyc_check_bounds(const char *label, int len, int index) { /*END closcall section */ /* Global variables. */ +gc_heap *Cyc_heap; +gc_thread_data *Cyc_thread; clock_t start; /* Starting time. */ char *stack_begin; /* Initialized by main. */ char *stack_limit1; /* Initialized by main. */ From 137305bbc9e264fd0075ec25d7374aecab7ed1f6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 02:13:31 -0400 Subject: [PATCH 046/339] Bug fixes --- runtime.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime.c b/runtime.c index a60e70a8..58a2054c 100644 --- a/runtime.c +++ b/runtime.c @@ -2382,7 +2382,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { switch(type_of(obj)){ case cons_tag: { - list hobj = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); + list hobj = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hobj ==> new heap object hobj->hdr.mark = 0; type_of(hobj) = cons_tag; car(hobj) = car(obj); @@ -2473,7 +2473,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { case closureN_tag: { int i; closureN_type *hobj = gc_alloc(Cyc_heap, - sizeof(closureN_type) + sizeof(object) * hobj->num_elt, + sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), heap_grown); mark(hobj) = 0; type_of(hobj) = closureN_tag; @@ -2491,7 +2491,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { case vector_tag: { int i; vector_type *hobj = gc_alloc(Cyc_heap, - sizeof(vector_type) + sizeof(object) * hobj->num_elt, + sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), heap_grown); mark(hobj) = 0; type_of(hobj) = vector_tag; From 1664e20d4cf9ecff587fe87c5da7b63916954a53 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 02:20:48 -0400 Subject: [PATCH 047/339] Initialize elts member during heap allocation --- runtime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime.c b/runtime.c index 58a2054c..73756f49 100644 --- a/runtime.c +++ b/runtime.c @@ -2480,6 +2480,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { hobj->fn = ((closureN) obj)->fn; hobj->num_args = ((closureN) obj)->num_args; hobj->num_elt = ((closureN) obj)-> num_elt; + hobj->elts = (object *)(((char *)hobj) + sizeof(closureN_type)); for (i = 0; i < hobj->num_elt; i++) { hobj->elts[i] = ((closureN) obj)->elts[i]; } @@ -2496,6 +2497,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { mark(hobj) = 0; type_of(hobj) = vector_tag; hobj->num_elt = ((vector) obj)-> num_elt; + hobj->elts = (object *)(((char *)hobj) + sizeof(vector_type)); for (i = 0; i < hobj->num_elt; i++) { hobj->elts[i] = ((vector) obj)->elts[i]; } From a6fc1999072a19c66722ca0f123d239cd3b154a8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 19 Oct 2015 22:02:45 -0400 Subject: [PATCH 048/339] Bugfix in allocating cons cell, cdr was being set to null. Also updated move2heap code to use 'hp' as the destination object. Using hobj and obj seemed to be asking for trouble. --- runtime.c | 258 ++++++++++++++++++++++++------------------------ scheme/eval.sld | 5 +- 2 files changed, 132 insertions(+), 131 deletions(-) diff --git a/runtime.c b/runtime.c index 73756f49..04060d72 100644 --- a/runtime.c +++ b/runtime.c @@ -2382,186 +2382,186 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { switch(type_of(obj)){ case cons_tag: { - list hobj = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hobj ==> new heap object - hobj->hdr.mark = 0; - type_of(hobj) = cons_tag; - car(hobj) = car(obj); - cdr(hobj) = cdr(hobj); - forward(obj) = hobj; + list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object + hp->hdr.mark = 0; + type_of(hp) = cons_tag; + car(hp) = car(obj); + cdr(hp) = cdr(obj); + forward(obj) = hp; type_of(obj) = forward_tag; // keep track of each allocation so we can scan/move // the whole live object 'tree' - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case macro_tag: { - macro_type *hobj = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = macro_tag; - hobj->fn = ((macro) obj)->fn; - hobj->num_args = ((macro) obj)->num_args; - forward(obj) = hobj; + macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown); + mark(hp) = 0; + type_of(hp) = macro_tag; + hp->fn = ((macro) obj)->fn; + hp->num_args = ((macro) obj)->num_args; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closure0_tag: { - closure0_type *hobj = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closure0_tag; - hobj->fn = ((closure0) obj)->fn; - hobj->num_args = ((closure0) obj)->num_args; - forward(obj) = hobj; + closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown); + mark(hp) = 0; + type_of(hp) = closure0_tag; + hp->fn = ((closure0) obj)->fn; + hp->num_args = ((closure0) obj)->num_args; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closure1_tag: { - closure1_type *hobj = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closure1_tag; - hobj->fn = ((closure1) obj)->fn; - hobj->num_args = ((closure1) obj)->num_args; - hobj->elt1 = ((closure1) obj)->elt1; - forward(obj) = hobj; + closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown); + mark(hp) = 0; + type_of(hp) = closure1_tag; + hp->fn = ((closure1) obj)->fn; + hp->num_args = ((closure1) obj)->num_args; + hp->elt1 = ((closure1) obj)->elt1; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closure2_tag: { - closure2_type *hobj = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closure2_tag; - hobj->fn = ((closure2) obj)->fn; - hobj->num_args = ((closure2) obj)->num_args; - hobj->elt1 = ((closure2) obj)->elt1; - hobj->elt2 = ((closure2) obj)->elt2; - forward(obj) = hobj; + closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown); + mark(hp) = 0; + type_of(hp) = closure2_tag; + hp->fn = ((closure2) obj)->fn; + hp->num_args = ((closure2) obj)->num_args; + hp->elt1 = ((closure2) obj)->elt1; + hp->elt2 = ((closure2) obj)->elt2; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closure3_tag: { - closure3_type *hobj = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closure3_tag; - hobj->fn = ((closure3) obj)->fn; - hobj->num_args = ((closure3) obj)->num_args; - hobj->elt1 = ((closure3) obj)->elt1; - hobj->elt2 = ((closure3) obj)->elt2; - hobj->elt3 = ((closure3) obj)->elt3; - forward(obj) = hobj; + closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown); + mark(hp) = 0; + type_of(hp) = closure3_tag; + hp->fn = ((closure3) obj)->fn; + hp->num_args = ((closure3) obj)->num_args; + hp->elt1 = ((closure3) obj)->elt1; + hp->elt2 = ((closure3) obj)->elt2; + hp->elt3 = ((closure3) obj)->elt3; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closure4_tag: { - closure4_type *hobj = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closure4_tag; - hobj->fn = ((closure4) obj)->fn; - hobj->num_args = ((closure4) obj)->num_args; - hobj->elt1 = ((closure4) obj)->elt1; - hobj->elt2 = ((closure4) obj)->elt2; - hobj->elt3 = ((closure4) obj)->elt3; - hobj->elt4 = ((closure4) obj)->elt4; - forward(obj) = hobj; + closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown); + mark(hp) = 0; + type_of(hp) = closure4_tag; + hp->fn = ((closure4) obj)->fn; + hp->num_args = ((closure4) obj)->num_args; + hp->elt1 = ((closure4) obj)->elt1; + hp->elt2 = ((closure4) obj)->elt2; + hp->elt3 = ((closure4) obj)->elt3; + hp->elt4 = ((closure4) obj)->elt4; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case closureN_tag: { int i; - closureN_type *hobj = gc_alloc(Cyc_heap, + closureN_type *hp = gc_alloc(Cyc_heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), heap_grown); - mark(hobj) = 0; - type_of(hobj) = closureN_tag; - hobj->fn = ((closureN) obj)->fn; - hobj->num_args = ((closureN) obj)->num_args; - hobj->num_elt = ((closureN) obj)-> num_elt; - hobj->elts = (object *)(((char *)hobj) + sizeof(closureN_type)); - for (i = 0; i < hobj->num_elt; i++) { - hobj->elts[i] = ((closureN) obj)->elts[i]; + mark(hp) = 0; + type_of(hp) = closureN_tag; + hp->fn = ((closureN) obj)->fn; + hp->num_args = ((closureN) obj)->num_args; + hp->num_elt = ((closureN) obj)-> num_elt; + hp->elts = (object *)(((char *)hp) + sizeof(closureN_type)); + for (i = 0; i < hp->num_elt; i++) { + hp->elts[i] = ((closureN) obj)->elts[i]; } - forward(obj) = hobj; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case vector_tag: { int i; - vector_type *hobj = gc_alloc(Cyc_heap, + vector_type *hp = gc_alloc(Cyc_heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), heap_grown); - mark(hobj) = 0; - type_of(hobj) = vector_tag; - hobj->num_elt = ((vector) obj)-> num_elt; - hobj->elts = (object *)(((char *)hobj) + sizeof(vector_type)); - for (i = 0; i < hobj->num_elt; i++) { - hobj->elts[i] = ((vector) obj)->elts[i]; + mark(hp) = 0; + type_of(hp) = vector_tag; + hp->num_elt = ((vector) obj)-> num_elt; + hp->elts = (object *)(((char *)hp) + sizeof(vector_type)); + for (i = 0; i < hp->num_elt; i++) { + hp->elts[i] = ((vector) obj)->elts[i]; } - forward(obj) = hobj; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case string_tag: { char *s; - string_type *hobj = gc_alloc(Cyc_heap, + string_type *hp = gc_alloc(Cyc_heap, sizeof(string_type) + ((string_len(obj) + 1)), heap_grown); - s = ((char *)hobj) + sizeof(string_type); + s = ((char *)hp) + sizeof(string_type); memcpy(s, string_str(obj), string_len(obj) + 1); - mark(hobj) = 0; - type_of(hobj) = string_tag; - string_len(hobj) = string_len(obj); - string_str(hobj) = s; - forward(obj) = hobj; + mark(hp) = 0; + type_of(hp) = string_tag; + string_len(hp) = string_len(obj); + string_str(hp) = s; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case integer_tag: { - integer_type *hobj = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = integer_tag; - hobj->value = ((integer_type *) obj)->value; - forward(obj) = hobj; + integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); + mark(hp) = 0; + type_of(hp) = integer_tag; + hp->value = ((integer_type *) obj)->value; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case double_tag: { - double_type *hobj = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = double_tag; - hobj->value = ((double_type *) obj)->value; - forward(obj) = hobj; + double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown); + mark(hp) = 0; + type_of(hp) = double_tag; + hp->value = ((double_type *) obj)->value; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case port_tag: { - port_type *hobj = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = port_tag; - hobj->fp = ((port_type *) obj)->fp; - hobj->mode = ((port_type *) obj)->mode; - forward(obj) = hobj; + port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown); + mark(hp) = 0; + type_of(hp) = port_tag; + hp->fp = ((port_type *) obj)->fp; + hp->mode = ((port_type *) obj)->mode; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case cvar_tag: { - cvar_type *hobj = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown); - mark(hobj) = 0; - type_of(hobj) = cvar_tag; - hobj->pvar = ((cvar_type *) obj)->pvar; - forward(obj) = hobj; + cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown); + mark(hp) = 0; + type_of(hp) = cvar_tag; + hp->pvar = ((cvar_type *) obj)->pvar; + forward(obj) = hp; type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hobj); - return (char *)hobj; + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; } case forward_tag: return (char *)forward(obj); @@ -2594,7 +2594,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work int heap_grown = 0; -fprintf(stderr, "DEBUG, started minor GC\n"); // JAE DEBUG +fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer if (num_args > NUM_GC_ANS) { printf("Fatal error - too many arguments (%d) to GC\n", num_args); @@ -2708,7 +2708,7 @@ fprintf(stderr, "DEBUG, started minor GC\n"); // JAE DEBUG // Check if we need to do a major GC if (heap_grown) { size_t freed = 0; -fprintf(stderr, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG +fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG gc_mark(Cyc_heap, cont); for (i = 0; i < num_args; i++){ gc_mark(Cyc_heap, args[i]); @@ -2716,7 +2716,7 @@ fprintf(stderr, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG gc_collect(Cyc_heap, &freed); } -fprintf(stderr, "DEBUG, finished minor GC\n"); // JAE DEBUG +fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG longjmp(jmp_main,1); // Return globals gc_cont, gc_ans } diff --git a/scheme/eval.sld b/scheme/eval.sld index 45f69be6..71c04bd6 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -11,7 +11,7 @@ ;(scheme cyclone libraries) ;; for handling import sets (scheme base) (scheme file) - ;(scheme write) ;; Only used for debugging + (scheme write) ;; Only used for debugging (scheme read)) (export ;environment @@ -252,7 +252,8 @@ primitive-procedures)) (define (primitive-procedure-objects) - (map (lambda (proc) (list 'primitive (cadr proc))) + (write `(DEBUG ,primitive-procedures)) + (map (lambda (proc) (write `(DEBUG2 ,proc)) (list 'primitive (cadr proc))) primitive-procedures)) (define (apply-primitive-procedure proc args) From da4e7a9d87e111caf120135ff6bfd51504c3e5b8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 18:43:02 -0400 Subject: [PATCH 049/339] Removed debug code --- scheme/eval.sld | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scheme/eval.sld b/scheme/eval.sld index 71c04bd6..45f69be6 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -11,7 +11,7 @@ ;(scheme cyclone libraries) ;; for handling import sets (scheme base) (scheme file) - (scheme write) ;; Only used for debugging + ;(scheme write) ;; Only used for debugging (scheme read)) (export ;environment @@ -252,8 +252,7 @@ primitive-procedures)) (define (primitive-procedure-objects) - (write `(DEBUG ,primitive-procedures)) - (map (lambda (proc) (write `(DEBUG2 ,proc)) (list 'primitive (cadr proc))) + (map (lambda (proc) (list 'primitive (cadr proc))) primitive-procedures)) (define (apply-primitive-procedure proc args) From e5277abfb80ad8919ff9f0aa9ddca4564d40984d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 21:15:17 -0400 Subject: [PATCH 050/339] Copy gc.c during bootstrap --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2d285843..abafa8ca 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ bootstrap: icyc cp scheme/*.sld $(BOOTSTRAP_DIR)/scheme cp scheme/cyclone/*.sld $(BOOTSTRAP_DIR)/scheme/cyclone cp runtime.c $(BOOTSTRAP_DIR) + cp gc.c $(BOOTSTRAP_DIR) cp dispatch.c $(BOOTSTRAP_DIR) cp scheme/base.c $(BOOTSTRAP_DIR)/scheme cp scheme/read.c $(BOOTSTRAP_DIR)/scheme From 4ce75a2213755d31df922dc86dfc92db85a0172e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 22:32:27 -0400 Subject: [PATCH 051/339] Debugging mark/sweep algorithms --- gc.c | 4 ++-- include/cyclone/types.h | 5 ++--- runtime.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/gc.c b/gc.c index fd657823..d11a33d4 100644 --- a/gc.c +++ b/gc.c @@ -161,7 +161,7 @@ size_t gc_heap_total_size(gc_heap *h) void gc_mark(gc_heap *h, object obj) { - if (!obj || is_marked(obj)) + if (nullp(obj) || is_value_type(obj) || mark(obj)) return; #if GC_DEBUG_PRINTFS @@ -232,7 +232,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) // END DEBUG #endif - if (!is_marked(p)) { + if (!mark(p)) { #if GC_DEBUG_PRINTFS fprintf(stdout, "sweep: object is not marked %p\n", p); #endif diff --git a/include/cyclone/types.h b/include/cyclone/types.h index f773535a..841ce5a0 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -51,7 +51,6 @@ struct gc_header_type_t { unsigned int mark; // mark bits (only need 2) // TODO: forwarding address (probably not needed for mark/sweep), anything else??? }; -#define is_marked(x) (is_object_type(x) && ((list)x)->hdr.mark) #define mark(x) (((list) x)->hdr.mark) /* HEAP definitions */ @@ -76,13 +75,13 @@ gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); void gc_mark(gc_heap *h, object obj); size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); -void gc_collect(gc_heap *h, size_t *sum_freed); +size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); /* GC debugging flags */ //#define DEBUG_GC 0 -#define GC_DEBUG_PRINTFS 0 +#define GC_DEBUG_PRINTFS 1 /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 diff --git a/runtime.c b/runtime.c index 04060d72..dac32078 100644 --- a/runtime.c +++ b/runtime.c @@ -2353,7 +2353,7 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { // if the heap was expanded during alloc, and after all the allocs are done // after a minor GC (or during the minor GC), call into this function to // free up unused space -void gc_collect(gc_heap *h, size_t *sum_freed) +size_t gc_collect(gc_heap *h, size_t *sum_freed) { printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); // Mark global variables @@ -2369,7 +2369,7 @@ void gc_collect(gc_heap *h, size_t *sum_freed) // conservative mark? // weak refs? // finalize? - gc_sweep(h, sum_freed); + return gc_sweep(h, sum_freed); // debug print free stats // return value from sweep?? } @@ -2594,7 +2594,7 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work int heap_grown = 0; -fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG +//fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer if (num_args > NUM_GC_ANS) { printf("Fatal error - too many arguments (%d) to GC\n", num_args); @@ -2707,16 +2707,18 @@ fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Check if we need to do a major GC if (heap_grown) { - size_t freed = 0; + size_t freed = 0, max_freed = 0; fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG gc_mark(Cyc_heap, cont); for (i = 0; i < num_args; i++){ gc_mark(Cyc_heap, args[i]); } - gc_collect(Cyc_heap, &freed); + max_freed = gc_collect(Cyc_heap, &freed); +printf("done, freed = %d, max_freed = %d\n", freed, max_freed); +exit(1); // JAE DEBUG } -fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG +//fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG longjmp(jmp_main,1); // Return globals gc_cont, gc_ans } From 0eb6be21d4c9c5907dc2da3e558133a74944e45a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 23:06:48 -0400 Subject: [PATCH 052/339] Remove debug code --- runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index dac32078..64975bf5 100644 --- a/runtime.c +++ b/runtime.c @@ -2715,7 +2715,7 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG } max_freed = gc_collect(Cyc_heap, &freed); printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -exit(1); // JAE DEBUG +//exit(1); // JAE DEBUG } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From 4beac74189e37f480cb4cecdf0a081144116748c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 20 Oct 2015 23:07:10 -0400 Subject: [PATCH 053/339] WIP --- gc.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index d11a33d4..3ef09817 100644 --- a/gc.c +++ b/gc.c @@ -74,29 +74,27 @@ void *gc_try_alloc(gc_heap *h, size_t size) void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) { void *result = NULL; - size_t max_freed, sum_freed, total_size; + size_t max_freed = 0, sum_freed = 0, total_size; // TODO: check return value, if null (could not alloc) then // run a collection and check how much free space there is. if less // the allowed ratio, try growing heap. // then try realloc. if cannot alloc now, then throw out of memory error size = gc_heap_align(size); - //return gc_try_alloc(h, size); result = gc_try_alloc(h, size); if (!result) { // TODO: may want to consider not doing this now, and implementing gc_collect as // part of the runtime, since we would have all of the roots, stack args, // etc available there. // max_freed = gc_collect(h); TODO: this does not work yet! -max_freed = 0; - - total_size = gc_heap_total_size(h); - if (((max_freed < size) || - ((total_size > sum_freed) && - (total_size - sum_freed) > (total_size * 0.75))) // Grow ratio - && ((!h->max_size) || (total_size < h->max_size))) { +// +// total_size = gc_heap_total_size(h); +// if (((max_freed < size) || +// ((total_size > sum_freed) && +// (total_size - sum_freed) > (total_size * 0.75))) // Grow ratio +// && ((!h->max_size) || (total_size < h->max_size))) { gc_grow_heap(h, size, 0); *heap_grown = 1; - } +// } result = gc_try_alloc(h, size); if (!result) { fprintf(stderr, "out of memory error allocating %d bytes\n", size); @@ -104,7 +102,7 @@ max_freed = 0; } } #if GC_DEBUG_PRINTFS - fprintf(stdout, "alloc %p\n", result); +// fprintf(stdout, "alloc %p\n", result); #endif return result; } @@ -165,7 +163,7 @@ void gc_mark(gc_heap *h, object obj) return; #if GC_DEBUG_PRINTFS - fprintf(stdout, "gc_mark %p\n", obj); +// fprintf(stdout, "gc_mark %p\n", obj); #endif ((list)obj)->hdr.mark = 1; // TODO: mark heap saves (??) @@ -234,7 +232,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (!mark(p)) { #if GC_DEBUG_PRINTFS - fprintf(stdout, "sweep: object is not marked %p\n", p); +// fprintf(stdout, "sweep: object is not marked %p\n", p); #endif // free p sum_freed += size; @@ -270,7 +268,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) max_freed = freed; } else { #if GC_DEBUG_PRINTFS - fprintf(stdout, "sweep: object is marked %p\n", p); +// fprintf(stdout, "sweep: object is marked %p\n", p); #endif ((list)p)->hdr.mark = 0; p = (object)(((char *)p) + size); From ee01b2679b17cdbac8bd8a9fc64c5acda46a6749 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 21 Oct 2015 22:55:58 -0400 Subject: [PATCH 054/339] Added debug code --- gc.c | 4 ++-- include/cyclone/runtime-main.h | 3 ++- runtime.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 3ef09817..a88d1af0 100644 --- a/gc.c +++ b/gc.c @@ -219,7 +219,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) } size = gc_heap_align(gc_allocated_bytes(p)); -#if GC_DEBUG_PRINTFS +//#if GC_DEBUG_PRINTFS // DEBUG if (!is_object_type(p)) fprintf(stderr, "sweep: invalid object at %p", p); @@ -228,7 +228,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (r && ((char *)p) + size > (char *)r) fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); // END DEBUG -#endif +//#endif if (!mark(p)) { #if GC_DEBUG_PRINTFS diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index c26a0f81..c8476c1e 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -57,7 +57,8 @@ static void Cyc_main (stack_size,heap_size,stack_base) printf("main: Allocating and initializing heap...\n"); #endif - Cyc_heap = gc_heap_create(heap_size, 0, 0); + //Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); + Cyc_heap = gc_heap_create(1024, 0, 0); Cyc_thread = (gc_thread_data *)malloc(sizeof(gc_thread_data)); Cyc_thread->moveBufLen = 0; gc_thr_grow_move_buffer(Cyc_thread); // Initialize the buffer diff --git a/runtime.c b/runtime.c index 64975bf5..41e89435 100644 --- a/runtime.c +++ b/runtime.c @@ -2380,6 +2380,7 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed) char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; +printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ case cons_tag: { list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object From c10d7c7829612c82a5de7bd652c7b8f67330a7fa Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 22 Oct 2015 22:23:43 -0400 Subject: [PATCH 055/339] Account for heap header when alloc memory for heap --- gc.c | 16 ++++++++++++---- include/cyclone/types.h | 1 + runtime.c | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index a88d1af0..37752593 100644 --- a/gc.c +++ b/gc.c @@ -17,7 +17,7 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) gc_free_list *free, *next; gc_heap *h; // TODO: mmap? - h = malloc(size); + h = malloc(gc_heap_pad_size(size)); if (!h) return NULL; h->size = size; h->chunk_size = chunk_size; @@ -32,6 +32,14 @@ printf("DEBUG h->data addr: %p\n", h->data); free->next = next; next->size = size - gc_heap_align(gc_free_chunk_size); next->next = NULL; +//#if GC_DEBUG_PRINTFS + fprintf(stderr, ("heap: %p-%p data: %p-%p"), + h, ((char*)h)+sexp_heap_pad_size(size), h->data, h->data + size); + fprintf(stderr, ("first: %p end: %p"), + (object)sexp_heap_first_block(h), (object)sexp_heap_end(h)); + fprintf(stderr, ("free1: %p-%p free2: %p-%p"), + free, ((char*)free)+free->size, next, ((char*)next)+next->size); +//#endif return h; } @@ -101,9 +109,9 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) exit(1); // TODO: throw error??? } } -#if GC_DEBUG_PRINTFS -// fprintf(stdout, "alloc %p\n", result); -#endif +//#if GC_DEBUG_PRINTFS + fprintf(stdout, "alloc %p size = %d\n", result, size); +//#endif return result; } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 841ce5a0..d8fc47d1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -58,6 +58,7 @@ struct gc_header_type_t { #define gc_heap_first_block(h) ((object)(h->data + gc_heap_align(gc_free_chunk_size))) #define gc_heap_last_block(h) ((object)((char*)h->data + h->size - gc_heap_align(gc_free_chunk_size))) #define gc_heap_end(h) ((object)((char*)h->data + h->size)) +#define gc_heap_pad_size(s) (sizeof(struct gc_heap_t) + (s) + gc_heap_align(1)) #define gc_free_chunk_size (sizeof(gc_free_list)) #define gc_align(n, bits) (((n)+(1<<(bits))-1)&(((unsigned int)-1)-((1<<(bits))-1))) diff --git a/runtime.c b/runtime.c index 41e89435..34429855 100644 --- a/runtime.c +++ b/runtime.c @@ -2716,7 +2716,7 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG } max_freed = gc_collect(Cyc_heap, &freed); printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -//exit(1); // JAE DEBUG +exit(1); // JAE DEBUG } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From 0d9e4c323492759a87e0ee718e39f3dedb9f0ae5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 22 Oct 2015 22:33:45 -0400 Subject: [PATCH 056/339] Bugfix --- gc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index 37752593..f0776323 100644 --- a/gc.c +++ b/gc.c @@ -34,9 +34,9 @@ printf("DEBUG h->data addr: %p\n", h->data); next->next = NULL; //#if GC_DEBUG_PRINTFS fprintf(stderr, ("heap: %p-%p data: %p-%p"), - h, ((char*)h)+sexp_heap_pad_size(size), h->data, h->data + size); + h, ((char*)h)+gc_heap_pad_size(size), h->data, h->data + size); fprintf(stderr, ("first: %p end: %p"), - (object)sexp_heap_first_block(h), (object)sexp_heap_end(h)); + (object)gc_heap_first_block(h), (object)gc_heap_end(h)); fprintf(stderr, ("free1: %p-%p free2: %p-%p"), free, ((char*)free)+free->size, next, ((char*)next)+next->size); //#endif From 849b28b54c5f7737a743b4220ce037059fe8f8a4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 02:32:15 -0400 Subject: [PATCH 057/339] Removed debug output --- gc.c | 18 +++++++++--------- include/cyclone/types.h | 2 +- runtime.c | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gc.c b/gc.c index f0776323..bbe82c85 100644 --- a/gc.c +++ b/gc.c @@ -22,9 +22,9 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) h->size = size; h->chunk_size = chunk_size; h->max_size = max_size; -printf("DEBUG h->data addr: %p\n", &(h->data)); +//printf("DEBUG h->data addr: %p\n", &(h->data)); h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); -printf("DEBUG h->data addr: %p\n", h->data); +//printf("DEBUG h->data addr: %p\n", h->data); h->next = NULL; free = h->free_list = (gc_free_list *)h->data; next = (gc_free_list *)(((char *) free) + gc_heap_align(gc_free_chunk_size)); @@ -32,14 +32,14 @@ printf("DEBUG h->data addr: %p\n", h->data); free->next = next; next->size = size - gc_heap_align(gc_free_chunk_size); next->next = NULL; -//#if GC_DEBUG_PRINTFS - fprintf(stderr, ("heap: %p-%p data: %p-%p"), +#if GC_DEBUG_PRINTFS + fprintf(stderr, ("heap: %p-%p data: %p-%p\n"), h, ((char*)h)+gc_heap_pad_size(size), h->data, h->data + size); - fprintf(stderr, ("first: %p end: %p"), + fprintf(stderr, ("first: %p end: %p\n"), (object)gc_heap_first_block(h), (object)gc_heap_end(h)); - fprintf(stderr, ("free1: %p-%p free2: %p-%p"), + fprintf(stderr, ("free1: %p-%p free2: %p-%p\n"), free, ((char*)free)+free->size, next, ((char*)next)+next->size); -//#endif +#endif return h; } @@ -109,9 +109,9 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) exit(1); // TODO: throw error??? } } -//#if GC_DEBUG_PRINTFS +#if GC_DEBUG_PRINTFS fprintf(stdout, "alloc %p size = %d\n", result, size); -//#endif +#endif return result; } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index d8fc47d1..90f8bf41 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -82,7 +82,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); /* GC debugging flags */ //#define DEBUG_GC 0 -#define GC_DEBUG_PRINTFS 1 +#define GC_DEBUG_PRINTFS 0 /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 diff --git a/runtime.c b/runtime.c index 34429855..f13ad143 100644 --- a/runtime.c +++ b/runtime.c @@ -2380,7 +2380,7 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed) char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; -printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG +//printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ case cons_tag: { list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object @@ -2716,7 +2716,7 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG } max_freed = gc_collect(Cyc_heap, &freed); printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -exit(1); // JAE DEBUG +//exit(1); // JAE DEBUG } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From 25303fc4a5398344b9ef0e964622c21df4518dd4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 02:44:55 -0400 Subject: [PATCH 058/339] Added temporary debug code to stop after 2 major GC's --- runtime.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index f13ad143..0a9de49d 100644 --- a/runtime.c +++ b/runtime.c @@ -9,6 +9,8 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" +int JAE_DEBUG = 0; + /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ const char *tag_names[21] = { \ @@ -2716,7 +2718,8 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG } max_freed = gc_collect(Cyc_heap, &freed); printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -//exit(1); // JAE DEBUG +JAE_DEBUG++; +if (JAE_DEBUG == 2) exit(1); // JAE DEBUG } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From a9c0411a16c632e734245ef867f85435728f475f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 22 Oct 2015 22:51:20 -0400 Subject: [PATCH 059/339] Bugfixes --- gc.c | 23 ++++++++++++++++------- include/cyclone/runtime-main.h | 4 ++-- runtime.c | 6 +++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/gc.c b/gc.c index bbe82c85..24e18b62 100644 --- a/gc.c +++ b/gc.c @@ -33,8 +33,8 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) next->size = size - gc_heap_align(gc_free_chunk_size); next->next = NULL; #if GC_DEBUG_PRINTFS - fprintf(stderr, ("heap: %p-%p data: %p-%p\n"), - h, ((char*)h)+gc_heap_pad_size(size), h->data, h->data + size); + fprintf(stderr, ("heap: %p-%p data: %p-%p size: %d\n"), + h, ((char*)h)+gc_heap_pad_size(size), h->data, h->data + size, size); fprintf(stderr, ("first: %p end: %p\n"), (object)gc_heap_first_block(h), (object)gc_heap_end(h)); fprintf(stderr, ("free1: %p-%p free2: %p-%p\n"), @@ -49,8 +49,8 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) gc_heap *h_last = gc_heap_last(h); cur_size = h_last->size; new_size = gc_heap_align(((cur_size > size) ? cur_size : size) * 2); - h->next = gc_heap_create(new_size, h->max_size, chunk_size); - return (h->next != NULL); + h_last->next = gc_heap_create(new_size, h_last->max_size, chunk_size); + return (h_last->next != NULL); } void *gc_try_alloc(gc_heap *h, size_t size) @@ -142,9 +142,10 @@ size_t gc_allocated_bytes(object obj) if (t == port_tag) return gc_heap_align(sizeof(port_type)); if (t == cvar_tag) return gc_heap_align(sizeof(cvar_type)); -#if GC_DEBUG_PRINTFS +//#if GC_DEBUG_PRINTFS fprintf(stderr, "gc_allocated_bytes: unexpected object %p of type %ld\n", obj, t); -#endif + exit(1); +//#endif return 0; } @@ -214,6 +215,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) object p, end; gc_free_list *q, *r, *s; for (; h; h = h->next) { // All heaps +fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); p = gc_heap_first_block(h); q = h->free_list; end = gc_heap_end(h); @@ -223,9 +225,11 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if ((char *)r == (char *)p) { // this is a free block, skip it p = (object) (((char *)p) + r->size); +fprintf(stdout, "skip free block %p size = %d\n", p, r->size); continue; } size = gc_heap_align(gc_allocated_bytes(p)); +//fprintf(stdout, "check object %p, size = %d\n", p, size); //#if GC_DEBUG_PRINTFS // DEBUG @@ -240,7 +244,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (!mark(p)) { #if GC_DEBUG_PRINTFS -// fprintf(stdout, "sweep: object is not marked %p\n", p); + fprintf(stdout, "sweep: object is not marked %p\n", p); #endif // free p sum_freed += size; @@ -278,6 +282,11 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) #if GC_DEBUG_PRINTFS // fprintf(stdout, "sweep: object is marked %p\n", p); #endif + //if (mark(p) != 1) { + // printf("unexpected mark value %d\n", mark(p)); + // exit(1); + //} + ((list)p)->hdr.mark = 0; p = (object)(((char *)p) + size); } diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index c8476c1e..ad98878a 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -57,8 +57,8 @@ static void Cyc_main (stack_size,heap_size,stack_base) printf("main: Allocating and initializing heap...\n"); #endif - //Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - Cyc_heap = gc_heap_create(1024, 0, 0); + Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); + //Cyc_heap = gc_heap_create(1024, 0, 0); Cyc_thread = (gc_thread_data *)malloc(sizeof(gc_thread_data)); Cyc_thread->moveBufLen = 0; gc_thr_grow_move_buffer(Cyc_thread); // Initialize the buffer diff --git a/runtime.c b/runtime.c index 0a9de49d..bf376f2f 100644 --- a/runtime.c +++ b/runtime.c @@ -9,7 +9,7 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" -int JAE_DEBUG = 0; +//int JAE_DEBUG = 0; /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ @@ -2718,8 +2718,8 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG } max_freed = gc_collect(Cyc_heap, &freed); printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -JAE_DEBUG++; -if (JAE_DEBUG == 2) exit(1); // JAE DEBUG +//JAE_DEBUG++; +//if (JAE_DEBUG == 2) exit(1); // JAE DEBUG } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From 7a45137ca2d1360d63d12304e8aa8dd3c6001129 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 19:48:55 -0400 Subject: [PATCH 060/339] Added debug statements --- gc.c | 5 ++++- runtime.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index 24e18b62..b15d5c07 100644 --- a/gc.c +++ b/gc.c @@ -225,7 +225,9 @@ fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); if ((char *)r == (char *)p) { // this is a free block, skip it p = (object) (((char *)p) + r->size); -fprintf(stdout, "skip free block %p size = %d\n", p, r->size); +#if GC_DEBUG_PRINTFS + fprintf(stdout, "skip free block %p size = %d\n", p, r->size); +#endif continue; } size = gc_heap_align(gc_allocated_bytes(p)); @@ -308,6 +310,7 @@ void gc_thr_grow_move_buffer(gc_thread_data *d) } d->moveBuf = realloc(d->moveBuf, d->moveBufLen * sizeof(void *)); + printf("grew moveBuffer, len = %d\n", d->moveBufLen); } void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) diff --git a/runtime.c b/runtime.c index bf376f2f..662cc26b 100644 --- a/runtime.c +++ b/runtime.c @@ -2708,8 +2708,11 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; scani++; } +//fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); + // Check if we need to do a major GC if (heap_grown) { + time_t majorStart = time(NULL); size_t freed = 0, max_freed = 0; fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG gc_mark(Cyc_heap, cont); @@ -2717,7 +2720,7 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG gc_mark(Cyc_heap, args[i]); } max_freed = gc_collect(Cyc_heap, &freed); -printf("done, freed = %d, max_freed = %d\n", freed, max_freed); +printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); //JAE_DEBUG++; //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG } From 31a2b276b348fc67c1730f60cd095699f55f810c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 22:13:11 -0400 Subject: [PATCH 061/339] Measuring and attempting to improve performance --- gc.c | 5 +++-- include/cyclone/types.h | 2 +- runtime.c | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index b15d5c07..8bc85749 100644 --- a/gc.c +++ b/gc.c @@ -48,7 +48,8 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) size_t cur_size, new_size; gc_heap *h_last = gc_heap_last(h); cur_size = h_last->size; - new_size = gc_heap_align(((cur_size > size) ? cur_size : size) * 2); + // JAE - For now, just add a new page + new_size = cur_size; //gc_heap_align(((cur_size > size) ? cur_size : size) * 2); h_last->next = gc_heap_create(new_size, h_last->max_size, chunk_size); return (h_last->next != NULL); } @@ -71,7 +72,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) f1->next = f2->next; } // zero-out the header - memset((object)f2, 0, sizeof(gc_header_type)); + //memset((object)f2, 0, sizeof(gc_header_type)); return f2; } } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 90f8bf41..69b44e01 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -94,7 +94,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); #define STACK_GROWS_DOWNWARD 1 /* Size of the stack buffer, in bytes. */ -#define STACK_SIZE 100000 +#define STACK_SIZE 500000 /* Size of the 2nd generation, in bytes. */ #define HEAP_SIZE 6000000 diff --git a/runtime.c b/runtime.c index 662cc26b..a3c8477e 100644 --- a/runtime.c +++ b/runtime.c @@ -10,6 +10,7 @@ #include "cyclone/runtime.h" //int JAE_DEBUG = 0; +int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ @@ -2382,6 +2383,8 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed) char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; +gcMoveCountsDEBUG[type_of(obj)]++; + //printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ case cons_tag: { @@ -2723,6 +2726,8 @@ fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); //JAE_DEBUG++; //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG +for (i = 0; i < 20; i++){ + printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]);} } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From 8f0a044e726e3e81467a6d6e764e7635fc03ec87 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 22:52:07 -0400 Subject: [PATCH 062/339] Forgot >= and instead used > This makes a *HUGE* difference in performance, because otherwise it becomes problematic to re-use slots --- gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 8bc85749..213e5d83 100644 --- a/gc.c +++ b/gc.c @@ -61,7 +61,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) // TODO: chunk size (ignoring for now) for (f1 = h->free_list, f2 = f1->next; f2; f1 = f2, f2 = f2->next) { // all free in this heap - if (f2->size > size) { // Big enough for request + if (f2->size >= size) { // Big enough for request // TODO: take whole chunk or divide up f2 (using f3)? if (f2->size >= (size + gc_heap_align(1) /* min obj size */)) { f3 = (gc_free_list *) (((char *)f2) + size); From 2527edac266257426e3bef3540fcd4374230c4c0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 22:53:36 -0400 Subject: [PATCH 063/339] Reduce stack size to 1/4 MB for now --- include/cyclone/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 69b44e01..9768aec1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -94,7 +94,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); #define STACK_GROWS_DOWNWARD 1 /* Size of the stack buffer, in bytes. */ -#define STACK_SIZE 500000 +#define STACK_SIZE 250000 /* Size of the 2nd generation, in bytes. */ #define HEAP_SIZE 6000000 From 434bac8a2f27e87416f98f6fc3aa763f4599d1d9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 23 Oct 2015 22:58:57 -0400 Subject: [PATCH 064/339] Added gc-dev3 --- gc-notes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/gc-notes.txt b/gc-notes.txt index c704c36b..b2a36193 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -1,2 +1,3 @@ Phase 1 (gc-dev) - Add gc.h, make sure it compiles. Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and be compatible with a new GC algorithm. +Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. From bbf4914d30b95a4348f3fc448f60a8edbad5e5db Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 24 Oct 2015 00:58:06 -0400 Subject: [PATCH 065/339] Cleanup --- gc.c | 12 +++++++----- include/cyclone/types.h | 10 ++++++---- runtime.c | 41 ++++++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/gc.c b/gc.c index 213e5d83..7d4500b0 100644 --- a/gc.c +++ b/gc.c @@ -71,8 +71,6 @@ void *gc_try_alloc(gc_heap *h, size_t size) } else { /* Take the whole chunk */ f1->next = f2->next; } - // zero-out the header - //memset((object)f2, 0, sizeof(gc_header_type)); return f2; } } @@ -216,7 +214,9 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) object p, end; gc_free_list *q, *r, *s; for (; h; h = h->next) { // All heaps -fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); +#if GC_DEBUG_CONCISE_PRINTFS + fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); +#endif p = gc_heap_first_block(h); q = h->free_list; end = gc_heap_end(h); @@ -234,7 +234,7 @@ fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); size = gc_heap_align(gc_allocated_bytes(p)); //fprintf(stdout, "check object %p, size = %d\n", p, size); -//#if GC_DEBUG_PRINTFS +#if GC_DEBUG_CONCISE_PRINTFS // DEBUG if (!is_object_type(p)) fprintf(stderr, "sweep: invalid object at %p", p); @@ -243,7 +243,7 @@ fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); if (r && ((char *)p) + size > (char *)r) fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); // END DEBUG -//#endif +#endif if (!mark(p)) { #if GC_DEBUG_PRINTFS @@ -311,7 +311,9 @@ void gc_thr_grow_move_buffer(gc_thread_data *d) } d->moveBuf = realloc(d->moveBuf, d->moveBufLen * sizeof(void *)); +#if GC_DEBUG_CONCISE_PRINTFS printf("grew moveBuffer, len = %d\n", d->moveBufLen); +#endif } void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 9768aec1..ecf58721 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -83,6 +83,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); /* GC debugging flags */ //#define DEBUG_GC 0 #define GC_DEBUG_PRINTFS 0 +#define GC_DEBUG_CONCISE_PRINTFS 0 /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 @@ -93,13 +94,14 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); /* Which way does the CPU grow its stack? */ #define STACK_GROWS_DOWNWARD 1 -/* Size of the stack buffer, in bytes. */ +/* Size of the stack buffer, in bytes. + This is used as the first generation of the GC. */ #define STACK_SIZE 250000 -/* Size of the 2nd generation, in bytes. */ +/* Size of a "page" on the heap (the 2nd generation), in bytes. */ #define HEAP_SIZE 6000000 -/* Define size of object tags. Options are "short" or "long". */ +/* Define size of object tags */ typedef long tag_type; #ifndef CLOCKS_PER_SEC @@ -150,7 +152,7 @@ typedef long tag_type; have extra least significant bits that can be used to mark them as values instead of objects (IE, pointer to a tagged object). On many machines, addresses are multiples of four, leaving the two - least significant bits free - according to lisp in small pieces. + least significant bits free - from lisp in small pieces. */ #define obj_is_char(x) ((unsigned long)(x) & (unsigned long)1) #define obj_obj2char(x) (char)((long)(x)>>1) diff --git a/runtime.c b/runtime.c index a3c8477e..cd47312f 100644 --- a/runtime.c +++ b/runtime.c @@ -10,7 +10,7 @@ #include "cyclone/runtime.h" //int JAE_DEBUG = 0; -int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +//int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ @@ -2350,22 +2350,21 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} -// NEW GC algorithm -// -// TODO: not quite sure when to call this function. might want to set a flag -// if the heap was expanded during alloc, and after all the allocs are done -// after a minor GC (or during the minor GC), call into this function to -// free up unused space +// Collect garbage using mark&sweep algorithm +// Note non-global roots should be marked prior to calling this function. size_t gc_collect(gc_heap *h, size_t *sum_freed) { +#if GC_DEBUG_CONCISE_PRINTFS printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); +#endif // Mark global variables - gc_mark(h, Cyc_global_variables); /* Internal global used by the runtime */ + gc_mark(h, Cyc_global_variables); // Internal global used by the runtime + // Marking it ensures all glos are marked { list l = global_table; for(; !nullp(l); l = cdr(l)){ cvar_type *c = (cvar_type *)car(l); - gc_mark(h, *(c->pvar)); // Mark global, not the pvar + gc_mark(h, *(c->pvar)); // Mark actual object the global points to } } // TODO: what else to mark? gc_mark( @@ -2373,8 +2372,7 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed) // weak refs? // finalize? return gc_sweep(h, sum_freed); - // debug print free stats - // return value from sweep?? + // debug print free stats? } // TODO: move globals to thread-specific structures. @@ -2383,7 +2381,7 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed) char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; -gcMoveCountsDEBUG[type_of(obj)]++; +//gcMoveCountsDEBUG[type_of(obj)]++; //printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ @@ -2715,19 +2713,24 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; // Check if we need to do a major GC if (heap_grown) { - time_t majorStart = time(NULL); size_t freed = 0, max_freed = 0; -fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG +#if GC_DEBUG_CONCISE_PRINTFS + time_t majorStart = time(NULL); + fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG +#endif gc_mark(Cyc_heap, cont); for (i = 0; i < num_args; i++){ gc_mark(Cyc_heap, args[i]); } max_freed = gc_collect(Cyc_heap, &freed); -printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); -//JAE_DEBUG++; -//if (JAE_DEBUG == 2) exit(1); // JAE DEBUG -for (i = 0; i < 20; i++){ - printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]);} +#if GC_DEBUG_CONCISE_PRINTFS + printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); + //JAE_DEBUG++; + //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG + for (i = 0; i < 20; i++){ + printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]); + } +#endif } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG From d69f3c89ca57eb199ce72ce6bb370ef5f29c3712 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 26 Oct 2015 22:31:28 -0400 Subject: [PATCH 066/339] Starting to add types/functions for tri-color marking --- gc.c | 72 ++++++++++++++++++++++++++++++----------- include/cyclone/types.h | 2 ++ 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/gc.c b/gc.c index 7d4500b0..20983ae1 100644 --- a/gc.c +++ b/gc.c @@ -331,25 +331,6 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) // } // END heap definitions -/* tri-color GC stuff, we will care about this later... -int colorWhite = 0; -int colorGray = 1; -int colorBlack = 2; -int colorBlue = 3; - -typedef enum {STATUS_ASYNC, STATUS_SYNC1, STATUS_SYNC2} status_type; - -// DLG globals -static void *swept; -static int dirty; -static void *scanned; - -// TODO: mutator actions -// TODO: collector -// TODO: extentions -// TODO: proofs, etc -// TODO: revist design using content from kolodner -*/ // int main(int argc, char **argv) { // int i; @@ -394,3 +375,56 @@ static void *scanned; // // return 0; // } + +// tri-color GC section, WIP +// +// Note: will need to use atomics and/or locking to access any +// variables shared between threads +typedef enum { STATUS_ASYNC + , STATUS_SYNC1 + , STATUS_SYNC2 + } gc_status_type; + +typedef enum { STAGE_CLEAR_OR_MARKING + , STAGE_TRACING + , STAGE_REF_PROCESSING + , STAGE_SWEEPING + , STAGE_RESTING + } gc_stage_type; + +static int gc_color_mark = 0; // Black +static const int gc_color_grey = 1; +static int gc_color_clear = 2; // White +static const int gc_color_blue = 3; + +static int gc_status_coll; +static int gc_stage; + +// Mutator functions + +void gc_mut_update() +{ + // TODO: how does this fit in with the write buffer? +} + +void gc_mut_create() +{ + // TODO: probably do not need this, can modify gc_move to + // assign thread's allocation color +} + +void gc_mut_cooperate() +{ +// TODO: +// If (statusm != statusc) then +// If (statusm == sync2) then +// For each x in roots: +// MarkGray(x) +// allocationColorm = markColor +// statusm = statusc +} + +// Collector functions +// Collection cycle + +// END tri-color marking section diff --git a/include/cyclone/types.h b/include/cyclone/types.h index ecf58721..d0fb9fa1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -25,6 +25,8 @@ typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { void **moveBuf; /* list of objects moved to heap during GC */ int moveBufLen; + int gc_alloc_color; // For tri-color marking + int gc_mut_status; }; /* GC data structures */ From 3f8526f3c55a90436b52df9a0bcb754ab0fac33b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 27 Oct 2015 02:50:04 -0400 Subject: [PATCH 067/339] Updated comments --- gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 20983ae1..da300c8f 100644 --- a/gc.c +++ b/gc.c @@ -400,7 +400,7 @@ static const int gc_color_blue = 3; static int gc_status_coll; static int gc_stage; -// Mutator functions +// GC functions called by the Mutator threads void gc_mut_update() { @@ -424,7 +424,7 @@ void gc_mut_cooperate() // statusm = statusc } -// Collector functions -// Collection cycle +// GC functions calld by the Collector thread +// GC Collection cycle // END tri-color marking section From aee0525588e26d989b97eef6eab622255a755482 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 26 Oct 2015 23:06:29 -0400 Subject: [PATCH 068/339] WIP --- gc.c | 34 ++++++++++++++++++++-------------- runtime.c | 28 ++++++++++++++-------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/gc.c b/gc.c index da300c8f..60889ab8 100644 --- a/gc.c +++ b/gc.c @@ -397,7 +397,7 @@ static const int gc_color_grey = 1; static int gc_color_clear = 2; // White static const int gc_color_blue = 3; -static int gc_status_coll; +static int gc_status_col; static int gc_stage; // GC functions called by the Mutator threads @@ -407,24 +407,30 @@ void gc_mut_update() // TODO: how does this fit in with the write buffer? } -void gc_mut_create() +// Done as part of gc_move +//void gc_mut_create() + +void gc_mut_cooperate(gc_thread_data *thd) { - // TODO: probably do not need this, can modify gc_move to - // assign thread's allocation color + if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access + if (thd->gc_mut_status == STATUS_SYNC2) { // TODO: more sync?? + // Since everything is on the stack, at this point probably only need + // to worry about anything on the stack that is referencing a heap object + // For each x in roots: + // MarkGray(x) + thd->gc_alloc_color = gc_color_mark; // TODO: synchronization for global?? + } + thd->gc_mut_status = gc_status_col; // TODO: syncronization?? + } } -void gc_mut_cooperate() +// Collector functions +void gc_mark_gray(object obj) { -// TODO: -// If (statusm != statusc) then -// If (statusm == sync2) then -// For each x in roots: -// MarkGray(x) -// allocationColorm = markColor -// statusm = statusc + if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? + // TODO: mark buffer, last write + } } - -// GC functions calld by the Collector thread // GC Collection cycle // END tri-color marking section diff --git a/runtime.c b/runtime.c index cd47312f..8ea4c4ea 100644 --- a/runtime.c +++ b/runtime.c @@ -2387,7 +2387,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { switch(type_of(obj)){ case cons_tag: { list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object - hp->hdr.mark = 0; + hp->hdr.mark = thd->gc_alloc_color; type_of(hp) = cons_tag; car(hp) = car(obj); cdr(hp) = cdr(obj); @@ -2400,7 +2400,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case macro_tag: { macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = macro_tag; hp->fn = ((macro) obj)->fn; hp->num_args = ((macro) obj)->num_args; @@ -2411,7 +2411,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case closure0_tag: { closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closure0_tag; hp->fn = ((closure0) obj)->fn; hp->num_args = ((closure0) obj)->num_args; @@ -2422,7 +2422,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case closure1_tag: { closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closure1_tag; hp->fn = ((closure1) obj)->fn; hp->num_args = ((closure1) obj)->num_args; @@ -2434,7 +2434,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case closure2_tag: { closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closure2_tag; hp->fn = ((closure2) obj)->fn; hp->num_args = ((closure2) obj)->num_args; @@ -2447,7 +2447,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case closure3_tag: { closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closure3_tag; hp->fn = ((closure3) obj)->fn; hp->num_args = ((closure3) obj)->num_args; @@ -2461,7 +2461,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case closure4_tag: { closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closure4_tag; hp->fn = ((closure4) obj)->fn; hp->num_args = ((closure4) obj)->num_args; @@ -2479,7 +2479,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { closureN_type *hp = gc_alloc(Cyc_heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = closureN_tag; hp->fn = ((closureN) obj)->fn; hp->num_args = ((closureN) obj)->num_args; @@ -2498,7 +2498,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { vector_type *hp = gc_alloc(Cyc_heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = vector_tag; hp->num_elt = ((vector) obj)-> num_elt; hp->elts = (object *)(((char *)hp) + sizeof(vector_type)); @@ -2517,7 +2517,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { heap_grown); s = ((char *)hp) + sizeof(string_type); memcpy(s, string_str(obj), string_len(obj) + 1); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = string_tag; string_len(hp) = string_len(obj); string_str(hp) = s; @@ -2528,7 +2528,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case integer_tag: { integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = integer_tag; hp->value = ((integer_type *) obj)->value; forward(obj) = hp; @@ -2538,7 +2538,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case double_tag: { double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = double_tag; hp->value = ((double_type *) obj)->value; forward(obj) = hp; @@ -2548,7 +2548,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case port_tag: { port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = port_tag; hp->fp = ((port_type *) obj)->fp; hp->mode = ((port_type *) obj)->mode; @@ -2559,7 +2559,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } case cvar_tag: { cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown); - mark(hp) = 0; + mark(hp) = thd->gc_alloc_color; type_of(hp) = cvar_tag; hp->pvar = ((cvar_type *) obj)->pvar; forward(obj) = hp; From d069be3387c70e04055c5e9172ede4087b0619e1 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 26 Oct 2015 23:08:15 -0400 Subject: [PATCH 069/339] Need to remove extraneous printf --- gc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gc.c b/gc.c index 60889ab8..7d3dfb02 100644 --- a/gc.c +++ b/gc.c @@ -1,3 +1,4 @@ +TODO: what the fuck is being printed by the runtime? looks like a time_t? find and remove it from this branch and gc-dev3 /* A basic mark-sweep GC As of now, the GC code is based off the implementation from chibi scheme From 86a188c33701f8c2a5b335d75419eae4960b5701 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 27 Oct 2015 23:01:31 -0400 Subject: [PATCH 070/339] Added notes --- gc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 7d3dfb02..36a4d3cd 100644 --- a/gc.c +++ b/gc.c @@ -1,4 +1,3 @@ -TODO: what the fuck is being printed by the runtime? looks like a time_t? find and remove it from this branch and gc-dev3 /* A basic mark-sweep GC As of now, the GC code is based off the implementation from chibi scheme @@ -411,6 +410,31 @@ void gc_mut_update() // Done as part of gc_move //void gc_mut_create() +// +TODO: think these points through and get answers from the paper +before writing the code: + +can cooperate be part of a minor gc? in that case, the +marking could be done as part of allocation + +but then what exactly does that mean, to mark gray? because +objects moved to the heap will be set to mark color at that +point (until collector thread finishes). but would want +objects on the heap referenced by them to be traced, so +I suppose that is the purpose of the gray, to indicate +those still need to be traced. but need to think this through, +do we need the markbuffer and last read/write? do those make + sense with mta approach (assume so)??? + +ONLY CONCERN - what happens if an object on the stack +has a reference to an object on the heap that is collected? +but how would this happen? collector marks global roots before +telling mutators to go to async, and once mutators go async +any allocations will not be collected. also once collectors go +async they have a chance to markgray, which will include the write +barrier. so given that, is it still possible for an old heap ref to +sneak into a stack object during the async phase? +// void gc_mut_cooperate(gc_thread_data *thd) { if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access From 4cb17436a67d0b49287ea0f805a6160b3926b3a9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 27 Oct 2015 23:03:16 -0400 Subject: [PATCH 071/339] Added more notes --- gc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gc.c b/gc.c index 36a4d3cd..9620775f 100644 --- a/gc.c +++ b/gc.c @@ -434,6 +434,19 @@ any allocations will not be collected. also once collectors go async they have a chance to markgray, which will include the write barrier. so given that, is it still possible for an old heap ref to sneak into a stack object during the async phase? + + +more questions: +- from above, figure out how/if after cooperation/async, can a stack object pick + up a reference to a heap object that will be collected during that GC cycle? + need to be able to prevent this somehow... +- how does the collector handle stack objects that reference objects from + another thread's stack? + ) need to figure this out because do not want to move these early, right? + want its own stack to move them? + ) but does that mean we need a fwd pointer to be live for awhile? do we need + a read barrier to get this to work? obviously we want to avoid a read barrier + at all costs. // void gc_mut_cooperate(gc_thread_data *thd) { From 22fe970b4a6329b6fd67f19b96d9c707bc306dda Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 28 Oct 2015 18:53:15 -0400 Subject: [PATCH 072/339] Added notes --- gc.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/gc.c b/gc.c index 9620775f..0eed3bc3 100644 --- a/gc.c +++ b/gc.c @@ -410,10 +410,12 @@ void gc_mut_update() // Done as part of gc_move //void gc_mut_create() -// +/* TODO: think these points through and get answers from the paper before writing the code: +PHASE 1 - separation of mutator and collector into separate threads + can cooperate be part of a minor gc? in that case, the marking could be done as part of allocation @@ -435,19 +437,44 @@ async they have a chance to markgray, which will include the write barrier. so given that, is it still possible for an old heap ref to sneak into a stack object during the async phase? - -more questions: -- from above, figure out how/if after cooperation/async, can a stack object pick +more questions on above point: +- figure out how/if after cooperation/async, can a stack object pick up a reference to a heap object that will be collected during that GC cycle? need to be able to prevent this somehow... + +- need to figure out real world use case(s) where this could happen, to try and + figure out how to address this problem + +PHASE 2 - multi-threaded mutator (IE, more than one stack thread): + - how does the collector handle stack objects that reference objects from another thread's stack? - ) need to figure this out because do not want to move these early, right? - want its own stack to move them? - ) but does that mean we need a fwd pointer to be live for awhile? do we need + * minor GC will only relocate that thread's objects, so another thread's would not + be moved. however, if another thread references one of the GC'd thread's + stack objects, it will now get a forwarding pointer. even worse, what if the + other thread is blocked and the reference becomes corrupt due to the stack + longjmp? there are major issues with one thread referencing another thread's + objects. + * had considered adding a stack bit to the object header. if we do this and + initialize it during object creation, a thread could in theory detect + if an object belongs to another thread. but it might be expensive because + a read barrier would have to be used to check the object's stack bit and + address (to see if it is on this heap). + * alternatively, how would one thread pick up a reference to another one's + objects? are there any ways to detect these events and deal with them? + it might be possible to detect such a case and allocate the object on the heap, + replacing it with a fwd pointer. unfortunately that means we need a read + barrier (ick) to handle forwarding pointers in arbitrary places + * but does that mean we need a fwd pointer to be live for awhile? do we need a read barrier to get this to work? obviously we want to avoid a read barrier at all costs. -// +- what are the real costs of allowing forwarding pointers to exist outside of just + minor GC? assume each runtime primitive would need to be updated to handle the + case where the obj is a fwd pointer - is it just a matter of each function + detecting this and (possibly) calling itself again with the 'real' address? + obviously that makes the runtime slower due to more checks, but maybe it is + not *so* bad? +*/ void gc_mut_cooperate(gc_thread_data *thd) { if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access From 9e8a5c45a5f33f6f1f862e0b7e09fdfdb20d56c0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 28 Oct 2015 21:26:49 -0400 Subject: [PATCH 073/339] Added notes --- gc.c | 90 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/gc.c b/gc.c index 0eed3bc3..82962a9a 100644 --- a/gc.c +++ b/gc.c @@ -376,46 +376,17 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) // return 0; // } -// tri-color GC section, WIP -// -// Note: will need to use atomics and/or locking to access any -// variables shared between threads -typedef enum { STATUS_ASYNC - , STATUS_SYNC1 - , STATUS_SYNC2 - } gc_status_type; - -typedef enum { STAGE_CLEAR_OR_MARKING - , STAGE_TRACING - , STAGE_REF_PROCESSING - , STAGE_SWEEPING - , STAGE_RESTING - } gc_stage_type; - -static int gc_color_mark = 0; // Black -static const int gc_color_grey = 1; -static int gc_color_clear = 2; // White -static const int gc_color_blue = 3; - -static int gc_status_col; -static int gc_stage; - -// GC functions called by the Mutator threads - -void gc_mut_update() -{ - // TODO: how does this fit in with the write buffer? -} - -// Done as part of gc_move -//void gc_mut_create() - /* -TODO: think these points through and get answers from the paper -before writing the code: +Rough plan for how to implement new GC algorithm. We need to do this in +phases in order to have any hope of getting everything working. Let's prove +the algorithm out, then extend support to multiple mutators if everything +looks good. PHASE 1 - separation of mutator and collector into separate threads +need to syncronize access (preferably via atomics) for anything shared between the +collector and mutator threads. + can cooperate be part of a minor gc? in that case, the marking could be done as part of allocation @@ -445,6 +416,15 @@ more questions on above point: - need to figure out real world use case(s) where this could happen, to try and figure out how to address this problem +from my understanding of the paper, the write barrier prevents this. consider, at the +start of async, the mutator's roots, global roots, and anything on the write barrier +have been marked. any new objects will be allocated as marked. that way, anything the +mutator could later access is either marked or will be after tracing. the only exception +is if the mutator changes a reference such that tracing will no longer find an object. +but the write barrier prevents this - during tracing a heap update causes the old +object to be marked as well. so it will eventually be traced, and there should be no +dangling objects after GC completes. + PHASE 2 - multi-threaded mutator (IE, more than one stack thread): - how does the collector handle stack objects that reference objects from @@ -475,6 +455,44 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): obviously that makes the runtime slower due to more checks, but maybe it is not *so* bad? */ + +// tri-color GC section, WIP +// +// Note: will need to use atomics and/or locking to access any +// variables shared between threads +typedef enum { STATUS_ASYNC + , STATUS_SYNC1 + , STATUS_SYNC2 + } gc_status_type; + +typedef enum { STAGE_CLEAR_OR_MARKING + , STAGE_TRACING + , STAGE_REF_PROCESSING + , STAGE_SWEEPING + , STAGE_RESTING + } gc_stage_type; + +static int gc_color_mark = 0; // Black +static const int gc_color_grey = 1; +static int gc_color_clear = 2; // White +static const int gc_color_blue = 3; + +static int gc_status_col; +static int gc_stage; + +// GC functions called by the Mutator threads + +void gc_mut_update() +{ + // TODO: how does this fit in with the write buffer? + // this part is important, especially during tracing +} + +// Done as part of gc_move +// ideally want to do this without needing sync. we need to sync to get markColor in coop, though +//void gc_mut_create() + +// TODO: when is this called, is this good enough, etc?? void gc_mut_cooperate(gc_thread_data *thd) { if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access From 91e52dda6294a8cb9f9a82d74ead3e084230a9fb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 28 Oct 2015 22:14:14 -0400 Subject: [PATCH 074/339] Added GC data structures --- gc.c | 4 ++++ include/cyclone/types.h | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 82962a9a..5a1c4b06 100644 --- a/gc.c +++ b/gc.c @@ -480,6 +480,10 @@ static const int gc_color_blue = 3; static int gc_status_col; static int gc_stage; +// Does not need sync, only used by collector thread +static void **mark_stack; +static int mark_stack_len; + // GC functions called by the Mutator threads void gc_mut_update() diff --git a/include/cyclone/types.h b/include/cyclone/types.h index d0fb9fa1..e8a03c16 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -25,8 +25,13 @@ typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { void **moveBuf; /* list of objects moved to heap during GC */ int moveBufLen; - int gc_alloc_color; // For tri-color marking + // Data needed for tri-color marking + int gc_alloc_color; int gc_mut_status; + int last_write; + int last_read; + void **mark_buffer; + int mark_buffer_len; }; /* GC data structures */ From 60d55e8974e172cbffe3134da4229996474b1519 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 28 Oct 2015 22:56:42 -0400 Subject: [PATCH 075/339] Added void* buffer util functions --- gc.c | 101 ++++++++++++++++++++++------------------ include/cyclone/types.h | 5 ++ 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/gc.c b/gc.c index 5a1c4b06..81b96ee7 100644 --- a/gc.c +++ b/gc.c @@ -326,56 +326,34 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj) (*alloci)++; } +// Generic buffer functions +void **vpbuffer_realloc(void **buf, int *len) +{ + return realloc(buf, (*len) * sizeof(void *)); +} + +void **vpbuffer_add(void **buf, int *len, int i, void *obj) +{ + if (i == *len) { + *len *= 2; + buf = vpbuffer_realloc(buf, len); + } + buf[i] = obj; + return buf; +} + +void vpbuffer_free(void **buf) +{ + free(buf); +} + + // void gc_init() // { // } // END heap definitions -// int main(int argc, char **argv) { -// int i; -// size_t freed = 0, max_freed = 0; -// gc_heap *h = gc_heap_create(8 * 1024 * 1024, 0, 0); -// void *obj1 = gc_alloc(h, sizeof(cons_type)); -// void *obj2 = gc_alloc(h, sizeof(cons_type)); -// void *objI = gc_alloc(h, sizeof(integer_type)); -// -// for (i = 0; i < 1000000; i++) { -// gc_alloc(h, sizeof(integer_type)); -// gc_alloc(h, sizeof(integer_type)); -// } -// -// // Build up an object graph to test collection... -// ((integer_type *)objI)->hdr.mark = 0; -// ((integer_type *)objI)->tag = integer_tag; -// ((integer_type *)objI)->value = 42; -// -// ((list)obj2)->hdr.mark = 0; -// ((list)obj2)->tag = cons_tag; -// ((list)obj2)->cons_car = objI; -// ((list)obj2)->cons_cdr = NULL; -// -// ((list)obj1)->hdr.mark = 0; -// ((list)obj1)->tag = cons_tag; -// ((list)obj1)->cons_car = obj2; -// ((list)obj1)->cons_cdr = NULL; -// -// printf("(heap: %p size: %d)", h, (unsigned int)gc_heap_total_size(h)); -// gc_mark(h, obj1); -// max_freed = gc_sweep(h, &freed); -// printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -// for (i = 0; i < 10; i++) { -// gc_alloc(h, sizeof(integer_type)); -// gc_alloc(h, sizeof(integer_type)); -// } -// printf("(heap: %p size: %d)", h, (unsigned int)gc_heap_total_size(h)); -// gc_mark(h, obj1); -// max_freed = gc_sweep(h, &freed); -// printf("done, freed = %d, max_freed = %d\n", freed, max_freed); -// -// return 0; -// } - /* Rough plan for how to implement new GC algorithm. We need to do this in phases in order to have any hope of getting everything working. Let's prove @@ -481,8 +459,8 @@ static int gc_status_col; static int gc_stage; // Does not need sync, only used by collector thread -static void **mark_stack; -static int mark_stack_len; +static void **mark_stack = NULL; +static int mark_stack_len = 128; // GC functions called by the Mutator threads @@ -521,3 +499,34 @@ void gc_mark_gray(object obj) // GC Collection cycle // END tri-color marking section + +//// Unit testing: +//int main(int argc, char **argv) { +// int a = 1, b = 2, c = 3, i; +// void **buf = NULL; +// int size = 1; +// +// buf = vpbuffer_realloc(buf, &size); +// printf("buf = %p, size = %d\n", buf, size); +// buf = vpbuffer_add(buf, &size, 0, &a); +// printf("buf = %p, size = %d\n", buf, size); +// buf = vpbuffer_add(buf, &size, 1, &b); +// printf("buf = %p, size = %d\n", buf, size); +// buf = vpbuffer_add(buf, &size, 2, &c); +// printf("buf = %p, size = %d\n", buf, size); +// buf = vpbuffer_add(buf, &size, 3, &a); +// printf("buf = %p, size = %d\n", buf, size); +// buf = vpbuffer_add(buf, &size, 4, &b); +// printf("buf = %p, size = %d\n", buf, size); +// for (i = 5; i < 20; i++) { +// buf = vpbuffer_add(buf, &size, i, &c); +// } +// +// for (i = 0; i < 20; i++){ +// printf("%d\n", *((int *) buf[i])); +// } +// vpbuffer_free(buf); +// printf("buf = %p, size = %d\n", buf, size); +// return 0; +//} +// diff --git a/include/cyclone/types.h b/include/cyclone/types.h index e8a03c16..fc6845fa 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -73,6 +73,11 @@ struct gc_header_type_t { #define gc_word_align(n) gc_align((n), 2) #define gc_heap_align(n) gc_align(n, 5) +/* Utility functions */ +void **vpbuffer_realloc(void **buf, int *len); +void **vpbuffer_add(void **buf, int *len, int i, void *obj); +void vpbuffer_free(void **buf); + /* GC prototypes */ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); From 1becf84a4751e4b0c4fb0bbdd9de25d0fd065a10 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 28 Oct 2015 23:01:27 -0400 Subject: [PATCH 076/339] WIP --- gc.c | 27 +++++++++++++++++++++++++-- include/cyclone/types.h | 8 ++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index 81b96ee7..ec383b8e 100644 --- a/gc.c +++ b/gc.c @@ -461,6 +461,7 @@ static int gc_stage; // Does not need sync, only used by collector thread static void **mark_stack = NULL; static int mark_stack_len = 128; +static int mark_stack_i = 0; // GC functions called by the Mutator threads @@ -490,12 +491,34 @@ void gc_mut_cooperate(gc_thread_data *thd) } // Collector functions -void gc_mark_gray(object obj) +void gc_mark_gray(gc_thread_data *thd, object obj) { if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? - // TODO: mark buffer, last write + // TODO: lock mark buffer (not ideal, but a possible first step)? + // pthread_mutex_lock + thd->mark_buffer = vpbuffer_add(thd->mark_buffer, + &(thd->mark_buffer_len), + thd->last_write, + obj); + // pthread_mutex_unlock + // unlock mark buffer + ATOMIC_INC(&(thd->last_write)); } } + +void gc_col_mark_gray(object obj) +{ + if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? + mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); + } +} + +void gc_col_empty_collector_stack() +{ +// TODO: +// while (!markstack.empty()) +// markBlack(markstack.pop()) +} // GC Collection cycle // END tri-color marking section diff --git a/include/cyclone/types.h b/include/cyclone/types.h index fc6845fa..631058cd 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -359,5 +359,13 @@ typedef union { double_type double_t; } common_type; +// Atomics section +// TODO: this is all compiler dependent, need to use different macros depending +// upon the compiler (and arch) +// TODO: relocate this to its own header? +#define ATOMIC_INC(ptr) __sync_fetch_and_add((ptr),1) +#define ATOMIC_DEC(ptr) __sync_fetch_and_sub((ptr),1) +#define ATOMIC_GET(ptr) __sync_fetch_and_add((ptr),0) +#define ATOMIC_SET_IF_EQ(ptr, oldv, newv) __sync_val_compare_and_swap(ptr, oldv, newv) #endif /* CYCLONE_TYPES_H */ From 40f2ac62079fce75f23ec070318a0762e3faf662 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 18:43:21 -0400 Subject: [PATCH 077/339] Added notes --- gc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index ec383b8e..e12886d7 100644 --- a/gc.c +++ b/gc.c @@ -493,7 +493,10 @@ void gc_mut_cooperate(gc_thread_data *thd) // Collector functions void gc_mark_gray(gc_thread_data *thd, object obj) { - if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? + // sync access to obj? check the paper, need to see if any other thread would be modifying + // either object type or mark. I believe both should be stable once the object is placed + // into the heap, with the collector being the only thread that changes marks. but double-check. + if (is_object_type(obj) && mark(obj) == ATOMIC_GET(&gc_color_clear)) { // TODO: sync?? // TODO: lock mark buffer (not ideal, but a possible first step)? // pthread_mutex_lock thd->mark_buffer = vpbuffer_add(thd->mark_buffer, @@ -508,7 +511,7 @@ void gc_mark_gray(gc_thread_data *thd, object obj) void gc_col_mark_gray(object obj) { - if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? + if (is_object_type(obj) && mark(obj) == ATOMIC_GET(&gc_color_clear)) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); } } From 90609443f4f0d7a9600b70a95a89fc92f975787a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 21:58:47 -0400 Subject: [PATCH 078/339] Added thread lock --- gc.c | 23 ++++++++++++++++++++--- include/cyclone/runtime-main.h | 5 ++--- include/cyclone/types.h | 3 +++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index e12886d7..67e5de3c 100644 --- a/gc.c +++ b/gc.c @@ -498,13 +498,12 @@ void gc_mark_gray(gc_thread_data *thd, object obj) // into the heap, with the collector being the only thread that changes marks. but double-check. if (is_object_type(obj) && mark(obj) == ATOMIC_GET(&gc_color_clear)) { // TODO: sync?? // TODO: lock mark buffer (not ideal, but a possible first step)? - // pthread_mutex_lock + pthread_mutex_lock(&(thd->lock)); thd->mark_buffer = vpbuffer_add(thd->mark_buffer, &(thd->mark_buffer_len), thd->last_write, obj); - // pthread_mutex_unlock - // unlock mark buffer + pthread_mutex_unlock(&(thd->lock)); ATOMIC_INC(&(thd->last_write)); } } @@ -526,6 +525,24 @@ void gc_col_empty_collector_stack() // END tri-color marking section + +// Initialize a thread from scratch +void gc_thread_data_init(gc_thread_data *thd) +{ + thd->moveBufLen = 0; + gc_thr_grow_move_buffer(thd); +// TODO: depends on collector state: thd->gc_alloc_color = ATOMIC_GET(&gc_; +// TODO: depends on collector state: thd->gc_mut_status; + thd->last_write = 0; + thd->last_read = 0; + thd->mark_buffer_len = 128; + thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); + if (pthread_mutex(&(thd->lock), NULL) != 0) { + fprintf(stderr, "Unable to initialize thread mutex\n"); + exit(1); + } +} + //// Unit testing: //int main(int argc, char **argv) { // int a = 1, b = 2, c = 3, i; diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index ad98878a..5a4af9eb 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -59,9 +59,8 @@ static void Cyc_main (stack_size,heap_size,stack_base) Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); //Cyc_heap = gc_heap_create(1024, 0, 0); - Cyc_thread = (gc_thread_data *)malloc(sizeof(gc_thread_data)); - Cyc_thread->moveBufLen = 0; - gc_thr_grow_move_buffer(Cyc_thread); // Initialize the buffer + Cyc_thread = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(Cyc_thread); // JAE TODO: clean up below (and all of this old code, really) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 631058cd..b83b80ef 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -16,6 +16,7 @@ #include #include #include +#include /* Define general object type. */ typedef void *object; @@ -32,6 +33,7 @@ struct gc_thread_data_t { int last_read; void **mark_buffer; int mark_buffer_len; + pthread_mutex_t lock; }; /* GC data structures */ @@ -91,6 +93,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); +void gc_thread_data_init(gc_thread_data *thd); /* GC debugging flags */ //#define DEBUG_GC 0 From 51222b42c684993062676778acd7879ece6e8062 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 22:45:28 -0400 Subject: [PATCH 079/339] Stubbing-out collector functions --- gc.c | 102 +++++++++++++++++++++++++++++++--------- include/cyclone/types.h | 28 +++++++++++ 2 files changed, 107 insertions(+), 23 deletions(-) diff --git a/gc.c b/gc.c index 67e5de3c..27bf6e6d 100644 --- a/gc.c +++ b/gc.c @@ -438,20 +438,8 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): // // Note: will need to use atomics and/or locking to access any // variables shared between threads -typedef enum { STATUS_ASYNC - , STATUS_SYNC1 - , STATUS_SYNC2 - } gc_status_type; - -typedef enum { STAGE_CLEAR_OR_MARKING - , STAGE_TRACING - , STAGE_REF_PROCESSING - , STAGE_SWEEPING - , STAGE_RESTING - } gc_stage_type; - static int gc_color_mark = 0; // Black -static const int gc_color_grey = 1; +static const int gc_color_grey = 1; // TODO: appears unused, clean up static int gc_color_clear = 2; // White static const int gc_color_blue = 3; @@ -463,6 +451,7 @@ static void **mark_stack = NULL; static int mark_stack_len = 128; static int mark_stack_i = 0; +///////////////////////////////////////////// // GC functions called by the Mutator threads void gc_mut_update() @@ -490,13 +479,15 @@ void gc_mut_cooperate(gc_thread_data *thd) } } +///////////////////////////////////////////// // Collector functions + void gc_mark_gray(gc_thread_data *thd, object obj) { - // sync access to obj? check the paper, need to see if any other thread would be modifying - // either object type or mark. I believe both should be stable once the object is placed - // into the heap, with the collector being the only thread that changes marks. but double-check. - if (is_object_type(obj) && mark(obj) == ATOMIC_GET(&gc_color_clear)) { // TODO: sync?? + // From what I can tell, no other thread would be modifying + // either object type or mark. Both should be stable once the object is placed + // into the heap, with the collector being the only thread that changes marks. + if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? // TODO: lock mark buffer (not ideal, but a possible first step)? pthread_mutex_lock(&(thd->lock)); thd->mark_buffer = vpbuffer_add(thd->mark_buffer, @@ -508,22 +499,87 @@ void gc_mark_gray(gc_thread_data *thd, object obj) } } -void gc_col_mark_gray(object obj) +void gc_collector_trace() { - if (is_object_type(obj) && mark(obj) == ATOMIC_GET(&gc_color_clear)) { +// note - can atomic operations be used for last read/write, to prevent +// coarser-grained synchronization there? +// TODO: +// clean = FALSE +// while (!(clean)) +// clean = TRUE +// For each m in mutators +// while (lastread[m] < lastwrite[m]) // TODO: use atomic sub to compare? +// clean = FALSE +// lastread[m] = lastread[m] + 1 // TODO: atomic increment +// markBlack(markbuffer[m][lastread[m]]) +// EmptyCollectorStack() +} + +// TODO: seriously consider changing the mark() macro to color(), +// and sync up the header variable. that would make all of this code +// bit clearer... + +void gc_mark_black(object obj) +{ + // TODO: is sync required to get colors? probably not on the collector + // thread (at least) since colors are only changed once during the clear + // phase and before the first handshake. + int markColor = gc_color_mark; //TODO: is atomic require here?? ATOMIC_GET(&gc_color_mark); + if (is_object_type(obj) && mark(obj) != markColor) { + // TODO: need to examine type and branch accordingly to grey pointers + // EG: colmarkgray(car); colmarkgray(cdr); etc.. + //For each pointer i in x do: + // CollectorMarkGray(i) + mark(obj) = markColor; + } +} + +void gc_collector_mark_gray(object obj) +{ + if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); } } -void gc_col_empty_collector_stack() +void gc_empty_collector_stack() { -// TODO: -// while (!markstack.empty()) -// markBlack(markstack.pop()) + // Mark stack is only used by the collector thread, so no sync needed + while (mark_stack_i > 0) { // not empty + mark_stack--; + gc_mark_black(mark_stack[mark_stack_i]); + } } + +// TODO: +void gc_handshake(gc_status_type s) +{ + gc_post_handshake(s); + gc_wait_handshake(); +} + +//void gc_post_handshake(gc_status_type s) +//{ +// TODO: use atomic to change value of gc_status_col +//} + +//void gc_wait_handshake() +//{ +// // TODO: +// for each m in mutators +// wait for statusm = statusc +//} + +///////////////////////////////////////////// // GC Collection cycle +// TODO: +//void gc_collector() +//{ +//} + +///////////////////////////////////////////// // END tri-color marking section +///////////////////////////////////////////// // Initialize a thread from scratch diff --git a/include/cyclone/types.h b/include/cyclone/types.h index b83b80ef..5056ce9e 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -75,6 +75,19 @@ struct gc_header_type_t { #define gc_word_align(n) gc_align((n), 2) #define gc_heap_align(n) gc_align(n, 5) +/* Enums for tri-color marking */ +typedef enum { STATUS_ASYNC + , STATUS_SYNC1 + , STATUS_SYNC2 + } gc_status_type; + +typedef enum { STAGE_CLEAR_OR_MARKING + , STAGE_TRACING + , STAGE_REF_PROCESSING + , STAGE_SWEEPING + , STAGE_RESTING + } gc_stage_type; + /* Utility functions */ void **vpbuffer_realloc(void **buf, int *len); void **vpbuffer_add(void **buf, int *len, int i, void *obj); @@ -94,6 +107,21 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd); +// Prototypes for mutator/collector: +void gc_mark_gray(gc_thread_data *thd, object obj); +void gc_collector_trace(); +void gc_mark_black(object obj); +void gc_collector_mark_gray(object obj); +void gc_empty_collector_stack(); +void gc_handshake(gc_status_type s); +void gc_post_handshake(gc_status_type s); +void gc_wait_handshake(); + +///////////////////////////////////////////// +// GC Collection cycle + +// TODO: +//void gc_collector() /* GC debugging flags */ //#define DEBUG_GC 0 From 2a226d376f0dd25122c034b3f0b595f438c36d1b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 02:51:20 -0400 Subject: [PATCH 080/339] WIP --- gc.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/gc.c b/gc.c index 27bf6e6d..2dd8f976 100644 --- a/gc.c +++ b/gc.c @@ -501,6 +501,21 @@ void gc_mark_gray(gc_thread_data *thd, object obj) void gc_collector_trace() { + int clean = 0; + while (!clean) { + clean = 1; + } + TODO: need a list of mutators. + could keep a buffer or linked list of them. a list may be more efficient + also need to consider how to map thread back to its gc_thread_data, + which we will need during GC (cooperate). maybe use a (platform-specific) + call like below to get a unique ID for the thread, and then use a + hashtable to get the thread info. how often will we be accessing this data? + seems we will need to be able to access it from 2 places: + - from mutator (can compute thread id here) + - from collector (need to be able to iterate across all mutators) + #include + printf("tid = %d\n", syscall(SYS_gettid)); // note - can atomic operations be used for last read/write, to prevent // coarser-grained synchronization there? // TODO: @@ -526,10 +541,48 @@ void gc_mark_black(object obj) // phase and before the first handshake. int markColor = gc_color_mark; //TODO: is atomic require here?? ATOMIC_GET(&gc_color_mark); if (is_object_type(obj) && mark(obj) != markColor) { - // TODO: need to examine type and branch accordingly to grey pointers - // EG: colmarkgray(car); colmarkgray(cdr); etc.. - //For each pointer i in x do: - // CollectorMarkGray(i) + // Gray any child objects + // Note we probably should use some form of atomics/synchronization + // for cons and vector types, as these pointers could change. + switch(type_of(obj)) { + case cons_tag: { + gc_collector_mark_gray(car(obj)); + gc_collector_mark_gray(cdr(obj)); + break; + } + case closure1_tag: + gc_collector_mark_gray(((closure1) obj)->elt1); + break; + case closure2_tag: + gc_collector_mark_gray(((closure2) obj)->elt1); + gc_collector_mark_gray(((closure2) obj)->elt2); + case closure3_tag: + gc_collector_mark_gray(((closure3) obj)->elt1); + gc_collector_mark_gray(((closure3) obj)->elt2); + gc_collector_mark_gray(((closure3) obj)->elt3); + case closure4_tag: + gc_collector_mark_gray(((closure4) obj)->elt1); + gc_collector_mark_gray(((closure4) obj)->elt2); + gc_collector_mark_gray(((closure4) obj)->elt3); + gc_collector_mark_gray(((closure4) obj)->elt4); + break; + case closureN_tag: { + int i, n = ((closureN) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_collector_mark_gray(((closureN) obj)->elts[i]); + } + break; + } + case vector_tag: { + int i, n = ((vector) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_collector_mark_gray(((vector) obj)->elts[i]); + } + break; + } + default: + break; + } mark(obj) = markColor; } } From b3af3aff731eda516decaa26d33813b944d95679 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 21:53:21 -0400 Subject: [PATCH 081/339] Added note --- gc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gc.c b/gc.c index 2dd8f976..1ef1f329 100644 --- a/gc.c +++ b/gc.c @@ -544,6 +544,8 @@ void gc_mark_black(object obj) // Gray any child objects // Note we probably should use some form of atomics/synchronization // for cons and vector types, as these pointers could change. + // Also this is a case for adding the stack/heap bit, because these could + // be stack objects if a thread issued an update. switch(type_of(obj)) { case cons_tag: { gc_collector_mark_gray(car(obj)); From fee0675fa2cd57049456510483d6435aaa969652 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 22:31:25 -0400 Subject: [PATCH 082/339] Added red color to indicate stack alloc --- gc.c | 37 +++++++++++++++++---------------- include/cyclone/types.h | 46 ++++++++++++++++++----------------------- scheme/cyclone/cgen.sld | 1 + 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/gc.c b/gc.c index 1ef1f329..a36e1245 100644 --- a/gc.c +++ b/gc.c @@ -438,10 +438,10 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): // // Note: will need to use atomics and/or locking to access any // variables shared between threads -static int gc_color_mark = 0; // Black -static const int gc_color_grey = 1; // TODO: appears unused, clean up -static int gc_color_clear = 2; // White -static const int gc_color_blue = 3; +static int gc_color_mark = 0; // Black, is swapped during GC +//static const int gc_color_grey = 1; // TODO: appears unused, clean up +static int gc_color_clear = 2; // White, is swapped during GC +// unfortunately this had to be split up; const colors are located in types.h static int gc_status_col; static int gc_stage; @@ -502,20 +502,21 @@ void gc_mark_gray(gc_thread_data *thd, object obj) void gc_collector_trace() { int clean = 0; - while (!clean) { - clean = 1; - } - TODO: need a list of mutators. - could keep a buffer or linked list of them. a list may be more efficient - also need to consider how to map thread back to its gc_thread_data, - which we will need during GC (cooperate). maybe use a (platform-specific) - call like below to get a unique ID for the thread, and then use a - hashtable to get the thread info. how often will we be accessing this data? - seems we will need to be able to access it from 2 places: - - from mutator (can compute thread id here) - - from collector (need to be able to iterate across all mutators) - #include - printf("tid = %d\n", syscall(SYS_gettid)); +// while (!clean) { +// clean = 1; +// } +// TODO: need a list of mutators. +// could keep a buffer or linked list of them. a list may be more efficient +// also need to consider how to map thread back to its gc_thread_data, +// which we will need during GC (cooperate). maybe use a (platform-specific) +// call like below to get a unique ID for the thread, and then use a +// hashtable to get the thread info. how often will we be accessing this data? +// seems we will need to be able to access it from 2 places: +// - from mutator (can compute thread id here) +// - from collector (need to be able to iterate across all mutators) +// #include +// printf("tid = %d\n", syscall(SYS_gettid)); + // note - can atomic operations be used for last read/write, to prevent // coarser-grained synchronization there? // TODO: diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 5056ce9e..85c5517d 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -88,6 +88,12 @@ typedef enum { STAGE_CLEAR_OR_MARKING , STAGE_RESTING } gc_stage_type; +// Constant colors are defined here. +// The mark/clear colors are defined in the gc module because +// the collector swaps their values as an optimization. +const int gc_color_blue = 3; // Unallocate memory +const int gc_color_red = 4; // Memory on the stack + /* Utility functions */ void **vpbuffer_realloc(void **buf, int *len); void **vpbuffer_add(void **buf, int *len, int i, void *obj); @@ -212,7 +218,7 @@ typedef void (*function_type_va)(int, object, object, object, ...); /* Define C-variable integration type */ typedef struct {gc_header_type hdr; tag_type tag; object *pvar;} cvar_type; typedef cvar_type *cvar; -#define make_cvar(n,v) cvar_type n; n.tag = cvar_tag; n.pvar = v; +#define make_cvar(n,v) cvar_type n; n.hdr.mark = gc_color_red; n.tag = cvar_tag; n.pvar = v; /* Define boolean type. */ typedef struct {gc_header_type hdr; const tag_type tag; const char *pname;} boolean_type; @@ -233,9 +239,9 @@ static object quote_##name = nil; /* Define numeric types */ typedef struct {gc_header_type hdr; tag_type tag; int value;} integer_type; -#define make_int(n,v) integer_type n; n.tag = integer_tag; n.value = v; +#define make_int(n,v) integer_type n; n.hdr.mark = gc_color_red; n.tag = integer_tag; n.value = v; typedef struct {gc_header_type hdr; tag_type tag; double value;} double_type; -#define make_double(n,v) double_type n; n.tag = double_tag; n.value = v; +#define make_double(n,v) double_type n; n.hdr.mark = gc_color_red; n.tag = double_tag; n.value = v; #define integer_value(x) (((integer_type *) x)->value) #define double_value(x) (((double_type *) x)->value) @@ -246,30 +252,18 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty //// all functions that allocate strings, the GC, cgen, and maybe more. //// Because these strings are (at least for now) allocaed on the stack. #define make_string(cs, s) string_type cs; \ -{ int len = strlen(s); cs.tag = string_tag; cs.len = len; \ +{ int len = strlen(s); cs.tag = string_tag; cs.len = len; cs.hdr.mark = gc_color_red; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len + 1);} -#define make_string_with_len(cs, s, length) string_type cs; \ +#define make_string_with_len(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; \ { int len = length; \ cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len); \ cs.str[len] = '\0';} -#define make_string_noalloc(cs, s, length) string_type cs; \ +#define make_string_noalloc(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } -// TODO: all of the dhalloc below needs to go away... -//#define make_string(cv,s) string_type cv; cv.tag = string_tag; \ -//{ int len = strlen(s); cv.str = dhallocp; \ -// if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ -// printf("Fatal error: data heap overflow\n"); exit(1); } \ -// memcpy(dhallocp, s, len + 1); dhallocp += len + 1; } -//#define make_stringn(cv,s,len) string_type cv; cv.tag = string_tag; \ -//{ cv.str = dhallocp; \ -// if ((dhallocp + len + 1) >= dhbottom + global_heap_size) { \ -// printf("Fatal error: data heap overflow\n"); exit(1); } \ -// memcpy(dhallocp, s, len); dhallocp += len; \ -// *dhallocp = '\0'; dhallocp += 1;} #define string_len(x) (((string_type *) x)->len) #define string_str(x) (((string_type *) x)->str) @@ -281,14 +275,14 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty // TODO: a simple wrapper around FILE may not be good enough long-term // TODO: how exactly mode will be used. need to know r/w, bin/txt typedef struct {gc_header_type hdr; tag_type tag; FILE *fp; int mode;} port_type; -#define make_port(p,f,m) port_type p; p.tag = port_tag; p.fp = f; p.mode = m; +#define make_port(p,f,m) port_type p; p.hdr.mark = gc_color_red; p.tag = port_tag; p.fp = f; p.mode = m; /* Vector type */ typedef struct {gc_header_type hdr; tag_type tag; int num_elt; object *elts;} vector_type; typedef vector_type *vector; -#define make_empty_vector(v) vector_type v; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; +#define make_empty_vector(v) vector_type v; v.hdr.mark = gc_color_red; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; /* Define cons type. */ @@ -348,15 +342,15 @@ typedef closureN_type *closureN; typedef closure0_type *closure; typedef closure0_type *macro; -#define mmacro(c,f) macro_type c; c.tag = macro_tag; c.fn = f; c.num_args = -1; -#define mclosure0(c,f) closure0_type c; c.tag = closure0_tag; c.fn = f; c.num_args = -1; -#define mclosure1(c,f,a) closure1_type c; c.tag = closure1_tag; \ +#define mmacro(c,f) macro_type c; c.hdr.mark = gc_color_red; c.tag = macro_tag; c.fn = f; c.num_args = -1; +#define mclosure0(c,f) closure0_type c; c.hdr.mark = gc_color_red; c.tag = closure0_tag; c.fn = f; c.num_args = -1; +#define mclosure1(c,f,a) closure1_type c; c.hdr.mark = gc_color_red; c.tag = closure1_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a; -#define mclosure2(c,f,a1,a2) closure2_type c; c.tag = closure2_tag; \ +#define mclosure2(c,f,a1,a2) closure2_type c; c.hdr.mark = gc_color_red; c.tag = closure2_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; -#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.tag = closure3_tag; \ +#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.hdr.mark = gc_color_red; c.tag = closure3_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; -#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.tag = closure4_tag; \ +#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.hdr.mark = gc_color_red; c.tag = closure4_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; c.elt4 = a4; #define mlist1(e1) (mcons(e1,nil)) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index b1d7be0d..2689cec6 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -996,6 +996,7 @@ (create-nclosure (lambda () (string-append "closureN_type " cv-name ";\n" + cv-name ".hdr.mark = gc_color_red;\n " cv-name ".tag = closureN_tag;\n " cv-name ".fn = (function_type)__lambda_" (number->string lid) ";\n" cv-name ".num_args = " (number->string (compute-num-args lam)) ";\n" From fc83ee260b57b5f7e24ac93808d773cade95756e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 29 Oct 2015 22:39:09 -0400 Subject: [PATCH 083/339] Added comments --- gc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index a36e1245..13df5c7a 100644 --- a/gc.c +++ b/gc.c @@ -545,8 +545,6 @@ void gc_mark_black(object obj) // Gray any child objects // Note we probably should use some form of atomics/synchronization // for cons and vector types, as these pointers could change. - // Also this is a case for adding the stack/heap bit, because these could - // be stack objects if a thread issued an update. switch(type_of(obj)) { case cons_tag: { gc_collector_mark_gray(car(obj)); @@ -592,6 +590,11 @@ void gc_mark_black(object obj) void gc_collector_mark_gray(object obj) { + // "Color" objects gray by adding them to the mark stack for further processing. + // + // Note that stack objects are always colored red during creation, so + // they should never be added to the mark stack. Which would be bad because it + // could lead to stack corruption. if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); } From bfc9160c9530878126124d1cf62eb16cfcaa3dbb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 18:46:31 -0400 Subject: [PATCH 084/339] Ensure stack-allocated data is colored red. --- runtime.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runtime.c b/runtime.c index 8ea4c4ea..89b71148 100644 --- a/runtime.c +++ b/runtime.c @@ -1103,6 +1103,7 @@ object Cyc_command_line_arguments(object cont) { object pl = alloca(sizeof(cons_type)); make_string(s, _cyc_argv[i - 1]); memcpy(ps, &s, sizeof(string_type)); + ((list)pl)->hdr.mark = gc_color_red; ((list)pl)->tag = cons_tag; ((list)pl)->cons_car = ps; ((list)pl)->cons_cdr = lis; @@ -1116,6 +1117,7 @@ object Cyc_make_vector(object cont, object len, object fill) { int i; Cyc_check_int(len); v = alloca(sizeof(vector_type)); + ((vector)v)->hdr.mark = gc_color_red; ((vector)v)->tag = vector_tag; ((vector)v)->num_elt = ((integer_type *)len)->value; ((vector)v)->elts = @@ -1137,6 +1139,7 @@ object Cyc_list2vector(object cont, object l) { Cyc_check_cons_or_nil(l); len = Cyc_length(l); v = alloca(sizeof(vector_type)); + ((vector)v)->hdr.mark = gc_color_red; ((vector)v)->tag = vector_tag; ((vector)v)->num_elt = len.value; ((vector)v)->elts = @@ -1418,11 +1421,13 @@ object Cyc_io_peek_char(object port) { /* This heap cons is used only for initialization. */ list mcons(a,d) object a,d; {register cons_type *c = malloc(sizeof(cons_type)); + c->hdr.mark = gc_color_red; c->tag = cons_tag; c->cons_car = a; c->cons_cdr = d; return c;} cvar_type *mcvar(object *var) { cvar_type *c = malloc(sizeof(cvar_type)); + c->hdr.mark = gc_color_red; c->tag = cvar_tag; c->pvar = var; return c;} @@ -1915,6 +1920,7 @@ void Cyc_apply(int argc, closure cont, object prim, ...){ for (i = 0; i < argc; i++) { tmp = va_arg(ap, object); + args[i].hdr.mark = gc_color_red; args[i].tag = cons_tag; args[i].cons_car = tmp; args[i].cons_cdr = (i == (argc-1)) ? nil : &args[i + 1]; @@ -1943,6 +1949,7 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { cont = buf[0]; for (i = 1; i < argc; i++) { + args[i - 1].hdr.mark = gc_color_red; args[i - 1].tag = cons_tag; args[i - 1].cons_car = buf[i]; args[i - 1].cons_cdr = (i == (argc-1)) ? nil : &args[i]; From be4fd84d6399b7070b8bd83dda37e39e939013c3 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 18:50:33 -0400 Subject: [PATCH 085/339] Changed color values Many types are allocated with a zeroed-out header, so making the red color 0 is now consistent with that code. --- gc.c | 6 +++--- include/cyclone/types.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 13df5c7a..0bcfeeb4 100644 --- a/gc.c +++ b/gc.c @@ -438,9 +438,9 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): // // Note: will need to use atomics and/or locking to access any // variables shared between threads -static int gc_color_mark = 0; // Black, is swapped during GC -//static const int gc_color_grey = 1; // TODO: appears unused, clean up -static int gc_color_clear = 2; // White, is swapped during GC +static int gc_color_mark = 2; // Black, is swapped during GC +static int gc_color_clear = 3; // White, is swapped during GC +//static const int gc_color_grey = 4; // TODO: appears unused, clean up // unfortunately this had to be split up; const colors are located in types.h static int gc_status_col; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 85c5517d..ae9e3b3a 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -91,8 +91,8 @@ typedef enum { STAGE_CLEAR_OR_MARKING // Constant colors are defined here. // The mark/clear colors are defined in the gc module because // the collector swaps their values as an optimization. -const int gc_color_blue = 3; // Unallocate memory -const int gc_color_red = 4; // Memory on the stack +const int gc_color_red = 0; // Memory not to be GC'd, such as on the stack +const int gc_color_blue = 1; // Unallocated memory /* Utility functions */ void **vpbuffer_realloc(void **buf, int *len); From cfc1f77bbcb8864a3261c94ab33ea80721f21575 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 23:04:39 -0400 Subject: [PATCH 086/339] Added notes --- gc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gc.c b/gc.c index 0bcfeeb4..513163eb 100644 --- a/gc.c +++ b/gc.c @@ -516,6 +516,22 @@ void gc_collector_trace() // - from collector (need to be able to iterate across all mutators) // #include // printf("tid = %d\n", syscall(SYS_gettid)); +// +// TODO: +// ACTION - I think the most efficient solution is to have each thread pass around +// the pointer to it's thread data. this param would have to be passed to all +// continuation calls made by the thread. +// the collector/runtime will need to maintain a list of the thread data structures, +// and will need to maintain it when a thread is created or terminated (either +// explicitly or when it returns). +// practically the required changes are: +// - stabilize this branch so it builds and runs (hope this just means commenting out +// the pthread calls for right now) +// - extend the runtime and compiled code to have a new thread_data (sp?) param +// also need to judge if there are issues that would prevent being able to add +// one, but it seems like it should be no problem +// - build the code and test that the value is actually maintained across calls +// (maybe assign it to a global at start and exit from GC if cur val != global val) // note - can atomic operations be used for last read/write, to prevent // coarser-grained synchronization there? From 2b849eb5245f09cf6a417130160d818a8bc6baee Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 23:06:14 -0400 Subject: [PATCH 087/339] Temporarily removing pthread calls --- gc.c | 24 ++++++++++++------------ include/cyclone/types.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index 513163eb..915d44f1 100644 --- a/gc.c +++ b/gc.c @@ -488,14 +488,14 @@ void gc_mark_gray(gc_thread_data *thd, object obj) // either object type or mark. Both should be stable once the object is placed // into the heap, with the collector being the only thread that changes marks. if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? - // TODO: lock mark buffer (not ideal, but a possible first step)? - pthread_mutex_lock(&(thd->lock)); - thd->mark_buffer = vpbuffer_add(thd->mark_buffer, - &(thd->mark_buffer_len), - thd->last_write, - obj); - pthread_mutex_unlock(&(thd->lock)); - ATOMIC_INC(&(thd->last_write)); +//TODO: // TODO: lock mark buffer (not ideal, but a possible first step)? +//TODO: pthread_mutex_lock(&(thd->lock)); +//TODO: thd->mark_buffer = vpbuffer_add(thd->mark_buffer, +//TODO: &(thd->mark_buffer_len), +//TODO: thd->last_write, +//TODO: obj); +//TODO: pthread_mutex_unlock(&(thd->lock)); +//TODO: ATOMIC_INC(&(thd->last_write)); } } @@ -668,10 +668,10 @@ void gc_thread_data_init(gc_thread_data *thd) thd->last_read = 0; thd->mark_buffer_len = 128; thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); - if (pthread_mutex(&(thd->lock), NULL) != 0) { - fprintf(stderr, "Unable to initialize thread mutex\n"); - exit(1); - } +// TODO: if (pthread_mutex(&(thd->lock), NULL) != 0) { +// TODO: fprintf(stderr, "Unable to initialize thread mutex\n"); +// TODO: exit(1); +// TODO: } } //// Unit testing: diff --git a/include/cyclone/types.h b/include/cyclone/types.h index ae9e3b3a..81dd121d 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -16,7 +16,7 @@ #include #include #include -#include +// TODO: #include /* Define general object type. */ typedef void *object; @@ -33,7 +33,7 @@ struct gc_thread_data_t { int last_read; void **mark_buffer; int mark_buffer_len; - pthread_mutex_t lock; +// TODO: pthread_mutex_t lock; }; /* GC data structures */ From 5c551446914ea65a56898a435b1251c5af1df306 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 23:13:34 -0400 Subject: [PATCH 088/339] For const colors, use define instead of declarations --- include/cyclone/types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 81dd121d..4cb0b5b8 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -91,8 +91,8 @@ typedef enum { STAGE_CLEAR_OR_MARKING // Constant colors are defined here. // The mark/clear colors are defined in the gc module because // the collector swaps their values as an optimization. -const int gc_color_red = 0; // Memory not to be GC'd, such as on the stack -const int gc_color_blue = 1; // Unallocated memory +#define gc_color_red 0 // Memory not to be GC'd, such as on the stack +#define gc_color_blue 1 // Unallocated memory /* Utility functions */ void **vpbuffer_realloc(void **buf, int *len); From be3857b1c8a3481b461e32d0a618bd29e8f57a53 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 23:35:47 -0400 Subject: [PATCH 089/339] Fixes to build --- gc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 915d44f1..6b2da5bd 100644 --- a/gc.c +++ b/gc.c @@ -626,11 +626,11 @@ void gc_empty_collector_stack() } // TODO: -void gc_handshake(gc_status_type s) -{ - gc_post_handshake(s); - gc_wait_handshake(); -} +//void gc_handshake(gc_status_type s) +//{ +// gc_post_handshake(s); +// gc_wait_handshake(); +//} //void gc_post_handshake(gc_status_type s) //{ From 866fbcac9a2e451251631085a62927dfa7195775 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 31 Oct 2015 02:55:20 -0400 Subject: [PATCH 090/339] WIP --- gc-notes.txt | 26 ++++++++++ runtime.c | 136 +++++++++++++++++++++++++-------------------------- 2 files changed, 92 insertions(+), 70 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index b2a36193..b94def8c 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -1,3 +1,29 @@ Phase 1 (gc-dev) - Add gc.h, make sure it compiles. Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and be compatible with a new GC algorithm. Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. + + +Notes for adding new thread data param +- primitives that will now need to accept the param: + ((eq? p 'Cyc-write-char) "Cyc_write_char") + Cyc_vector_set + Cyc_vector_ref + Cyc_vector_length(void *data, object v) { + Cyc_length + Cyc_number2string(void *data, object cont, object n) { +object Cyc_symbol2string(object cont, object sym) { +object Cyc_list2string(void *data, object cont, object lst){ +#define Cyc_string_append_va_list(data, argc) { \ +object Cyc_string_set(object str, object k, object chr) { +object Cyc_string_ref(void *data, object str, object k) { +object Cyc_substring(void *data, object cont, object str, object start, object end) { +object Cyc_installation_dir(object cont, object type) { +object Cyc_command_line_arguments(object cont) { +object Cyc_make_vector(object cont, object len, object fill) { +object Cyc_list2vector(void *data, object cont, object l) { + +- plan: + - update runtime, get it to compile + - update any associated tools (dispatch.c, etc) + - update cgen + - integration diff --git a/runtime.c b/runtime.c index 89b71148..de7e5b0f 100644 --- a/runtime.c +++ b/runtime.c @@ -60,22 +60,22 @@ void Cyc_check_bounds(const char *label, int len, int index) { /* END error checking */ /* These macros are hardcoded here to support functions in this module. */ -#define closcall1(cfn,a1) if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(0, (closure)a1, cfn); } else { ((cfn)->fn)(1,cfn,a1);} +#define closcall1(td,cfn,a1) if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(td,0, (closure)a1, cfn); } else { ((cfn)->fn)(td,1,cfn,a1);} /* Return to continuation after checking for stack overflow. */ -#define return_closcall1(cfn,a1) \ +#define return_closcall1(td,cfn,a1) \ {char stack; \ if (check_overflow(&stack,stack_limit1)) { \ object buf[1]; buf[0] = a1;\ - GC(cfn,buf,1); return; \ - } else {closcall1((closure) (cfn),a1); return;}} -#define closcall2(cfn,a1,a2) if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(1, (closure)a1, cfn,a2); } else { ((cfn)->fn)(2,cfn,a1,a2);} + GC(td,cfn,buf,1); return; \ + } else {closcall1(td,(closure) (cfn),a1); return;}} +#define closcall2(td,cfn,a1,a2) if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(td,1, (closure)a1, cfn,a2); } else { ((cfn)->fn)(td,2,cfn,a1,a2);} /* Return to continuation after checking for stack overflow. */ -#define return_closcall2(cfn,a1,a2) \ +#define return_closcall2(td,cfn,a1,a2) \ {char stack; \ if (check_overflow(&stack,stack_limit1)) { \ object buf[2]; buf[0] = a1;buf[1] = a2;\ - GC(cfn,buf,2); return; \ - } else {closcall2((closure) (cfn),a1,a2); return;}} + GC(td,cfn,buf,2); return; \ + } else {closcall2(td,(closure) (cfn),a1,a2); return;}} /*END closcall section */ /* Global variables. */ @@ -251,7 +251,7 @@ object Cyc_glo_eval = nil; /* Exception handler */ object Cyc_exception_handler_stack = nil; -object Cyc_default_exception_handler(int argc, closure _, object err) { +object Cyc_default_exception_handler(void *data, int argc, closure _, object err) { fprintf(stderr, "Error: "); if (nullp(err) || is_value_type(err) || type_of(err) != cons_tag) { @@ -281,29 +281,29 @@ object Cyc_current_exception_handler() { } /* Raise an exception from the runtime code */ -void Cyc_rt_raise(object err) { +void Cyc_rt_raise(void *data, object err) { make_cons(c2, err, nil); make_cons(c1, boolean_f, &c2); make_cons(c0, &c1, nil); - apply(nil, Cyc_current_exception_handler(), &c0); + apply(data, nil, Cyc_current_exception_handler(), &c0); // Should never get here fprintf(stderr, "Internal error in Cyc_rt_raise\n"); exit(1); } -void Cyc_rt_raise2(const char *msg, object err) { +void Cyc_rt_raise2(void *data, const char *msg, object err) { make_string(s, msg); make_cons(c3, err, nil); make_cons(c2, &s, &c3); make_cons(c1, boolean_f, &c2); make_cons(c0, &c1, nil); - apply(nil, Cyc_current_exception_handler(), &c0); + apply(data, nil, Cyc_current_exception_handler(), &c0); // Should never get here fprintf(stderr, "Internal error in Cyc_rt_raise2\n"); exit(1); } -void Cyc_rt_raise_msg(const char *err) { +void Cyc_rt_raise_msg(void *data, const char *err) { make_string(s, err); - Cyc_rt_raise(&s); + Cyc_rt_raise(data, &s); } /* END exception handler */ @@ -389,13 +389,13 @@ object Cyc_has_cycle(object lst) { // to the value returned by (current-output-port). It is an // error to attempt an output operation on a closed port // -object dispatch_display_va(int argc, object clo, object cont, object x, ...) { +object dispatch_display_va(void *data, int argc, object clo, object cont, object x, ...) { object result; va_list ap; va_start(ap, x); result = Cyc_display_va_list(argc - 1, x, ap); va_end(ap); - return_closcall1(cont, result); + return_closcall1(data, cont, result); } object Cyc_display_va(int argc, object x, ...) { @@ -506,13 +506,13 @@ object Cyc_display(object x, FILE *port) fprintf(port, "Cyc_display: bad tag x=%ld\n", ((closure)x)->tag); getchar(); exit(0);} return quote_void;} -object dispatch_write_va(int argc, object clo, object cont, object x, ...) { +object dispatch_write_va(void *data, int argc, object clo, object cont, object x, ...) { object result; va_list ap; va_start(ap, x); result = Cyc_write_va_list(argc - 1, x, ap); va_end(ap); - return_closcall1(cont, result); + return_closcall1(data, cont, result); } object Cyc_write_va(int argc, object x, ...) { @@ -585,7 +585,7 @@ object Cyc_write(object x, FILE *port) fprintf(port, "\n"); return y;} -object Cyc_write_char(object c, object port) +object Cyc_write_char(void *data, object c, object port) { if (obj_is_char(c)) { fprintf(((port_type *)port)->fp, "%c", obj_obj2char(c)); @@ -801,14 +801,14 @@ object Cyc_set_cdr(object l, object val) { return l; } -object Cyc_vector_set(object v, object k, object obj) { +object Cyc_vector_set(void *data, object v, object k, object obj) { int idx; Cyc_check_vec(v); Cyc_check_int(k); idx = ((integer_type *)k)->value; if (idx < 0 || idx >= ((vector)v)->num_elt) { - Cyc_rt_raise2("vector-set! - invalid index", k); + Cyc_rt_raise2(data, "vector-set! - invalid index", k); } ((vector)v)->elts[idx] = obj; @@ -818,32 +818,32 @@ object Cyc_vector_set(object v, object k, object obj) { return v; } -object Cyc_vector_ref(object v, object k) { +object Cyc_vector_ref(void *data, object v, object k) { if (nullp(v) || is_value_type(v) || ((list)v)->tag != vector_tag) { - Cyc_rt_raise_msg("vector-ref - invalid parameter, expected vector\n"); + Cyc_rt_raise_msg(data, "vector-ref - invalid parameter, expected vector\n"); } if (nullp(k) || is_value_type(k) || ((list)k)->tag != integer_tag) { - Cyc_rt_raise_msg("vector-ref - invalid parameter, expected integer\n"); + Cyc_rt_raise_msg(data, "vector-ref - invalid parameter, expected integer\n"); } if (integer_value(k) < 0 || integer_value(k) >= ((vector)v)->num_elt) { - Cyc_rt_raise2("vector-ref - invalid index", k); + Cyc_rt_raise2(data, "vector-ref - invalid index", k); } return ((vector)v)->elts[((integer_type *)k)->value]; } -integer_type Cyc_vector_length(object v) { +integer_type Cyc_vector_length(void *data, object v) { if (!nullp(v) && !is_value_type(v) && ((list)v)->tag == vector_tag) { make_int(len, ((vector)v)->num_elt); return len; } - Cyc_rt_raise_msg("vector-length - invalid parameter, expected vector\n"); } + Cyc_rt_raise_msg(data, "vector-length - invalid parameter, expected vector\n"); } -integer_type Cyc_length(object l){ +integer_type Cyc_length(void *data, object l){ make_int(len, 0); while(!nullp(l)){ if (is_value_type(l) || ((list)l)->tag != cons_tag){ - Cyc_rt_raise_msg("length - invalid parameter, expected list\n"); + Cyc_rt_raise_msg(data, "length - invalid parameter, expected list\n"); } l = cdr(l); len.value++; @@ -851,7 +851,7 @@ integer_type Cyc_length(object l){ return len; } -object Cyc_number2string(object cont, object n) { +object Cyc_number2string(void *data, object cont, object n) { char buffer[1024]; Cyc_check_num(n); if (type_of(n) == integer_tag) { @@ -859,18 +859,18 @@ object Cyc_number2string(object cont, object n) { } else if (type_of(n) == double_tag) { snprintf(buffer, 1024, "%lf", ((double_type *)n)->value); } else { - Cyc_rt_raise2("number->string - Unexpected object", n); + Cyc_rt_raise2(data, "number->string - Unexpected object", n); } //make_string_noalloc(str, buffer, strlen(buffer)); make_string(str, buffer); - return_closcall1(cont, &str); + return_closcall1(data, cont, &str); } -object Cyc_symbol2string(object cont, object sym) { +object Cyc_symbol2string(void *data, object cont, object sym) { Cyc_check_sym(sym); { const char *pname = symbol_pname(sym); make_string(str, pname); - return_closcall1(cont, &str); }} + return_closcall1(data, cont, &str); }} object Cyc_string2symbol(object str) { object sym; @@ -882,14 +882,14 @@ object Cyc_string2symbol(object str) { return sym; } -object Cyc_list2string(object cont, object lst){ +object Cyc_list2string(void *data, object cont, object lst){ char *buf; int i = 0; integer_type len; Cyc_check_cons_or_nil(lst); - len = Cyc_length(lst); // Inefficient, walks whole list + len = Cyc_length(data, lst); // Inefficient, walks whole list buf = alloca(sizeof(char) * (len.value + 1)); while(!nullp(lst)){ buf[i++] = obj_obj2char(car(lst)); @@ -899,7 +899,7 @@ object Cyc_list2string(object cont, object lst){ //{ make_string_noalloc(str, buf, i); { make_string(str, buf); - return_closcall1(cont, &str);} + return_closcall1(data, cont, &str);} } common_type Cyc_string2number(object str){ @@ -937,7 +937,7 @@ integer_type Cyc_string_cmp(object str1, object str2) { } } -#define Cyc_string_append_va_list(argc) { \ +#define Cyc_string_append_va_list(data, argc) { \ int i = 0, total_len = 1; \ int *len = alloca(sizeof(int) * argc); \ char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); \ @@ -963,19 +963,19 @@ integer_type Cyc_string_cmp(object str1, object str2) { *bufferp = '\0'; \ make_string(result, buffer); \ va_end(ap); \ - return_closcall1(cont, &result); \ + return_closcall1(data, cont, &result); \ } -void dispatch_string_91append(int _argc, object clo, object cont, object str1, ...) { +void dispatch_string_91append(void *data, int _argc, object clo, object cont, object str1, ...) { va_list ap; va_start(ap, str1); - Cyc_string_append_va_list(_argc - 1); + Cyc_string_append_va_list(data, _argc - 1); } -object Cyc_string_append(object cont, int _argc, object str1, ...) { +object Cyc_string_append(void *data, object cont, int _argc, object str1, ...) { va_list ap; va_start(ap, str1); - Cyc_string_append_va_list(_argc); + Cyc_string_append_va_list(data, _argc); } integer_type Cyc_string_length(object str) { @@ -984,7 +984,7 @@ integer_type Cyc_string_length(object str) { { make_int(len, strlen(string_str(str))); return len; }} -object Cyc_string_set(object str, object k, object chr) { +object Cyc_string_set(void *data, object str, object k, object chr) { char *raw; int idx, len; @@ -992,7 +992,7 @@ object Cyc_string_set(object str, object k, object chr) { Cyc_check_int(k); if (!eq(boolean_t, Cyc_is_char(chr))) { - Cyc_rt_raise2("Expected char but received", chr); + Cyc_rt_raise2(data, "Expected char but received", chr); } raw = string_str(str); @@ -1004,7 +1004,7 @@ object Cyc_string_set(object str, object k, object chr) { return str; } -object Cyc_string_ref(object str, object k) { +object Cyc_string_ref(void *data, object str, object k) { const char *raw; int idx, len; @@ -1016,13 +1016,13 @@ object Cyc_string_ref(object str, object k) { len = strlen(raw); if (idx < 0 || idx >= len) { - Cyc_rt_raise2("string-ref - invalid index", k); + Cyc_rt_raise2(data, "string-ref - invalid index", k); } return obj_char2obj(raw[idx]); } -object Cyc_substring(object cont, object str, object start, object end) { +object Cyc_substring(void *data, object cont, object str, object start, object end) { const char *raw; int s, e, len; @@ -1036,10 +1036,10 @@ object Cyc_substring(object cont, object str, object start, object end) { len = strlen(raw); if (s > e) { - Cyc_rt_raise2("substring - start cannot be greater than end", start); + Cyc_rt_raise2(data, "substring - start cannot be greater than end", start); } if (s > len) { - Cyc_rt_raise2("substring - start cannot be greater than string length", start); + Cyc_rt_raise2(data, "substring - start cannot be greater than string length", start); } if (e > len) { e = len; @@ -1047,13 +1047,7 @@ object Cyc_substring(object cont, object str, object start, object end) { { make_string_with_len(sub, raw + s, e - s); -//string_type sub; -//{ int len = e - s; -// sub.tag = string_tag; sub.len = len; -// sub.str = alloca(sizeof(char) * (len + 1)); -// memcpy(sub.str, raw + s, len); -// sub.str[len + 1] = '\0';} - return_closcall1(cont, &sub); + return_closcall1(data, cont, &sub); } } @@ -1061,28 +1055,28 @@ object Cyc_substring(object cont, object str, object start, object end) { * Return directory where cyclone is installed. * This is configured via the makefile during a build. */ -object Cyc_installation_dir(object cont, object type) { +object Cyc_installation_dir(void *data, object cont, object type) { if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "sld", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_SLD); make_string(str, buf); - return_closcall1(cont, &str); + return_closcall1(data, cont, &str); } else if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "lib", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_LIB); make_string(str, buf); - return_closcall1(cont, &str); + return_closcall1(data, cont, &str); } else if (Cyc_is_symbol(type) == boolean_t && strncmp(((symbol)type)->pname, "inc", 5) == 0) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", CYC_INSTALL_INC); make_string(str, buf); - return_closcall1(cont, &str); + return_closcall1(data, cont, &str); } else { make_string(str, CYC_INSTALL_DIR); - return_closcall1(cont, &str); + return_closcall1(data, cont, &str); } } @@ -1095,7 +1089,7 @@ object Cyc_installation_dir(object cont, object type) { * * For now, runtime options are not removed. */ -object Cyc_command_line_arguments(object cont) { +object Cyc_command_line_arguments(void *data, object cont) { int i; object lis = nil; for (i = _cyc_argc; i > 1; i--) { // skip program name @@ -1109,10 +1103,10 @@ object Cyc_command_line_arguments(object cont) { ((list)pl)->cons_cdr = lis; lis = pl; } - return_closcall1(cont, lis); + return_closcall1(data, cont, lis); } -object Cyc_make_vector(object cont, object len, object fill) { +object Cyc_make_vector(void *data, object cont, object len, object fill) { object v = nil; int i; Cyc_check_int(len); @@ -1127,10 +1121,10 @@ object Cyc_make_vector(object cont, object len, object fill) { for (i = 0; i < ((vector)v)->num_elt; i++) { ((vector)v)->elts[i] = fill; } - return_closcall1(cont, v); + return_closcall1(data, cont, v); } -object Cyc_list2vector(object cont, object l) { +object Cyc_list2vector(void *data, object cont, object l) { object v = nil; integer_type len; object lst = l; @@ -1150,7 +1144,7 @@ object Cyc_list2vector(object cont, object l) { ((vector)v)->elts[i++] = car(lst); lst = cdr(lst); } - return_closcall1(cont, v); + return_closcall1(data, cont, v); } integer_type Cyc_system(object cmd) { @@ -1193,6 +1187,8 @@ object __halt(object obj) { return nil; } +JAE TODO: left off here + #define declare_num_op(FUNC, FUNC_OP, FUNC_APPLY, OP, DIV) \ common_type FUNC_OP(object x, object y) { \ common_type s; \ @@ -1823,7 +1819,7 @@ void _Cyc_91read_91line(object cont, object args) { Cyc_io_read_line(cont, car(args));} void _Cyc_91write_91char(object cont, object args) { Cyc_check_num_args("write-char", 2, args); - return_closcall1(cont, Cyc_write_char(car(args), cadr(args)));} + return_closcall1(cont, Cyc_write_char(data, car(args), cadr(args)));} void _Cyc_91write(object cont, object args) { Cyc_check_num_args("write", 1, args); { integer_type argc = Cyc_length(args); From 196cc5143123ddc8df159e5061069cedbef7869c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 21:50:46 -0400 Subject: [PATCH 091/339] WIP --- gc-notes.txt | 8 ++++++++ runtime.c | 47 +++++++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index b94def8c..09050d33 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -21,9 +21,17 @@ object Cyc_installation_dir(object cont, object type) { object Cyc_command_line_arguments(object cont) { object Cyc_make_vector(object cont, object len, object fill) { object Cyc_list2vector(void *data, object cont, object l) { +declare_num_op(Cyc_sum, Cyc_sum_op, dispatch_sum, +, 0); +declare_num_op(Cyc_sub, Cyc_sub_op, dispatch_sub, -, 0); +declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *, 0); +declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /, 1); +port_type Cyc_io_open_input_file(void *data, object str) { +port_type Cyc_io_open_output_file(void *data, object str) { - plan: - update runtime, get it to compile + - have not adjusted any code that checks value of argc, will probably need to do that + EG for Cyc_num_op_va_list - update any associated tools (dispatch.c, etc) - update cgen - integration diff --git a/runtime.c b/runtime.c index de7e5b0f..7ca7e21b 100644 --- a/runtime.c +++ b/runtime.c @@ -1187,19 +1187,19 @@ object __halt(object obj) { return nil; } -JAE TODO: left off here - #define declare_num_op(FUNC, FUNC_OP, FUNC_APPLY, OP, DIV) \ -common_type FUNC_OP(object x, object y) { \ +common_type FUNC_OP(void *data, object x, object y) { \ common_type s; \ int tx = type_of(x), ty = type_of(y); \ + s.double_t.hdr.mark = gc_color_red; \ s.double_t.tag = double_tag; \ if (DIV && \ ((ty == integer_tag && integer_value(y) == 0) || \ (ty == double_tag && double_value(y) == 0.0))) { \ - Cyc_rt_raise_msg("Divide by zero"); \ + Cyc_rt_raise_msg(data, "Divide by zero"); \ } \ if (tx == integer_tag && ty == integer_tag) { \ + s.integer_t.hdr.mark = gc_color_red; \ s.integer_t.tag = integer_tag; \ s.integer_t.value = ((integer_type *)x)->value OP ((integer_type *)y)->value; \ } else if (tx == double_tag && ty == integer_tag) { \ @@ -1212,23 +1212,23 @@ common_type FUNC_OP(object x, object y) { \ make_string(s, "Bad argument type"); \ make_cons(c1, y, nil); \ make_cons(c0, &s, &c1); \ - Cyc_rt_raise(&c0); \ + Cyc_rt_raise(data, &c0); \ } \ return s; \ } \ -common_type FUNC(int argc, object n, ...) { \ +common_type FUNC(void *data, int argc, object n, ...) { \ va_list ap; \ va_start(ap, n); \ - common_type result = Cyc_num_op_va_list(argc, FUNC_OP, n, ap); \ + common_type result = Cyc_num_op_va_list(data, argc, FUNC_OP, n, ap); \ va_end(ap); \ return result; \ } \ -void FUNC_APPLY(int argc, object clo, object cont, object n, ...) { \ +void FUNC_APPLY(void *data, int argc, object clo, object cont, object n, ...) { \ va_list ap; \ va_start(ap, n); \ - common_type result = Cyc_num_op_va_list(argc - 1, FUNC_OP, n, ap); \ + common_type result = Cyc_num_op_va_list(data, argc - 1, FUNC_OP, n, ap); \ va_end(ap); \ - return_closcall1(cont, &result); \ + return_closcall1(data, cont, &result); \ } declare_num_op(Cyc_sum, Cyc_sum_op, dispatch_sum, +, 0); @@ -1238,38 +1238,43 @@ declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *, 0); // result contains a decimal component? declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /, 1); -common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns) { +common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(object, object)), object n, va_list ns) { common_type sum; int i; if (argc == 0) { + sum.integer_t.hdr.mark = gc_color_red; sum.integer_t.tag = integer_tag; sum.integer_t.value = 0; return sum; } if (type_of(n) == integer_tag) { + sum.integer_t.hdr.mark = gc_color_red; sum.integer_t.tag = integer_tag; sum.integer_t.value = ((integer_type *)n)->value; } else if (type_of(n) == double_tag) { + sum.double_t.hdr.mark = gc_color_red; sum.double_t.tag = double_tag; sum.double_t.value = ((double_type *)n)->value; } else { make_string(s, "Bad argument type"); make_cons(c1, n, nil); make_cons(c0, &s, &c1); - Cyc_rt_raise(&c0); + Cyc_rt_raise(data, &c0); } for (i = 1; i < argc; i++) { common_type result = fn_op(&sum, va_arg(ns, object)); if (type_of(&result) == integer_tag) { + sum.integer_t.hdr.mark = gc_color_red; sum.integer_t.tag = integer_tag; sum.integer_t.value = ((integer_type *) &result)->value; } else if (type_of(&result) == double_tag) { + sum.double_t.hdr.mark = gc_color_red; sum.double_t.tag = double_tag; sum.double_t.value = ((double_type *) &result)->value; } else { - Cyc_rt_raise_msg("Internal error, invalid tag in Cyc_num_op_va_list"); + Cyc_rt_raise_msg(data, "Internal error, invalid tag in Cyc_num_op_va_list"); } } @@ -1293,23 +1298,23 @@ port_type Cyc_stderr() { return p; } -port_type Cyc_io_open_input_file(object str) { +port_type Cyc_io_open_input_file(void *data, object str) { const char *fname; Cyc_check_str(str); fname = ((string_type *)str)->str; make_port(p, NULL, 1); p.fp = fopen(fname, "r"); - if (p.fp == NULL) { Cyc_rt_raise2("Unable to open file", str); } + if (p.fp == NULL) { Cyc_rt_raise2(data, "Unable to open file", str); } return p; } -port_type Cyc_io_open_output_file(object str) { +port_type Cyc_io_open_output_file(void *data, object str) { const char *fname; Cyc_check_str(str); fname = ((string_type *)str)->str; make_port(p, NULL, 0); p.fp = fopen(fname, "w"); - if (p.fp == NULL) { Cyc_rt_raise2("Unable to open file", str); } + if (p.fp == NULL) { Cyc_rt_raise2(data, "Unable to open file", str); } return p; } @@ -1376,7 +1381,7 @@ object Cyc_io_read_char(object port) { } /* TODO: this function needs some work, but approximates what is needed */ -object Cyc_io_read_line(object cont, object port) { +object Cyc_io_read_line(void *data, object cont, object port) { FILE *stream = ((port_type *)port)->fp; char buf[1024]; int i = 0, c; @@ -1384,12 +1389,12 @@ object Cyc_io_read_line(object cont, object port) { while (1) { c = fgetc(stream); if (c == EOF && i == 0) { - return_closcall1(cont, Cyc_EOF); + return_closcall1(data, cont, Cyc_EOF); } else if (c == EOF || i == 1023 || c == '\n') { buf[i] = '\0'; { make_string(s, buf); - return_closcall1(cont, &s); + return_closcall1(data, cont, &s); } } @@ -1428,6 +1433,8 @@ cvar_type *mcvar(object *var) { c->pvar = var; return c;} +JAE TODO: left off thread data changes here + void _Cyc_91global_91vars(object cont, object args){ return_closcall1(cont, Cyc_global_variables); } void _car(object cont, object args) { From 9ebe928f6b01d0fe69e27bf8a1dd3712ad22a1b2 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 30 Oct 2015 23:16:20 -0400 Subject: [PATCH 092/339] WIP --- gc-notes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/gc-notes.txt b/gc-notes.txt index 09050d33..fd50c895 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -27,6 +27,7 @@ declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *, 0); declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /, 1); port_type Cyc_io_open_input_file(void *data, object str) { port_type Cyc_io_open_output_file(void *data, object str) { +object Cyc_io_read_line(void *data, object cont, object port) { - plan: - update runtime, get it to compile From 4dd95d718e1ed775d86675c45940321aed0cf694 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 2 Nov 2015 22:44:32 -0500 Subject: [PATCH 093/339] Added thread data argument --- generate-c.scm | 5 +- include/cyclone/runtime-main.h | 1 + include/cyclone/runtime.h | 54 ++-- runtime.c | 509 ++++++++++++++++----------------- 4 files changed, 285 insertions(+), 284 deletions(-) diff --git a/generate-c.scm b/generate-c.scm index 08078a75..9eeff6b0 100644 --- a/generate-c.scm +++ b/generate-c.scm @@ -17,7 +17,7 @@ #include \"cyclone/types.h\" #include \"cyclone/runtime.h\" -void do_dispatch(int argc, function_type func, object clo, object *b) { +void do_dispatch(void *data, int argc, function_type func, object clo, object *b) { switch(argc) {" ) (define bs "") @@ -25,6 +25,7 @@ void do_dispatch(int argc, function_type func, object clo, object *b) { (display "case " ) (display i ) (display ":func(" ) + (display "data,") (display i ) (display ",clo" ) (display bs ) @@ -39,7 +40,7 @@ void do_dispatch(int argc, function_type func, object clo, object *b) { { char buf[1024]; snprintf(buf, 1023, \"Unhandled number of function arguments: %d\\n\", argc); - Cyc_rt_raise_msg(buf); + Cyc_rt_raise_msg(data, buf); } } }" ))) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 5a4af9eb..13e58601 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -85,6 +85,7 @@ static void Cyc_main (stack_size,heap_size,stack_base) printf("Done with GC\n"); #endif +// JAE - note for the general case, setjmp will return the data pointer's addy if (type_of(gc_cont) == cons_tag || prim(gc_cont)) { Cyc_apply_from_buf(gc_num_ans, gc_cont, gc_ans); } else { diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 45e75e1a..d692930d 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -10,30 +10,30 @@ #define CYCLONE_RUNTIME_H /* Error checking definitions */ -#define Cyc_check_num_args(fnc_name, num_args, args) { \ - integer_type l = Cyc_length(args); \ +#define Cyc_check_num_args(data, fnc_name, num_args, args) { \ + integer_type l = Cyc_length(data, args); \ if (num_args > l.value) { \ char buf[128]; \ snprintf(buf, 127, "Expected %d arguments but received %d.", num_args, l.value); \ - Cyc_rt_raise_msg(buf); \ + Cyc_rt_raise_msg(data, buf); \ } \ } -#define Cyc_check_type(fnc_test, tag, obj) { \ - if (eq(boolean_f, fnc_test(obj))) Cyc_invalid_type_error(tag, obj); } +#define Cyc_check_type(data, fnc_test, tag, obj) { \ + if (eq(boolean_f, fnc_test(obj))) Cyc_invalid_type_error(data, tag, obj); } -#define Cyc_check_cons_or_nil(obj) { if (!nullp(obj)) { Cyc_check_cons(obj); }} -#define Cyc_check_cons(obj) Cyc_check_type(Cyc_is_cons, cons_tag, obj); -#define Cyc_check_num(obj) Cyc_check_type(Cyc_is_number, integer_tag, obj); -#define Cyc_check_int(obj) Cyc_check_type(Cyc_is_integer, integer_tag, obj); -#define Cyc_check_str(obj) Cyc_check_type(Cyc_is_string, string_tag, obj); -#define Cyc_check_sym(obj) Cyc_check_type(Cyc_is_symbol, symbol_tag, obj); -#define Cyc_check_vec(obj) Cyc_check_type(Cyc_is_vector, vector_tag, obj); -#define Cyc_check_port(obj) Cyc_check_type(Cyc_is_port, port_tag, obj); -#define Cyc_check_fnc(obj) Cyc_check_type(Cyc_is_procedure, closure2_tag, obj); -void Cyc_invalid_type_error(int tag, object found); -void Cyc_check_obj(int tag, object obj); -void Cyc_check_bounds(const char *label, int len, int index); +#define Cyc_check_cons_or_nil(d,obj) { if (!nullp(obj)) { Cyc_check_cons(d,obj); }} +#define Cyc_check_cons(d,obj) Cyc_check_type(d,Cyc_is_cons, cons_tag, obj); +#define Cyc_check_num(d,obj) Cyc_check_type(d,Cyc_is_number, integer_tag, obj); +#define Cyc_check_int(d,obj) Cyc_check_type(d,Cyc_is_integer, integer_tag, obj); +#define Cyc_check_str(d,obj) Cyc_check_type(d,Cyc_is_string, string_tag, obj); +#define Cyc_check_sym(d,obj) Cyc_check_type(d,Cyc_is_symbol, symbol_tag, obj); +#define Cyc_check_vec(d,obj) Cyc_check_type(d,Cyc_is_vector, vector_tag, obj); +#define Cyc_check_port(d,obj) Cyc_check_type(d,Cyc_is_port, port_tag, obj); +#define Cyc_check_fnc(d,obj) Cyc_check_type(d,Cyc_is_procedure, closure2_tag, obj); +void Cyc_invalid_type_error(void *data, int tag, object found); +void Cyc_check_obj(void *data, int tag, object obj); +void Cyc_check_bounds(void *data, const char *label, int len, int index); /* END error checking */ extern long global_stack_size; @@ -80,7 +80,7 @@ object cell_get(object cell); } \ } -/* Prototypes for Lisp built-in functions. */ +/* Prototypes for primitive functions. */ extern object Cyc_global_variables; int _cyc_argc; @@ -88,8 +88,8 @@ char **_cyc_argv; object Cyc_get_global_variables(); object Cyc_get_cvar(object var); object Cyc_set_cvar(object var, object value); -object apply(object cont, object func, object args); -void Cyc_apply(int argc, closure cont, object prim, ...); +object apply(void *data, object cont, object func, object args); +void Cyc_apply(void *data, int argc, closure cont, object prim, ...); integer_type Cyc_string_cmp(object str1, object str2); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); list mcons(object,object); @@ -204,9 +204,9 @@ void add_mutation(object var, object value); void clear_mutations(); extern list mutation_table; -void dispatch(int argc, function_type func, object clo, object cont, object args); -void dispatch_va(int argc, function_type_va func, object clo, object cont, object args); -void do_dispatch(int argc, function_type func, object clo, object *buffer); +void dispatch(void *data, int argc, function_type func, object clo, object cont, object args); +void dispatch_va(void *data, int argc, function_type_va func, object clo, object cont, object args); +void do_dispatch(void *data, int argc, function_type func, object clo, object *buffer); /* Global variables. */ extern gc_heap *Cyc_heap; @@ -372,11 +372,11 @@ extern object Cyc_exception_handler_stack; // behavior portable? If not, will have to modify cgen to not emit the var. #define __glo__85exception_91handler_91stack_85 Cyc_exception_handler_stack -object Cyc_default_exception_handler(int argc, closure _, object err); +object Cyc_default_exception_handler(void *data, int argc, closure _, object err); object Cyc_current_exception_handler(); -void Cyc_rt_raise(object err); -void Cyc_rt_raise2(const char *msg, object err); -void Cyc_rt_raise_msg(const char *err); +void Cyc_rt_raise(void *data, object err); +void Cyc_rt_raise2(void *data, const char *msg, object err); +void Cyc_rt_raise_msg(void *data, const char *err); /* END exception handler */ #endif /* CYCLONE_RUNTIME_H */ diff --git a/runtime.c b/runtime.c index 7ca7e21b..f1323b58 100644 --- a/runtime.c +++ b/runtime.c @@ -37,23 +37,23 @@ const char *tag_names[21] = { \ , "Reserved for future use" \ , "Reserved for future use" }; -void Cyc_invalid_type_error(int tag, object found) { +void Cyc_invalid_type_error(void *data, int tag, object found) { char buf[256]; snprintf(buf, 255, "Invalid type: expected %s, found", tag_names[tag]); - Cyc_rt_raise2(buf, found); + Cyc_rt_raise2(data, buf, found); } -void Cyc_check_obj(int tag, object obj) { +void Cyc_check_obj(void *data, int tag, object obj) { if (!is_object_type(obj)) { - Cyc_invalid_type_error(tag, obj); + Cyc_invalid_type_error(data, tag, obj); } } -void Cyc_check_bounds(const char *label, int len, int index) { +void Cyc_check_bounds(void *data, const char *label, int len, int index) { if (index < 0 || index >= len) { char buf[128]; snprintf(buf, 127, "%s - invalid index %d", label, index); - Cyc_rt_raise_msg(buf); + Cyc_rt_raise_msg(data, buf); } } @@ -590,7 +590,7 @@ object Cyc_write_char(void *data, object c, object port) if (obj_is_char(c)) { fprintf(((port_type *)port)->fp, "%c", obj_obj2char(c)); } else { - Cyc_rt_raise2("Argument is not a character", c); + Cyc_rt_raise2(data, "Argument is not a character", c); } return quote_void; } @@ -1433,412 +1433,410 @@ cvar_type *mcvar(object *var) { c->pvar = var; return c;} -JAE TODO: left off thread data changes here - -void _Cyc_91global_91vars(object cont, object args){ - return_closcall1(cont, Cyc_global_variables); } -void _car(object cont, object args) { +void _Cyc_91global_91vars(void *data, object cont, object args){ + return_closcall1(data, cont, Cyc_global_variables); } +void _car(void *data, object cont, object args) { Cyc_check_num_args("car", 1, args); { object var = car(args); Cyc_check_cons(var); - return_closcall1(cont, car(var)); }} -void _cdr(object cont, object args) { + return_closcall1(data, cont, car(var)); }} +void _cdr(void *data, object cont, object args) { Cyc_check_num_args("cdr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdr(car(args))); } -void _caar(object cont, object args) { + return_closcall1(data, cont, cdr(car(args))); } +void _caar(void *data, object cont, object args) { Cyc_check_num_args("caar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caar(car(args))); } -void _cadr(object cont, object args) { + return_closcall1(data, cont, caar(car(args))); } +void _cadr(void *data, object cont, object args) { Cyc_check_num_args("cadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cadr(car(args))); } -void _cdar(object cont, object args) { + return_closcall1(data, cont, cadr(car(args))); } +void _cdar(void *data, object cont, object args) { Cyc_check_num_args("cdar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdar(car(args))); } -void _cddr(object cont, object args) { + return_closcall1(data, cont, cdar(car(args))); } +void _cddr(void *data, object cont, object args) { Cyc_check_num_args("cddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cddr(car(args))); } -void _caaar(object cont, object args) { + return_closcall1(data, cont, cddr(car(args))); } +void _caaar(void *data, object cont, object args) { Cyc_check_num_args("caaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caaar(car(args))); } -void _caadr(object cont, object args) { + return_closcall1(data, cont, caaar(car(args))); } +void _caadr(void *data, object cont, object args) { Cyc_check_num_args("caadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caadr(car(args))); } -void _cadar(object cont, object args) { + return_closcall1(data, cont, caadr(car(args))); } +void _cadar(void *data, object cont, object args) { Cyc_check_num_args("cadar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cadar(car(args))); } -void _caddr(object cont, object args) { + return_closcall1(data, cont, cadar(car(args))); } +void _caddr(void *data, object cont, object args) { Cyc_check_num_args("caddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caddr(car(args))); } -void _cdaar(object cont, object args) { + return_closcall1(data, cont, caddr(car(args))); } +void _cdaar(void *data, object cont, object args) { Cyc_check_num_args("cdaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdaar(car(args))); } -void _cdadr(object cont, object args) { + return_closcall1(data, cont, cdaar(car(args))); } +void _cdadr(void *data, object cont, object args) { Cyc_check_num_args("cdadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdadr(car(args))); } -void _cddar(object cont, object args) { + return_closcall1(data, cont, cdadr(car(args))); } +void _cddar(void *data, object cont, object args) { Cyc_check_num_args("cddar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cddar(car(args))); } -void _cdddr(object cont, object args) { + return_closcall1(data, cont, cddar(car(args))); } +void _cdddr(void *data, object cont, object args) { Cyc_check_num_args("cdddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdddr(car(args))); } -void _caaaar(object cont, object args) { + return_closcall1(data, cont, cdddr(car(args))); } +void _caaaar(void *data, object cont, object args) { Cyc_check_num_args("caaaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caaaar(car(args))); } -void _caaadr(object cont, object args) { + return_closcall1(data, cont, caaaar(car(args))); } +void _caaadr(void *data, object cont, object args) { Cyc_check_num_args("caaadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caaadr(car(args))); } -void _caadar(object cont, object args) { + return_closcall1(data, cont, caaadr(car(args))); } +void _caadar(void *data, object cont, object args) { Cyc_check_num_args("caadar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caadar(car(args))); } -void _caaddr(object cont, object args) { + return_closcall1(data, cont, caadar(car(args))); } +void _caaddr(void *data, object cont, object args) { Cyc_check_num_args("caaddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caaddr(car(args))); } -void _cadaar(object cont, object args) { + return_closcall1(data, cont, caaddr(car(args))); } +void _cadaar(void *data, object cont, object args) { Cyc_check_num_args("cadaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cadaar(car(args))); } -void _cadadr(object cont, object args) { + return_closcall1(data, cont, cadaar(car(args))); } +void _cadadr(void *data, object cont, object args) { Cyc_check_num_args("cadadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cadadr(car(args))); } -void _caddar(object cont, object args) { + return_closcall1(data, cont, cadadr(car(args))); } +void _caddar(void *data, object cont, object args) { Cyc_check_num_args("caddar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, caddar(car(args))); } -void _cadddr(object cont, object args) { + return_closcall1(data, cont, caddar(car(args))); } +void _cadddr(void *data, object cont, object args) { Cyc_check_num_args("cadddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cadddr(car(args))); } -void _cdaaar(object cont, object args) { + return_closcall1(data, cont, cadddr(car(args))); } +void _cdaaar(void *data, object cont, object args) { Cyc_check_num_args("cdaaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdaaar(car(args))); } -void _cdaadr(object cont, object args) { + return_closcall1(data, cont, cdaaar(car(args))); } +void _cdaadr(void *data, object cont, object args) { Cyc_check_num_args("cdaadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdaadr(car(args))); } -void _cdadar(object cont, object args) { + return_closcall1(data, cont, cdaadr(car(args))); } +void _cdadar(void *data, object cont, object args) { Cyc_check_num_args("cdadar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdadar(car(args))); } -void _cdaddr(object cont, object args) { + return_closcall1(data, cont, cdadar(car(args))); } +void _cdaddr(void *data, object cont, object args) { Cyc_check_num_args("cdaddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdaddr(car(args))); } -void _cddaar(object cont, object args) { + return_closcall1(data, cont, cdaddr(car(args))); } +void _cddaar(void *data, object cont, object args) { Cyc_check_num_args("cddaar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cddaar(car(args))); } -void _cddadr(object cont, object args) { + return_closcall1(data, cont, cddaar(car(args))); } +void _cddadr(void *data, object cont, object args) { Cyc_check_num_args("cddadr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cddadr(car(args))); } -void _cdddar(object cont, object args) { + return_closcall1(data, cont, cddadr(car(args))); } +void _cdddar(void *data, object cont, object args) { Cyc_check_num_args("cdddar", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cdddar(car(args))); } -void _cddddr(object cont, object args) { + return_closcall1(data, cont, cdddar(car(args))); } +void _cddddr(void *data, object cont, object args) { Cyc_check_num_args("cddddr", 1, args); Cyc_check_cons(car(args)); - return_closcall1(cont, cddddr(car(args))); } -void _cons(object cont, object args) { + return_closcall1(data, cont, cddddr(car(args))); } +void _cons(void *data, object cont, object args) { Cyc_check_num_args("cons", 2, args); { make_cons(c, car(args), cadr(args)); - return_closcall1(cont, &c); }} -void _eq_127(object cont, object args){ + return_closcall1(data, cont, &c); }} +void _eq_127(void *data, object cont, object args){ Cyc_check_num_args("eq?", 2, args); - return_closcall1(cont, Cyc_eq(car(args), cadr(args))); } -void _eqv_127(object cont, object args){ + return_closcall1(data, cont, Cyc_eq(car(args), cadr(args))); } +void _eqv_127(void *data, object cont, object args){ Cyc_check_num_args("eqv?", 2, args); - _eq_127(cont, args); } -void _equal_127(object cont, object args){ + _eq_127(data, cont, args); } +void _equal_127(void *data, object cont, object args){ Cyc_check_num_args("equal?", 2, args); - return_closcall1(cont, equalp(car(args), cadr(args))); } -void _length(object cont, object args){ + return_closcall1(data, cont, equalp(car(args), cadr(args))); } +void _length(void *data, object cont, object args){ Cyc_check_num_args("length", 1, args); { integer_type i = Cyc_length(car(args)); - return_closcall1(cont, &i); }} -void _vector_91length(object cont, object args){ + return_closcall1(data, cont, &i); }} +void _vector_91length(void *data, object cont, object args){ Cyc_check_num_args("vector_91length", 1, args); { integer_type i = Cyc_vector_length(car(args)); - return_closcall1(cont, &i); }} -void _null_127(object cont, object args) { + return_closcall1(data, cont, &i); }} +void _null_127(void *data, object cont, object args) { Cyc_check_num_args("null?", 1, args); - return_closcall1(cont, Cyc_is_null(car(args))); } -void _set_91car_67(object cont, object args) { + return_closcall1(data, cont, Cyc_is_null(car(args))); } +void _set_91car_67(void *data, object cont, object args) { Cyc_check_num_args("set-car!", 2, args); - return_closcall1(cont, Cyc_set_car(car(args), cadr(args))); } -void _set_91cdr_67(object cont, object args) { + return_closcall1(data, cont, Cyc_set_car(car(args), cadr(args))); } +void _set_91cdr_67(void *data, object cont, object args) { Cyc_check_num_args("set-cdr!", 2, args); - return_closcall1(cont, Cyc_set_cdr(car(args), cadr(args))); } -void _Cyc_91has_91cycle_127(object cont, object args) { + return_closcall1(data, cont, Cyc_set_cdr(car(args), cadr(args))); } +void _Cyc_91has_91cycle_127(void *data, object cont, object args) { Cyc_check_num_args("Cyc-has-cycle?", 1, args); - return_closcall1(cont, Cyc_has_cycle(car(args))); } -void __87(object cont, object args) { + return_closcall1(data, cont, Cyc_has_cycle(car(args))); } +void __87(void *data, object cont, object args) { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_sum, cont, cont, args); } -void __91(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_sum, cont, cont, args); } +void __91(void *data, object cont, object args) { Cyc_check_num_args("-", 1, args); { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_sub, cont, cont, args); }} -void __85(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_sub, cont, cont, args); }} +void __85(void *data, object cont, object args) { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_mul, cont, cont, args); } -void __95(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_mul, cont, cont, args); } +void __95(void *data, object cont, object args) { Cyc_check_num_args("/", 1, args); { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_div, cont, cont, args); }} -void _Cyc_91cvar_127(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_div, cont, cont, args); }} +void _Cyc_91cvar_127(void *data, object cont, object args) { Cyc_check_num_args("Cyc-cvar?", 1, args); - return_closcall1(cont, Cyc_is_cvar(car(args))); } -void _boolean_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_cvar(car(args))); } +void _boolean_127(void *data, object cont, object args) { Cyc_check_num_args("boolean?", 1, args); - return_closcall1(cont, Cyc_is_boolean(car(args))); } -void _char_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_boolean(car(args))); } +void _char_127(void *data, object cont, object args) { Cyc_check_num_args("char?", 1, args); - return_closcall1(cont, Cyc_is_char(car(args))); } -void _eof_91object_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_char(car(args))); } +void _eof_91object_127(void *data, object cont, object args) { Cyc_check_num_args("eof_91object?", 1, args); - return_closcall1(cont, Cyc_is_eof_object(car(args))); } -void _number_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_eof_object(car(args))); } +void _number_127(void *data, object cont, object args) { Cyc_check_num_args("number?", 1, args); - return_closcall1(cont, Cyc_is_number(car(args))); } -void _real_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_number(car(args))); } +void _real_127(void *data, object cont, object args) { Cyc_check_num_args("real?", 1, args); - return_closcall1(cont, Cyc_is_real(car(args))); } -void _integer_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_real(car(args))); } +void _integer_127(void *data, object cont, object args) { Cyc_check_num_args("integer?", 1, args); - return_closcall1(cont, Cyc_is_integer(car(args))); } -void _pair_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_integer(car(args))); } +void _pair_127(void *data, object cont, object args) { Cyc_check_num_args("pair?", 1, args); - return_closcall1(cont, Cyc_is_cons(car(args))); } -void _procedure_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_cons(car(args))); } +void _procedure_127(void *data, object cont, object args) { Cyc_check_num_args("procedure?", 1, args); - return_closcall1(cont, Cyc_is_procedure(car(args))); } -void _macro_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_procedure(car(args))); } +void _macro_127(void *data, object cont, object args) { Cyc_check_num_args("macro?", 1, args); - return_closcall1(cont, Cyc_is_macro(car(args))); } -void _port_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_macro(car(args))); } +void _port_127(void *data, object cont, object args) { Cyc_check_num_args("port?", 1, args); - return_closcall1(cont, Cyc_is_port(car(args))); } -void _vector_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_port(car(args))); } +void _vector_127(void *data, object cont, object args) { Cyc_check_num_args("vector?", 1, args); - return_closcall1(cont, Cyc_is_vector(car(args))); } -void _string_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_vector(car(args))); } +void _string_127(void *data, object cont, object args) { Cyc_check_num_args("string?", 1, args); - return_closcall1(cont, Cyc_is_string(car(args))); } -void _symbol_127(object cont, object args) { + return_closcall1(data, cont, Cyc_is_string(car(args))); } +void _symbol_127(void *data, object cont, object args) { Cyc_check_num_args("symbol?", 1, args); - return_closcall1(cont, Cyc_is_symbol(car(args))); } + return_closcall1(data, cont, Cyc_is_symbol(car(args))); } -void _Cyc_91get_91cvar(object cont, object args) { +void _Cyc_91get_91cvar(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } -void _Cyc_91set_91cvar_67(object cont, object args) { +void _Cyc_91set_91cvar_67(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } /* Note we cannot use _exit (per convention) because it is reserved by C */ -void _cyc_exit(object cont, object args) { +void _cyc_exit(void *data, object cont, object args) { if(nullp(args)) __halt(nil); __halt(car(args)); } -void __75halt(object cont, object args) { +void __75halt(void *data, object cont, object args) { exit(0); } -void _cell_91get(object cont, object args) { +void _cell_91get(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } -void _set_91global_67(object cont, object args) { +void _set_91global_67(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } -void _set_91cell_67(object cont, object args) { +void _set_91cell_67(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } -void _cell(object cont, object args) { +void _cell(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } -void __123(object cont, object args) { +void __123(void *data, object cont, object args) { Cyc_check_num_args("=", 2, args); - return_closcall1(cont, __num_eq(car(args), cadr(args)));} -void __125(object cont, object args) { + return_closcall1(data, cont, __num_eq(car(args), cadr(args)));} +void __125(void *data, object cont, object args) { Cyc_check_num_args(">", 2, args); - return_closcall1(cont, __num_gt(car(args), cadr(args)));} -void __121(object cont, object args) { + return_closcall1(data, cont, __num_gt(car(args), cadr(args)));} +void __121(void *data, object cont, object args) { Cyc_check_num_args("<", 2, args); - return_closcall1(cont, __num_lt(car(args), cadr(args)));} -void __125_123(object cont, object args) { + return_closcall1(data, cont, __num_lt(car(args), cadr(args)));} +void __125_123(void *data, object cont, object args) { Cyc_check_num_args(">=", 2, args); - return_closcall1(cont, __num_gte(car(args), cadr(args)));} -void __121_123(object cont, object args) { + return_closcall1(data, cont, __num_gte(car(args), cadr(args)));} +void __121_123(void *data, object cont, object args) { Cyc_check_num_args("<=", 2, args); - return_closcall1(cont, __num_lte(car(args), cadr(args)));} + return_closcall1(data, cont, __num_lte(car(args), cadr(args)));} -void _apply(object cont, object args) { +void _apply(void *data, object cont, object args) { Cyc_check_num_args("apply", 2, args); - apply(cont, car(args), cadr(args)); } -void _assoc (object cont, object args) { + apply(data, cont, car(args), cadr(args)); } +void _assoc (void *data, object cont, object args) { Cyc_check_num_args("assoc ", 2, args); - return_closcall1(cont, assoc(car(args), cadr(args)));} -void _assq (object cont, object args) { + return_closcall1(data, cont, assoc(car(args), cadr(args)));} +void _assq (void *data, object cont, object args) { Cyc_check_num_args("assq ", 2, args); - return_closcall1(cont, assq(car(args), cadr(args)));} -void _assv (object cont, object args) { + return_closcall1(data, cont, assq(car(args), cadr(args)));} +void _assv (void *data, object cont, object args) { Cyc_check_num_args("assv ", 2, args); - return_closcall1(cont, assq(car(args), cadr(args)));} -void _member(object cont, object args) { + return_closcall1(data, cont, assq(car(args), cadr(args)));} +void _member(void *data, object cont, object args) { Cyc_check_num_args("member", 2, args); - return_closcall1(cont, memberp(car(args), cadr(args)));} -void _memq(object cont, object args) { + return_closcall1(data, cont, memberp(car(args), cadr(args)));} +void _memq(void *data, object cont, object args) { Cyc_check_num_args("memq", 2, args); - return_closcall1(cont, memqp(car(args), cadr(args)));} -void _memv(object cont, object args) { + return_closcall1(data, cont, memqp(car(args), cadr(args)));} +void _memv(void *data, object cont, object args) { Cyc_check_num_args("memv", 2, args); - return_closcall1(cont, memqp(car(args), cadr(args)));} -void _char_91_125integer(object cont, object args) { + return_closcall1(data, cont, memqp(car(args), cadr(args)));} +void _char_91_125integer(void *data, object cont, object args) { Cyc_check_num_args("char->integer", 1, args); { integer_type i = Cyc_char2integer(car(args)); - return_closcall1(cont, &i);}} -void _integer_91_125char(object cont, object args) { + return_closcall1(data, cont, &i);}} +void _integer_91_125char(void *data, object cont, object args) { Cyc_check_num_args("integer->char", 1, args); - return_closcall1(cont, Cyc_integer2char(car(args)));} -void _string_91_125number(object cont, object args) { + return_closcall1(data, cont, Cyc_integer2char(car(args)));} +void _string_91_125number(void *data, object cont, object args) { Cyc_check_num_args("string->number", 1, args); { common_type i = Cyc_string2number(car(args)); - return_closcall1(cont, &i);}} -void _string_91length(object cont, object args) { + return_closcall1(data, cont, &i);}} +void _string_91length(void *data, object cont, object args) { Cyc_check_num_args("string-length", 1, args); { integer_type i = Cyc_string_length(car(args)); - return_closcall1(cont, &i);}} -void _cyc_substring(object cont, object args) { + return_closcall1(data, cont, &i);}} +void _cyc_substring(void *data, object cont, object args) { Cyc_check_num_args("substring", 3, args); - Cyc_substring(cont, car(args), cadr(args), caddr(args));} -void _cyc_string_91set_67(object cont, object args) { + Cyc_substring(data, cont, car(args), cadr(args), caddr(args));} +void _cyc_string_91set_67(void *data, object cont, object args) { Cyc_check_num_args("string-set!", 3, args); { object s = Cyc_string_set(car(args), cadr(args), caddr(args)); - return_closcall1(cont, s); }} -void _cyc_string_91ref(object cont, object args) { + return_closcall1(data, cont, s); }} +void _cyc_string_91ref(void *data, object cont, object args) { Cyc_check_num_args("string-ref", 2, args); { object c = Cyc_string_ref(car(args), cadr(args)); - return_closcall1(cont, c); }} -void _Cyc_91installation_91dir(object cont, object args) { + return_closcall1(data, cont, c); }} +void _Cyc_91installation_91dir(void *data, object cont, object args) { Cyc_check_num_args("Cyc-installation-dir", 1, args); - Cyc_installation_dir(cont, car(args));} -void _command_91line_91arguments(object cont, object args) { + Cyc_installation_dir(data, cont, car(args));} +void _command_91line_91arguments(void *data, object cont, object args) { object cmdline = Cyc_command_line_arguments(cont); - return_closcall1(cont, cmdline); } -void _cyc_system(object cont, object args) { + return_closcall1(data, cont, cmdline); } +void _cyc_system(void *data, object cont, object args) { Cyc_check_num_args("system", 1, args); { integer_type i = Cyc_system(car(args)); - return_closcall1(cont, &i);}} -//void _error(object cont, object args) { + return_closcall1(data, cont, &i);}} +//void _error(void *data, object cont, object args) { // integer_type argc = Cyc_length(args); -// dispatch_va(argc.value, dispatch_error, cont, cont, args); } -void _Cyc_91current_91exception_91handler(object cont, object args) { +// dispatch_va(data, argc.value, dispatch_error, cont, cont, args); } +void _Cyc_91current_91exception_91handler(void *data, object cont, object args) { object handler = Cyc_current_exception_handler(); - return_closcall1(cont, handler); } -void _Cyc_91default_91exception_91handler(object cont, object args) { + return_closcall1(data, cont, handler); } +void _Cyc_91default_91exception_91handler(void *data, object cont, object args) { // TODO: this is a quick-and-dirty implementation, may be a better way to write this - Cyc_default_exception_handler(1, args, car(args)); + Cyc_default_exception_handler(data, 1, args, car(args)); } -void _string_91cmp(object cont, object args) { +void _string_91cmp(void *data, object cont, object args) { Cyc_check_num_args("string-cmp", 2, args); { integer_type cmp = Cyc_string_cmp(car(args), cadr(args)); - return_closcall1(cont, &cmp);}} -void _string_91append(object cont, object args) { + return_closcall1(data, cont, &cmp);}} +void _string_91append(void *data, object cont, object args) { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_string_91append, cont, cont, args); } -void _make_91vector(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_string_91append, cont, cont, args); } +void _make_91vector(void *data, object cont, object args) { Cyc_check_num_args("make-vector", 1, args); { integer_type argc = Cyc_length(args); if (argc.value >= 2) { - Cyc_make_vector(cont, car(args), cadr(args));} + Cyc_make_vector(data, cont, car(args), cadr(args));} else { - Cyc_make_vector(cont, car(args), boolean_f);}}} -void _vector_91ref(object cont, object args) { + Cyc_make_vector(data, cont, car(args), boolean_f);}}} +void _vector_91ref(void *data, object cont, object args) { Cyc_check_num_args("vector-ref", 2, args); { object ref = Cyc_vector_ref(car(args), cadr(args)); - return_closcall1(cont, ref);}} -void _vector_91set_67(object cont, object args) { + return_closcall1(data, cont, ref);}} +void _vector_91set_67(void *data, object cont, object args) { Cyc_check_num_args("vector-set!", 3, args); { object ref = Cyc_vector_set(car(args), cadr(args), caddr(args)); - return_closcall1(cont, ref);}} -void _list_91_125vector(object cont, object args) { + return_closcall1(data, cont, ref);}} +void _list_91_125vector(void *data, object cont, object args) { Cyc_check_num_args("list->vector", 1, args); - Cyc_list2vector(cont, car(args));} -void _list_91_125string(object cont, object args) { + Cyc_list2vector(data, cont, car(args));} +void _list_91_125string(void *data, object cont, object args) { Cyc_check_num_args("list->string", 1, args); - Cyc_list2string(cont, car(args));} -void _string_91_125symbol(object cont, object args) { + Cyc_list2string(data, cont, car(args));} +void _string_91_125symbol(void *data, object cont, object args) { Cyc_check_num_args("string->symbol", 1, args); - return_closcall1(cont, Cyc_string2symbol(car(args)));} -void _symbol_91_125string(object cont, object args) { + return_closcall1(data, cont, Cyc_string2symbol(car(args)));} +void _symbol_91_125string(void *data, object cont, object args) { Cyc_check_num_args("symbol->string", 1, args); - Cyc_symbol2string(cont, car(args));} -void _number_91_125string(object cont, object args) { + Cyc_symbol2string(data, cont, car(args));} +void _number_91_125string(void *data, object cont, object args) { Cyc_check_num_args("number->string", 1, args); - Cyc_number2string(cont, car(args));} -void _open_91input_91file(object cont, object args) { + Cyc_number2string(data, cont, car(args));} +void _open_91input_91file(void *data, object cont, object args) { Cyc_check_num_args("open-input-file", 1, args); { port_type p = Cyc_io_open_input_file(car(args)); - return_closcall1(cont, &p);}} -void _open_91output_91file(object cont, object args) { + return_closcall1(data, cont, &p);}} +void _open_91output_91file(void *data, object cont, object args) { Cyc_check_num_args("open-output-file", 1, args); { port_type p = Cyc_io_open_output_file(car(args)); - return_closcall1(cont, &p);}} -void _close_91port(object cont, object args) { + return_closcall1(data, cont, &p);}} +void _close_91port(void *data, object cont, object args) { Cyc_check_num_args("close-port", 1, args); - return_closcall1(cont, Cyc_io_close_port(car(args)));} -void _close_91input_91port(object cont, object args) { + return_closcall1(data, cont, Cyc_io_close_port(car(args)));} +void _close_91input_91port(void *data, object cont, object args) { Cyc_check_num_args("close-input-port", 1, args); - return_closcall1(cont, Cyc_io_close_input_port(car(args)));} -void _close_91output_91port(object cont, object args) { + return_closcall1(data, cont, Cyc_io_close_input_port(car(args)));} +void _close_91output_91port(void *data, object cont, object args) { Cyc_check_num_args("close-output-port", 1, args); - return_closcall1(cont, Cyc_io_close_output_port(car(args)));} -void _Cyc_91flush_91output_91port(object cont, object args) { + return_closcall1(data, cont, Cyc_io_close_output_port(car(args)));} +void _Cyc_91flush_91output_91port(void *data, object cont, object args) { Cyc_check_num_args("Cyc-flush-output-port", 1, args); - return_closcall1(cont, Cyc_io_flush_output_port(car(args)));} -void _file_91exists_127(object cont, object args) { + return_closcall1(data, cont, Cyc_io_flush_output_port(car(args)));} +void _file_91exists_127(void *data, object cont, object args) { Cyc_check_num_args("file-exists?", 1, args); - return_closcall1(cont, Cyc_io_file_exists(car(args)));} -void _delete_91file(object cont, object args) { + return_closcall1(data, cont, Cyc_io_file_exists(car(args)));} +void _delete_91file(void *data, object cont, object args) { Cyc_check_num_args("delete-file", 1, args); - return_closcall1(cont, Cyc_io_delete_file(car(args)));} -void _read_91char(object cont, object args) { + return_closcall1(data, cont, Cyc_io_delete_file(car(args)));} +void _read_91char(void *data, object cont, object args) { Cyc_check_num_args("read-char", 1, args); - return_closcall1(cont, Cyc_io_read_char(car(args)));} -void _peek_91char(object cont, object args) { + return_closcall1(data, cont, Cyc_io_read_char(car(args)));} +void _peek_91char(void *data, object cont, object args) { Cyc_check_num_args("peek-char", 1, args); - return_closcall1(cont, Cyc_io_peek_char(car(args)));} -void _Cyc_91read_91line(object cont, object args) { + return_closcall1(data, cont, Cyc_io_peek_char(car(args)));} +void _Cyc_91read_91line(void *data, object cont, object args) { Cyc_check_num_args("Cyc-read-line", 1, args); - Cyc_io_read_line(cont, car(args));} -void _Cyc_91write_91char(object cont, object args) { + Cyc_io_read_line(data, cont, car(args));} +void _Cyc_91write_91char(void *data, object cont, object args) { Cyc_check_num_args("write-char", 2, args); - return_closcall1(cont, Cyc_write_char(data, car(args), cadr(args)));} -void _Cyc_91write(object cont, object args) { + return_closcall1(data, cont, Cyc_write_char(data, car(args), cadr(args)));} +void _Cyc_91write(void *data, object cont, object args) { Cyc_check_num_args("write", 1, args); { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_write_va, cont, cont, args); }} -void _display(object cont, object args) { + dispatch(data, argc.value, (function_type)dispatch_write_va, cont, cont, args); }} +void _display(void *data, object cont, object args) { Cyc_check_num_args("display", 1, args); { integer_type argc = Cyc_length(args); - dispatch(argc.value, (function_type)dispatch_display_va, cont, cont, args); }} -void _call_95cc(object cont, object args){ + dispatch(data, argc.value, (function_type)dispatch_display_va, cont, cont, args); }} +void _call_95cc(void *data, object cont, object args){ Cyc_check_num_args("call/cc", 1, args); Cyc_check_fnc(car(args)); - return_closcall2(__glo_call_95cc, cont, car(args)); + return_closcall2(data, __glo_call_95cc, cont, car(args)); } /* @@ -1846,14 +1844,14 @@ void _call_95cc(object cont, object args){ * @param func - Function to execute * @param args - A list of arguments to the function */ -object apply(object cont, object func, object args){ +object apply(void *data, object cont, object func, object args){ common_type buf; //printf("DEBUG apply: "); //Cyc_display(args); //printf("\n"); if (!is_object_type(func)) { - Cyc_rt_raise2("Call of non-procedure: ", func); + Cyc_rt_raise2(data, "Call of non-procedure: ", func); } // Causes problems... @@ -1862,7 +1860,7 @@ object apply(object cont, object func, object args){ switch(type_of(func)) { case primitive_tag: // TODO: should probably check arg counts and error out if needed - ((primitive_type *)func)->fn(cont, args); + ((primitive_type *)func)->fn(data, cont, args); break; case macro_tag: case closure0_tag: @@ -1871,10 +1869,10 @@ object apply(object cont, object func, object args){ case closure3_tag: case closure4_tag: case closureN_tag: - buf.integer_t = Cyc_length(args); + buf.integer_t = Cyc_length(data, args); // TODO: validate number of args provided: Cyc_check_num_args("", ((closure)func)->num_args, args); // TODO: could be more efficient, eg: cyc_length(args) is called twice. - dispatch(buf.integer_t.value, ((closure)func)->fn, func, cont, args); + dispatch(data, buf.integer_t.value, ((closure)func)->fn, func, cont, args); break; case cons_tag: @@ -1883,25 +1881,25 @@ object apply(object cont, object func, object args){ object fobj = car(func); if (!is_object_type(fobj) || type_of(fobj) != symbol_tag) { - Cyc_rt_raise2("Call of non-procedure: ", func); + Cyc_rt_raise2(data, "Call of non-procedure: ", func); } else if (strncmp(((symbol)fobj)->pname, "lambda", 7) == 0) { make_cons(c, func, args); //printf("JAE DEBUG, sending to eval: "); //Cyc_display(&c, stderr); - ((closure)__glo_eval)->fn(2, __glo_eval, cont, &c, nil); + ((closure)__glo_eval)->fn(data, 2, __glo_eval, cont, &c, nil); // TODO: would be better to compare directly against symbols here, // but need a way of looking them up ahead of time. // maybe a libinit() or such is required. } else if (strncmp(((symbol)fobj)->pname, "primitive", 10) == 0) { make_cons(c, cadr(func), args); - ((closure)__glo_eval)->fn(3, __glo_eval, cont, &c, nil); + ((closure)__glo_eval)->fn(data, 3, __glo_eval, cont, &c, nil); } else if (strncmp(((symbol)fobj)->pname, "procedure", 10) == 0) { make_cons(c, func, args); - ((closure)__glo_eval)->fn(3, __glo_eval, cont, &c, nil); + ((closure)__glo_eval)->fn(data, 3, __glo_eval, cont, &c, nil); } else { make_cons(c, func, args); - Cyc_rt_raise2("Unable to evaluate: ", &c); + Cyc_rt_raise2(data, "Unable to evaluate: ", &c); } } @@ -1913,7 +1911,7 @@ object apply(object cont, object func, object args){ } // Version of apply meant to be called from within compiled code -void Cyc_apply(int argc, closure cont, object prim, ...){ +void Cyc_apply(void *data, int argc, closure cont, object prim, ...){ va_list ap; object tmp; int i; @@ -1933,12 +1931,12 @@ void Cyc_apply(int argc, closure cont, object prim, ...){ //printf("\n"); va_end(ap); - apply(cont, prim, (object)&args[0]); + apply(data, cont, prim, (object)&args[0]); } // END apply /* Extract args from given array, assuming cont is the first arg in buf */ -void Cyc_apply_from_buf(int argc, object prim, object *buf) { +void Cyc_apply_from_buf(data, int argc, object prim, object *buf) { list args; object cont; int i; @@ -1958,7 +1956,7 @@ void Cyc_apply_from_buf(int argc, object prim, object *buf) { args[i - 1].cons_cdr = (i == (argc-1)) ? nil : &args[i]; } - apply(cont, prim, (object)&args[0]); + apply(data, cont, prim, (object)&args[0]); } ///** @@ -2744,9 +2742,10 @@ void GC(cont, args, num_args) closure cont; object *args; int num_args; } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG - longjmp(jmp_main,1); // Return globals gc_cont, gc_ans + longjmp(jmp_main, &data); // Return globals gc_cont, gc_ans } + /* Overall GC notes: note fwd pointers are only ever placed on the stack, never the heap @@ -2838,7 +2837,7 @@ to handle this detail yet. and it is very important to get right /** * Receive a list of arguments and apply them to the given function */ -void dispatch(int argc, function_type func, object clo, object cont, object args) { +void dispatch(void *data, int argc, function_type func, object clo, object cont, object args) { object b[argc + 1]; // OK to do this? Is this portable? int i; @@ -2849,13 +2848,13 @@ void dispatch(int argc, function_type func, object clo, object cont, object args args = cdr(args); } - do_dispatch(argc, func, clo, b); + do_dispatch(data, argc, func, clo, b); } /** * Same as above but for a varargs C function */ -void dispatch_va(int argc, function_type_va func, object clo, object cont, object args) { +void dispatch_va(void *data, int argc, function_type_va func, object clo, object cont, object args) { object b[argc + 1]; // OK to do this? Is this portable? int i; @@ -2866,7 +2865,7 @@ void dispatch_va(int argc, function_type_va func, object clo, object cont, objec args = cdr(args); } - do_dispatch(argc, (function_type)func, clo, b); + do_dispatch(data, argc, (function_type)func, clo, b); } static primitive_type Cyc_91global_91vars_primitive = {{0}, primitive_tag, "Cyc-global-vars", &_Cyc_91global_91vars}; From e1c308d2b19814c5dc9ddc647ee16a3f4588128a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 2 Nov 2015 22:47:55 -0500 Subject: [PATCH 094/339] Adding data argument --- include/cyclone/runtime.h | 114 +++++++++++++-------------- runtime.c | 158 +++++++++++++++++++------------------- 2 files changed, 136 insertions(+), 136 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index d692930d..ceef8fa7 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -90,68 +90,67 @@ object Cyc_get_cvar(object var); object Cyc_set_cvar(object var, object value); object apply(void *data, object cont, object func, object args); void Cyc_apply(void *data, int argc, closure cont, object prim, ...); -integer_type Cyc_string_cmp(object str1, object str2); -void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); +integer_type Cyc_string_cmp(void *data, object str1, object str2); +void dispatch_string_91append(void *data, int argc, object clo, object cont, object str1, ...); list mcons(object,object); cvar_type *mcvar(object *var); object Cyc_display(object, FILE *port); -object dispatch_display_va(int argc, object clo, object cont, object x, ...); +object dispatch_display_va(void *data, int argc, object clo, object cont, object x, ...); object Cyc_display_va(int argc, object x, ...); object Cyc_display_va_list(int argc, object x, va_list ap); -object Cyc_write_char(object c, object port); +object Cyc_write_char(void *data, object c, object port); object Cyc_write(object, FILE *port); -object dispatch_write_va(int argc, object clo, object cont, object x, ...); +object dispatch_write_va(void *data, int argc, object clo, object cont, object x, ...); object Cyc_write_va(int argc, object x, ...); object Cyc_write_va_list(int argc, object x, va_list ap); object Cyc_has_cycle(object lst); -list assoc(object x, list l); -object __num_eq(object x, object y); -object __num_gt(object x, object y); -object __num_lt(object x, object y); -object __num_gte(object x, object y); -object __num_lte(object x, object y); +object __num_eq(void *, object x, object y); +object __num_gt(void *, object x, object y); +object __num_lt(void *, object x, object y); +object __num_gte(void *, object x, object y); +object __num_lte(void *, object x, object y); object Cyc_eq(object x, object y); -object Cyc_set_car(object l, object val) ; -object Cyc_set_cdr(object l, object val) ; -integer_type Cyc_length(object l); -integer_type Cyc_vector_length(object v); -object Cyc_vector_ref(object v, object k); -object Cyc_vector_set(object v, object k, object obj); -object Cyc_make_vector(object cont, object len, object fill); -object Cyc_list2vector(object cont, object l); -object Cyc_number2string(object cont, object n); -object Cyc_symbol2string(object cont, object sym) ; -object Cyc_string2symbol(object str); -object Cyc_list2string(object cont, object lst); -common_type Cyc_string2number(object str); +object Cyc_set_car(void *, object l, object val) ; +object Cyc_set_cdr(void *, object l, object val) ; +integer_type Cyc_length(void *d, object l); +integer_type Cyc_vector_length(void *data, object v); +object Cyc_vector_ref(void *d, object v, object k); +object Cyc_vector_set(void *d, object v, object k, object obj); +object Cyc_make_vector(void *data, object cont, object len, object fill); +object Cyc_list2vector(void *data, object cont, object l); +object Cyc_number2string(void *d, object cont, object n); +object Cyc_symbol2string(void *d, object cont, object sym) ; +object Cyc_string2symbol(void *d, object str); +object Cyc_list2string(void *d, object cont, object lst); +common_type Cyc_string2number(void *d, object str); void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); -object Cyc_string_append(object cont, int argc, object str1, ...); -integer_type Cyc_string_length(object str); -object Cyc_substring(object cont, object str, object start, object end); -object Cyc_string_ref(object str, object k); -object Cyc_string_set(object str, object k, object chr); -object Cyc_installation_dir(object cont, object type); -object Cyc_command_line_arguments(object cont); +object Cyc_string_append(void *data, object cont, int argc, object str1, ...); +integer_type Cyc_string_length(void *data, object str); +object Cyc_substring(void *data, object cont, object str, object start, object end); +object Cyc_string_ref(void *data, object str, object k); +object Cyc_string_set(void *data, object str, object k, object chr); +object Cyc_installation_dir(void *data, object cont, object type); +object Cyc_command_line_arguments(void *data, object cont); integer_type Cyc_system(object cmd); integer_type Cyc_char2integer(object chr); -object Cyc_integer2char(object n); +object Cyc_integer2char(void *data, object n); void Cyc_halt(closure); object __halt(object obj); port_type Cyc_stdout(void); port_type Cyc_stdin(void); port_type Cyc_stderr(void); -port_type Cyc_io_open_input_file(object str); -port_type Cyc_io_open_output_file(object str); -object Cyc_io_close_port(object port); -object Cyc_io_close_input_port(object port); -object Cyc_io_close_output_port(object port); -object Cyc_io_flush_output_port(object port); -object Cyc_io_delete_file(object filename); -object Cyc_io_file_exists(object filename); -object Cyc_io_read_char(object port); -object Cyc_io_peek_char(object port); -object Cyc_io_read_line(object cont, object port); +port_type Cyc_io_open_input_file(void *data, object str); +port_type Cyc_io_open_output_file(void *data, object str); +object Cyc_io_close_port(void *data, object port); +object Cyc_io_close_input_port(void *data, object port); +object Cyc_io_close_output_port(void *data, object port); +object Cyc_io_flush_output_port(void *data, object port); +object Cyc_io_delete_file(void *data, object filename); +object Cyc_io_file_exists(void *data, object filename); +object Cyc_io_read_char(void *data, object port); +object Cyc_io_peek_char(void *data, object port); +object Cyc_io_read_line(void *data, object cont, object port); object Cyc_is_boolean(object o); object Cyc_is_cons(object o); @@ -164,27 +163,28 @@ object Cyc_is_port(object o); object Cyc_is_symbol(object o); object Cyc_is_string(object o); object Cyc_is_char(object o); -object Cyc_is_procedure(object o); +object Cyc_is_procedure(void *data, object o); object Cyc_is_macro(object o); object Cyc_is_eof_object(object o); object Cyc_is_cvar(object o); -common_type Cyc_sum_op(object x, object y); -common_type Cyc_sub_op(object x, object y); -common_type Cyc_mul_op(object x, object y); -common_type Cyc_div_op(object x, object y); -common_type Cyc_sum(int argc, object n, ...); -common_type Cyc_sub(int argc, object n, ...); -common_type Cyc_mul(int argc, object n, ...); -common_type Cyc_div(int argc, object n, ...); -common_type Cyc_num_op_va_list(int argc, common_type (fn_op(object, object)), object n, va_list ns); +common_type Cyc_sum_op(void *data, object x, object y); +common_type Cyc_sub_op(void *data, object x, object y); +common_type Cyc_mul_op(void *data, object x, object y); +common_type Cyc_div_op(void *data, object x, object y); +common_type Cyc_sum(void *data, int argc, object n, ...); +common_type Cyc_sub(void *data, int argc, object n, ...); +common_type Cyc_mul(void *data, int argc, object n, ...); +common_type Cyc_div(void *data, int argc, object n, ...); +common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(object, object)), object n, va_list ns); int equal(object,object); -list assq(object,list); +list assq(void *,object,list); +list assoc(void *,object x, list l); object get(object,object); object equalp(object,object); -object memberp(object,list); -object memqp(object,list); +object memberp(void *,object,list); +object memqp(void *,object,list); char *transport(char *,int); -void GC(closure,object*,int); +void GC(void *,closure,object*,int); void Cyc_st_init(); void Cyc_st_add(char *frame); diff --git a/runtime.c b/runtime.c index f1323b58..b1ef0c78 100644 --- a/runtime.c +++ b/runtime.c @@ -596,13 +596,13 @@ object Cyc_write_char(void *data, object c, object port) } // TODO: should not be a predicate, may end up moving these to Scheme code -object memberp(x,l) object x; list l; -{Cyc_check_cons_or_nil(l); +object memberp(void *data, object x, list l); +{Cyc_check_cons_or_nil(data, l); for (; !nullp(l); l = cdr(l)) if (boolean_f != equalp(x,car(l))) return boolean_t; return boolean_f;} -object memqp(x,l) object x; list l; -{Cyc_check_cons_or_nil(l); +object memqp(void *data, object x, list l) +{Cyc_check_cons_or_nil(data, l); for (; !nullp(l); l = cdr(l)) if (eq(x,car(l))) return boolean_t; return boolean_f;} @@ -624,55 +624,55 @@ object equalp(x,y) object x,y; type_of(x)!=cons_tag || type_of(y)!=cons_tag) return boolean_f; if (boolean_f == equalp(car(x),car(y))) return boolean_f;}} -list assq(x,l) object x; list l; +list assq(void *data, object x, list l) {if (nullp(l) || is_value_type(l) || type_of(l) != cons_tag) return boolean_f; for (; !nullp(l); l = cdr(l)) {register list la = car(l); - Cyc_check_cons(la); + Cyc_check_cons(data, la); if (eq(x,car(la))) return la;} return boolean_f;} -list assoc(x,l) object x; list l; +list assoc(void *data, object x, list l) {if (nullp(l) || is_value_type(l) || type_of(l) != cons_tag) return boolean_f; for (; !nullp(l); l = cdr(l)) {register list la = car(l); - Cyc_check_cons(la); + Cyc_check_cons(data, la); if (boolean_f != equalp(x,car(la))) return la;} return boolean_f;} // TODO: generate these using macros??? -object __num_eq(x, y) object x, y; -{Cyc_check_num(x); - Cyc_check_num(y); +object __num_eq(void *data, object x, object y) +{Cyc_check_num(data, x); + Cyc_check_num(data, y); if (((integer_type *)x)->value == ((integer_type *)y)->value) return boolean_t; return boolean_f;} -object __num_gt(x, y) object x, y; -{Cyc_check_num(x); - Cyc_check_num(y); +object __num_gt(void *data, object x, object y) +{Cyc_check_num(data, x); + Cyc_check_num(data, y); if (((integer_type *)x)->value > ((integer_type *)y)->value) return boolean_t; return boolean_f;} -object __num_lt(x, y) object x, y; -{Cyc_check_num(x); - Cyc_check_num(y); +object __num_lt(void *data, object x, object y) +{Cyc_check_num(data, x); + Cyc_check_num(data, y); if (((integer_type *)x)->value < ((integer_type *)y)->value) return boolean_t; return boolean_f;} -object __num_gte(x, y) object x, y; -{Cyc_check_num(x); - Cyc_check_num(y); +object __num_gte(void *data, object x, object y) +{Cyc_check_num(data, x); + Cyc_check_num(data, y); if (((integer_type *)x)->value >= ((integer_type *)y)->value) return boolean_t; return boolean_f;} -object __num_lte(x, y) object x, y; -{Cyc_check_num(x); - Cyc_check_num(y); +object __num_lte(void *data, object x, object y) +{Cyc_check_num(data, x); + Cyc_check_num(data, y); if (((integer_type *)x)->value <= ((integer_type *)y)->value) return boolean_t; return boolean_f;} @@ -735,7 +735,7 @@ object Cyc_is_char(object o){ return boolean_t; return boolean_f;} -object Cyc_is_procedure(object o) { +object Cyc_is_procedure(void *data, object o) { int tag; if (!nullp(o) && !is_value_type(o)) { tag = type_of(o); @@ -748,7 +748,7 @@ object Cyc_is_procedure(object o) { tag == primitive_tag) { return boolean_t; } else if (tag == cons_tag) { - integer_type l = Cyc_length(o); + integer_type l = Cyc_length(data, o); if (l.value > 0 && Cyc_is_symbol(car(o)) == boolean_t) { if (strncmp(((symbol)car(o))->pname, "primitive", 10) == 0 || strncmp(((symbol)car(o))->pname, "procedure", 10) == 0 ) { @@ -787,15 +787,15 @@ object Cyc_eq(object x, object y) { return boolean_f; } -object Cyc_set_car(object l, object val) { - if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(cons_tag, l); +object Cyc_set_car(void *data, object l, object val) { + if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); car(l) = val; add_mutation(l, val); return l; } -object Cyc_set_cdr(object l, object val) { - if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(cons_tag, l); +object Cyc_set_cdr(void *data, object l, object val) { + if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); cdr(l) = val; add_mutation(l, val); return l; @@ -803,8 +803,8 @@ object Cyc_set_cdr(object l, object val) { object Cyc_vector_set(void *data, object v, object k, object obj) { int idx; - Cyc_check_vec(v); - Cyc_check_int(k); + Cyc_check_vec(data, v); + Cyc_check_int(data, k); idx = ((integer_type *)k)->value; if (idx < 0 || idx >= ((vector)v)->num_elt) { @@ -853,7 +853,7 @@ integer_type Cyc_length(void *data, object l){ object Cyc_number2string(void *data, object cont, object n) { char buffer[1024]; - Cyc_check_num(n); + Cyc_check_num(data, n); if (type_of(n) == integer_tag) { snprintf(buffer, 1024, "%d", ((integer_type *)n)->value); } else if (type_of(n) == double_tag) { @@ -867,14 +867,14 @@ object Cyc_number2string(void *data, object cont, object n) { } object Cyc_symbol2string(void *data, object cont, object sym) { - Cyc_check_sym(sym); + Cyc_check_sym(data, sym); { const char *pname = symbol_pname(sym); make_string(str, pname); return_closcall1(data, cont, &str); }} -object Cyc_string2symbol(object str) { +object Cyc_string2symbol(void *data, object str) { object sym; - Cyc_check_str(str); + Cyc_check_str(data, str); sym = find_symbol_by_name(string_str(str)); if (!sym) { sym = add_symbol_by_name(string_str(str)); @@ -887,7 +887,7 @@ object Cyc_list2string(void *data, object cont, object lst){ int i = 0; integer_type len; - Cyc_check_cons_or_nil(lst); + Cyc_check_cons_or_nil(data, lst); len = Cyc_length(data, lst); // Inefficient, walks whole list buf = alloca(sizeof(char) * (len.value + 1)); @@ -902,11 +902,11 @@ object Cyc_list2string(void *data, object cont, object lst){ return_closcall1(data, cont, &str);} } -common_type Cyc_string2number(object str){ +common_type Cyc_string2number(void *data, object str){ common_type result; double n; - Cyc_check_obj(string_tag, str); - Cyc_check_str(str); + Cyc_check_obj(data, string_tag, str); + Cyc_check_str(data, str); if (type_of(str) == string_tag && ((string_type *) str)->str){ n = atof(((string_type *) str)->str); @@ -927,9 +927,9 @@ common_type Cyc_string2number(object str){ return result; } -integer_type Cyc_string_cmp(object str1, object str2) { - Cyc_check_str(str1); - Cyc_check_str(str2); +integer_type Cyc_string_cmp(void *data, object str1, object str2) { + Cyc_check_str(data, str1); + Cyc_check_str(data, str2); { make_int(cmp, strcmp(((string_type *)str1)->str, ((string_type *)str2)->str)); @@ -943,14 +943,14 @@ integer_type Cyc_string_cmp(object str1, object str2) { char *buffer, *bufferp, **str = alloca(sizeof(char *) * argc); \ object tmp; \ if (argc > 0) { \ - Cyc_check_str(str1); \ + Cyc_check_str(data, str1); \ str[i] = ((string_type *)str1)->str; \ len[i] = strlen(str[i]); \ total_len += len[i]; \ } \ for (i = 1; i < argc; i++) { \ tmp = va_arg(ap, object); \ - Cyc_check_str(tmp); \ + Cyc_check_str(data, tmp); \ str[i] = ((string_type *)tmp)->str; \ len[i] = strlen(str[i]); \ total_len += len[i]; \ @@ -978,9 +978,9 @@ object Cyc_string_append(void *data, object cont, int _argc, object str1, ...) { Cyc_string_append_va_list(data, _argc); } -integer_type Cyc_string_length(object str) { - Cyc_check_obj(string_tag, str); - Cyc_check_str(str); +integer_type Cyc_string_length(void *data, object str) { + Cyc_check_obj(data, string_tag, str); + Cyc_check_str(data, str); { make_int(len, strlen(string_str(str))); return len; }} @@ -988,8 +988,8 @@ object Cyc_string_set(void *data, object str, object k, object chr) { char *raw; int idx, len; - Cyc_check_str(str); - Cyc_check_int(k); + Cyc_check_str(data, str); + Cyc_check_int(data, k); if (!eq(boolean_t, Cyc_is_char(chr))) { Cyc_rt_raise2(data, "Expected char but received", chr); @@ -999,7 +999,7 @@ object Cyc_string_set(void *data, object str, object k, object chr) { idx = integer_value(k), len = strlen(raw); - Cyc_check_bounds("string-set!", len, idx); + Cyc_check_bounds(data, "string-set!", len, idx); raw[idx] = obj_obj2char(chr); return str; } @@ -1008,8 +1008,8 @@ object Cyc_string_ref(void *data, object str, object k) { const char *raw; int idx, len; - Cyc_check_str(str); - Cyc_check_int(k); + Cyc_check_str(data, str); + Cyc_check_int(data, k); raw = string_str(str); idx = integer_value(k), @@ -1026,9 +1026,9 @@ object Cyc_substring(void *data, object cont, object str, object start, object e const char *raw; int s, e, len; - Cyc_check_str(str); - Cyc_check_int(start); - Cyc_check_int(end); + Cyc_check_str(data, str); + Cyc_check_int(data, start); + Cyc_check_int(data, end); raw = string_str(str); s = integer_value(start), @@ -1109,7 +1109,7 @@ object Cyc_command_line_arguments(void *data, object cont) { object Cyc_make_vector(void *data, object cont, object len, object fill) { object v = nil; int i; - Cyc_check_int(len); + Cyc_check_int(data, len); v = alloca(sizeof(vector_type)); ((vector)v)->hdr.mark = gc_color_red; ((vector)v)->tag = vector_tag; @@ -1130,8 +1130,8 @@ object Cyc_list2vector(void *data, object cont, object l) { object lst = l; int i = 0; - Cyc_check_cons_or_nil(l); - len = Cyc_length(l); + Cyc_check_cons_or_nil(data, l); + len = Cyc_length(data, l); v = alloca(sizeof(vector_type)); ((vector)v)->hdr.mark = gc_color_red; ((vector)v)->tag = vector_tag; @@ -1162,10 +1162,10 @@ integer_type Cyc_char2integer(object chr){ return n; } -object Cyc_integer2char(object n){ +object Cyc_integer2char(void *data, object n){ int val = 0; - Cyc_check_int(n); + Cyc_check_int(data, n); if (!nullp(n)) { val = ((integer_type *) n)->value; } @@ -1300,7 +1300,7 @@ port_type Cyc_stderr() { port_type Cyc_io_open_input_file(void *data, object str) { const char *fname; - Cyc_check_str(str); + Cyc_check_str(data, str); fname = ((string_type *)str)->str; make_port(p, NULL, 1); p.fp = fopen(fname, "r"); @@ -1310,7 +1310,7 @@ port_type Cyc_io_open_input_file(void *data, object str) { port_type Cyc_io_open_output_file(void *data, object str) { const char *fname; - Cyc_check_str(str); + Cyc_check_str(data, str); fname = ((string_type *)str)->str; make_port(p, NULL, 0); p.fp = fopen(fname, "w"); @@ -1318,14 +1318,14 @@ port_type Cyc_io_open_output_file(void *data, object str) { return p; } -object Cyc_io_close_input_port(object port) { - return Cyc_io_close_port(port); } +object Cyc_io_close_input_port(void *data, object port) { + return Cyc_io_close_port(data, port); } -object Cyc_io_close_output_port(object port) { - return Cyc_io_close_port(port); } +object Cyc_io_close_output_port(void *data, object port) { + return Cyc_io_close_port(data, port); } -object Cyc_io_close_port(object port) { - Cyc_check_port(port); +object Cyc_io_close_port(void *data, object port) { + Cyc_check_port(data, port); { FILE *stream = ((port_type *)port)->fp; if (stream) fclose(stream); @@ -1334,8 +1334,8 @@ object Cyc_io_close_port(object port) { return port; } -object Cyc_io_flush_output_port(object port) { - Cyc_check_port(port); +object Cyc_io_flush_output_port(void *data, object port) { + Cyc_check_port(data, port); { FILE *stream = ((port_type *)port)->fp; if (stream) { @@ -1346,18 +1346,18 @@ object Cyc_io_flush_output_port(object port) { return port; } -object Cyc_io_delete_file(object filename) { +object Cyc_io_delete_file(void *data, object filename) { const char *fname; - Cyc_check_str(filename); + Cyc_check_str(data, filename); fname = ((string_type *)filename)->str; if (remove(fname) == 0) return boolean_t; // Success return boolean_f; } -object Cyc_io_file_exists(object filename) { +object Cyc_io_file_exists(void *data, object filename) { const char *fname; - Cyc_check_str(filename); + Cyc_check_str(data, filename); fname = ((string_type *)filename)->str; FILE *file; // Possibly overkill, but portable @@ -1369,8 +1369,8 @@ object Cyc_io_file_exists(object filename) { } // TODO: port arg is optional! (maybe handle that in expansion section??) -object Cyc_io_read_char(object port) { - Cyc_check_port(port); +object Cyc_io_read_char(void *data, object port) { + Cyc_check_port(data, port); { int c = fgetc(((port_type *) port)->fp); if (c != EOF) { @@ -1403,11 +1403,11 @@ object Cyc_io_read_line(void *data, object cont, object port) { return nil; } -object Cyc_io_peek_char(object port) { +object Cyc_io_peek_char(void *data, object port) { FILE *stream; int c; - Cyc_check_port(port); + Cyc_check_port(data, port); { stream = ((port_type *) port)->fp; c = fgetc(stream); @@ -2596,7 +2596,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } \ } -void GC(cont, args, num_args) closure cont; object *args; int num_args; +void GC(void *data, closure cont, object *args, int num_args) { char tmp; object temp; From 4838dfb40f455afa98107088d3276102bccc363a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 3 Nov 2015 22:58:34 -0500 Subject: [PATCH 095/339] Fixed compilation errors for libcyclone.a --- include/cyclone/runtime.h | 4 +- runtime.c | 366 +++++++++++++++++++------------------- 2 files changed, 185 insertions(+), 185 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index ceef8fa7..b531e1d4 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -30,7 +30,6 @@ #define Cyc_check_sym(d,obj) Cyc_check_type(d,Cyc_is_symbol, symbol_tag, obj); #define Cyc_check_vec(d,obj) Cyc_check_type(d,Cyc_is_vector, vector_tag, obj); #define Cyc_check_port(d,obj) Cyc_check_type(d,Cyc_is_port, port_tag, obj); -#define Cyc_check_fnc(d,obj) Cyc_check_type(d,Cyc_is_procedure, closure2_tag, obj); void Cyc_invalid_type_error(void *data, int tag, object found); void Cyc_check_obj(void *data, int tag, object obj); void Cyc_check_bounds(void *data, const char *label, int len, int index); @@ -124,7 +123,6 @@ object Cyc_symbol2string(void *d, object cont, object sym) ; object Cyc_string2symbol(void *d, object str); object Cyc_list2string(void *d, object cont, object lst); common_type Cyc_string2number(void *d, object str); -void dispatch_string_91append(int argc, object clo, object cont, object str1, ...); object Cyc_string_append(void *data, object cont, int argc, object str1, ...); integer_type Cyc_string_length(void *data, object str); object Cyc_substring(void *data, object cont, object str, object start, object end); @@ -175,7 +173,7 @@ common_type Cyc_sum(void *data, int argc, object n, ...); common_type Cyc_sub(void *data, int argc, object n, ...); common_type Cyc_mul(void *data, int argc, object n, ...); common_type Cyc_div(void *data, int argc, object n, ...); -common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(object, object)), object n, va_list ns); +common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(void *, object, object)), object n, va_list ns); int equal(object,object); list assq(void *,object,list); list assoc(void *,object x, list l); diff --git a/runtime.c b/runtime.c index b1ef0c78..219d81da 100644 --- a/runtime.c +++ b/runtime.c @@ -596,7 +596,7 @@ object Cyc_write_char(void *data, object c, object port) } // TODO: should not be a predicate, may end up moving these to Scheme code -object memberp(void *data, object x, list l); +object memberp(void *data, object x, list l) {Cyc_check_cons_or_nil(data, l); for (; !nullp(l); l = cdr(l)) if (boolean_f != equalp(x,car(l))) return boolean_t; return boolean_f;} @@ -1238,7 +1238,7 @@ declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *, 0); // result contains a decimal component? declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /, 1); -common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(object, object)), object n, va_list ns) { +common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(void *, object, object)), object n, va_list ns) { common_type sum; int i; if (argc == 0) { @@ -1264,7 +1264,7 @@ common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(object, } for (i = 1; i < argc; i++) { - common_type result = fn_op(&sum, va_arg(ns, object)); + common_type result = fn_op(data, &sum, va_arg(ns, object)); if (type_of(&result) == integer_tag) { sum.integer_t.hdr.mark = gc_color_red; sum.integer_t.tag = integer_tag; @@ -1436,214 +1436,214 @@ cvar_type *mcvar(object *var) { void _Cyc_91global_91vars(void *data, object cont, object args){ return_closcall1(data, cont, Cyc_global_variables); } void _car(void *data, object cont, object args) { - Cyc_check_num_args("car", 1, args); + Cyc_check_num_args(data, "car", 1, args); { object var = car(args); - Cyc_check_cons(var); + Cyc_check_cons(data, var); return_closcall1(data, cont, car(var)); }} void _cdr(void *data, object cont, object args) { - Cyc_check_num_args("cdr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdr(car(args))); } void _caar(void *data, object cont, object args) { - Cyc_check_num_args("caar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caar(car(args))); } void _cadr(void *data, object cont, object args) { - Cyc_check_num_args("cadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cadr(car(args))); } void _cdar(void *data, object cont, object args) { - Cyc_check_num_args("cdar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdar(car(args))); } void _cddr(void *data, object cont, object args) { - Cyc_check_num_args("cddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cddr(car(args))); } void _caaar(void *data, object cont, object args) { - Cyc_check_num_args("caaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caaar(car(args))); } void _caadr(void *data, object cont, object args) { - Cyc_check_num_args("caadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caadr(car(args))); } void _cadar(void *data, object cont, object args) { - Cyc_check_num_args("cadar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cadar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cadar(car(args))); } void _caddr(void *data, object cont, object args) { - Cyc_check_num_args("caddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caddr(car(args))); } void _cdaar(void *data, object cont, object args) { - Cyc_check_num_args("cdaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdaar(car(args))); } void _cdadr(void *data, object cont, object args) { - Cyc_check_num_args("cdadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdadr(car(args))); } void _cddar(void *data, object cont, object args) { - Cyc_check_num_args("cddar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cddar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cddar(car(args))); } void _cdddr(void *data, object cont, object args) { - Cyc_check_num_args("cdddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdddr(car(args))); } void _caaaar(void *data, object cont, object args) { - Cyc_check_num_args("caaaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caaaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caaaar(car(args))); } void _caaadr(void *data, object cont, object args) { - Cyc_check_num_args("caaadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caaadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caaadr(car(args))); } void _caadar(void *data, object cont, object args) { - Cyc_check_num_args("caadar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caadar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caadar(car(args))); } void _caaddr(void *data, object cont, object args) { - Cyc_check_num_args("caaddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caaddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caaddr(car(args))); } void _cadaar(void *data, object cont, object args) { - Cyc_check_num_args("cadaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cadaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cadaar(car(args))); } void _cadadr(void *data, object cont, object args) { - Cyc_check_num_args("cadadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cadadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cadadr(car(args))); } void _caddar(void *data, object cont, object args) { - Cyc_check_num_args("caddar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "caddar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, caddar(car(args))); } void _cadddr(void *data, object cont, object args) { - Cyc_check_num_args("cadddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cadddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cadddr(car(args))); } void _cdaaar(void *data, object cont, object args) { - Cyc_check_num_args("cdaaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdaaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdaaar(car(args))); } void _cdaadr(void *data, object cont, object args) { - Cyc_check_num_args("cdaadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdaadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdaadr(car(args))); } void _cdadar(void *data, object cont, object args) { - Cyc_check_num_args("cdadar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdadar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdadar(car(args))); } void _cdaddr(void *data, object cont, object args) { - Cyc_check_num_args("cdaddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdaddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdaddr(car(args))); } void _cddaar(void *data, object cont, object args) { - Cyc_check_num_args("cddaar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cddaar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cddaar(car(args))); } void _cddadr(void *data, object cont, object args) { - Cyc_check_num_args("cddadr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cddadr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cddadr(car(args))); } void _cdddar(void *data, object cont, object args) { - Cyc_check_num_args("cdddar", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cdddar", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cdddar(car(args))); } void _cddddr(void *data, object cont, object args) { - Cyc_check_num_args("cddddr", 1, args); - Cyc_check_cons(car(args)); + Cyc_check_num_args(data, "cddddr", 1, args); + Cyc_check_cons(data, car(args)); return_closcall1(data, cont, cddddr(car(args))); } void _cons(void *data, object cont, object args) { - Cyc_check_num_args("cons", 2, args); + Cyc_check_num_args(data, "cons", 2, args); { make_cons(c, car(args), cadr(args)); return_closcall1(data, cont, &c); }} void _eq_127(void *data, object cont, object args){ - Cyc_check_num_args("eq?", 2, args); + Cyc_check_num_args(data, "eq?", 2, args); return_closcall1(data, cont, Cyc_eq(car(args), cadr(args))); } void _eqv_127(void *data, object cont, object args){ - Cyc_check_num_args("eqv?", 2, args); + Cyc_check_num_args(data, "eqv?", 2, args); _eq_127(data, cont, args); } void _equal_127(void *data, object cont, object args){ - Cyc_check_num_args("equal?", 2, args); + Cyc_check_num_args(data, "equal?", 2, args); return_closcall1(data, cont, equalp(car(args), cadr(args))); } void _length(void *data, object cont, object args){ - Cyc_check_num_args("length", 1, args); - { integer_type i = Cyc_length(car(args)); + Cyc_check_num_args(data, "length", 1, args); + { integer_type i = Cyc_length(data, car(args)); return_closcall1(data, cont, &i); }} void _vector_91length(void *data, object cont, object args){ - Cyc_check_num_args("vector_91length", 1, args); - { integer_type i = Cyc_vector_length(car(args)); + Cyc_check_num_args(data, "vector_91length", 1, args); + { integer_type i = Cyc_vector_length(data, car(args)); return_closcall1(data, cont, &i); }} void _null_127(void *data, object cont, object args) { - Cyc_check_num_args("null?", 1, args); + Cyc_check_num_args(data, "null?", 1, args); return_closcall1(data, cont, Cyc_is_null(car(args))); } void _set_91car_67(void *data, object cont, object args) { - Cyc_check_num_args("set-car!", 2, args); - return_closcall1(data, cont, Cyc_set_car(car(args), cadr(args))); } + Cyc_check_num_args(data, "set-car!", 2, args); + return_closcall1(data, cont, Cyc_set_car(data, car(args), cadr(args))); } void _set_91cdr_67(void *data, object cont, object args) { - Cyc_check_num_args("set-cdr!", 2, args); - return_closcall1(data, cont, Cyc_set_cdr(car(args), cadr(args))); } + Cyc_check_num_args(data, "set-cdr!", 2, args); + return_closcall1(data, cont, Cyc_set_cdr(data, car(args), cadr(args))); } void _Cyc_91has_91cycle_127(void *data, object cont, object args) { - Cyc_check_num_args("Cyc-has-cycle?", 1, args); + Cyc_check_num_args(data, "Cyc-has-cycle?", 1, args); return_closcall1(data, cont, Cyc_has_cycle(car(args))); } void __87(void *data, object cont, object args) { - integer_type argc = Cyc_length(args); + integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_sum, cont, cont, args); } void __91(void *data, object cont, object args) { - Cyc_check_num_args("-", 1, args); - { integer_type argc = Cyc_length(args); + Cyc_check_num_args(data, "-", 1, args); + { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_sub, cont, cont, args); }} void __85(void *data, object cont, object args) { - integer_type argc = Cyc_length(args); + integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_mul, cont, cont, args); } void __95(void *data, object cont, object args) { - Cyc_check_num_args("/", 1, args); - { integer_type argc = Cyc_length(args); + Cyc_check_num_args(data, "/", 1, args); + { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_div, cont, cont, args); }} void _Cyc_91cvar_127(void *data, object cont, object args) { - Cyc_check_num_args("Cyc-cvar?", 1, args); + Cyc_check_num_args(data, "Cyc-cvar?", 1, args); return_closcall1(data, cont, Cyc_is_cvar(car(args))); } void _boolean_127(void *data, object cont, object args) { - Cyc_check_num_args("boolean?", 1, args); + Cyc_check_num_args(data, "boolean?", 1, args); return_closcall1(data, cont, Cyc_is_boolean(car(args))); } void _char_127(void *data, object cont, object args) { - Cyc_check_num_args("char?", 1, args); + Cyc_check_num_args(data, "char?", 1, args); return_closcall1(data, cont, Cyc_is_char(car(args))); } void _eof_91object_127(void *data, object cont, object args) { - Cyc_check_num_args("eof_91object?", 1, args); + Cyc_check_num_args(data, "eof_91object?", 1, args); return_closcall1(data, cont, Cyc_is_eof_object(car(args))); } void _number_127(void *data, object cont, object args) { - Cyc_check_num_args("number?", 1, args); + Cyc_check_num_args(data, "number?", 1, args); return_closcall1(data, cont, Cyc_is_number(car(args))); } void _real_127(void *data, object cont, object args) { - Cyc_check_num_args("real?", 1, args); + Cyc_check_num_args(data, "real?", 1, args); return_closcall1(data, cont, Cyc_is_real(car(args))); } void _integer_127(void *data, object cont, object args) { - Cyc_check_num_args("integer?", 1, args); + Cyc_check_num_args(data, "integer?", 1, args); return_closcall1(data, cont, Cyc_is_integer(car(args))); } void _pair_127(void *data, object cont, object args) { - Cyc_check_num_args("pair?", 1, args); + Cyc_check_num_args(data, "pair?", 1, args); return_closcall1(data, cont, Cyc_is_cons(car(args))); } void _procedure_127(void *data, object cont, object args) { - Cyc_check_num_args("procedure?", 1, args); - return_closcall1(data, cont, Cyc_is_procedure(car(args))); } + Cyc_check_num_args(data, "procedure?", 1, args); + return_closcall1(data, cont, Cyc_is_procedure(data, car(args))); } void _macro_127(void *data, object cont, object args) { - Cyc_check_num_args("macro?", 1, args); + Cyc_check_num_args(data, "macro?", 1, args); return_closcall1(data, cont, Cyc_is_macro(car(args))); } void _port_127(void *data, object cont, object args) { - Cyc_check_num_args("port?", 1, args); + Cyc_check_num_args(data, "port?", 1, args); return_closcall1(data, cont, Cyc_is_port(car(args))); } void _vector_127(void *data, object cont, object args) { - Cyc_check_num_args("vector?", 1, args); + Cyc_check_num_args(data, "vector?", 1, args); return_closcall1(data, cont, Cyc_is_vector(car(args))); } void _string_127(void *data, object cont, object args) { - Cyc_check_num_args("string?", 1, args); + Cyc_check_num_args(data, "string?", 1, args); return_closcall1(data, cont, Cyc_is_string(car(args))); } void _symbol_127(void *data, object cont, object args) { - Cyc_check_num_args("symbol?", 1, args); + Cyc_check_num_args(data, "symbol?", 1, args); return_closcall1(data, cont, Cyc_is_symbol(car(args))); } void _Cyc_91get_91cvar(void *data, object cont, object args) { @@ -1668,76 +1668,76 @@ void _cell(void *data, object cont, object args) { printf("not implemented\n"); exit(1); } void __123(void *data, object cont, object args) { - Cyc_check_num_args("=", 2, args); - return_closcall1(data, cont, __num_eq(car(args), cadr(args)));} + Cyc_check_num_args(data, "=", 2, args); + return_closcall1(data, cont, __num_eq(data, car(args), cadr(args)));} void __125(void *data, object cont, object args) { - Cyc_check_num_args(">", 2, args); - return_closcall1(data, cont, __num_gt(car(args), cadr(args)));} + Cyc_check_num_args(data, ">", 2, args); + return_closcall1(data, cont, __num_gt(data, car(args), cadr(args)));} void __121(void *data, object cont, object args) { - Cyc_check_num_args("<", 2, args); - return_closcall1(data, cont, __num_lt(car(args), cadr(args)));} + Cyc_check_num_args(data, "<", 2, args); + return_closcall1(data, cont, __num_lt(data, car(args), cadr(args)));} void __125_123(void *data, object cont, object args) { - Cyc_check_num_args(">=", 2, args); - return_closcall1(data, cont, __num_gte(car(args), cadr(args)));} + Cyc_check_num_args(data, ">=", 2, args); + return_closcall1(data, cont, __num_gte(data, car(args), cadr(args)));} void __121_123(void *data, object cont, object args) { - Cyc_check_num_args("<=", 2, args); - return_closcall1(data, cont, __num_lte(car(args), cadr(args)));} + Cyc_check_num_args(data, "<=", 2, args); + return_closcall1(data, cont, __num_lte(data, car(args), cadr(args)));} void _apply(void *data, object cont, object args) { - Cyc_check_num_args("apply", 2, args); + Cyc_check_num_args(data, "apply", 2, args); apply(data, cont, car(args), cadr(args)); } void _assoc (void *data, object cont, object args) { - Cyc_check_num_args("assoc ", 2, args); - return_closcall1(data, cont, assoc(car(args), cadr(args)));} + Cyc_check_num_args(data, "assoc ", 2, args); + return_closcall1(data, cont, assoc(data, car(args), cadr(args)));} void _assq (void *data, object cont, object args) { - Cyc_check_num_args("assq ", 2, args); - return_closcall1(data, cont, assq(car(args), cadr(args)));} + Cyc_check_num_args(data, "assq ", 2, args); + return_closcall1(data, cont, assq(data, car(args), cadr(args)));} void _assv (void *data, object cont, object args) { - Cyc_check_num_args("assv ", 2, args); - return_closcall1(data, cont, assq(car(args), cadr(args)));} + Cyc_check_num_args(data, "assv ", 2, args); + return_closcall1(data, cont, assq(data, car(args), cadr(args)));} void _member(void *data, object cont, object args) { - Cyc_check_num_args("member", 2, args); - return_closcall1(data, cont, memberp(car(args), cadr(args)));} + Cyc_check_num_args(data, "member", 2, args); + return_closcall1(data, cont, memberp(data, car(args), cadr(args)));} void _memq(void *data, object cont, object args) { - Cyc_check_num_args("memq", 2, args); - return_closcall1(data, cont, memqp(car(args), cadr(args)));} + Cyc_check_num_args(data, "memq", 2, args); + return_closcall1(data, cont, memqp(data, car(args), cadr(args)));} void _memv(void *data, object cont, object args) { - Cyc_check_num_args("memv", 2, args); - return_closcall1(data, cont, memqp(car(args), cadr(args)));} + Cyc_check_num_args(data, "memv", 2, args); + return_closcall1(data, cont, memqp(data, car(args), cadr(args)));} void _char_91_125integer(void *data, object cont, object args) { - Cyc_check_num_args("char->integer", 1, args); + Cyc_check_num_args(data, "char->integer", 1, args); { integer_type i = Cyc_char2integer(car(args)); return_closcall1(data, cont, &i);}} void _integer_91_125char(void *data, object cont, object args) { - Cyc_check_num_args("integer->char", 1, args); - return_closcall1(data, cont, Cyc_integer2char(car(args)));} + Cyc_check_num_args(data, "integer->char", 1, args); + return_closcall1(data, cont, Cyc_integer2char(data, car(args)));} void _string_91_125number(void *data, object cont, object args) { - Cyc_check_num_args("string->number", 1, args); - { common_type i = Cyc_string2number(car(args)); + Cyc_check_num_args(data, "string->number", 1, args); + { common_type i = Cyc_string2number(data, car(args)); return_closcall1(data, cont, &i);}} void _string_91length(void *data, object cont, object args) { - Cyc_check_num_args("string-length", 1, args); - { integer_type i = Cyc_string_length(car(args)); + Cyc_check_num_args(data, "string-length", 1, args); + { integer_type i = Cyc_string_length(data, car(args)); return_closcall1(data, cont, &i);}} void _cyc_substring(void *data, object cont, object args) { - Cyc_check_num_args("substring", 3, args); + Cyc_check_num_args(data, "substring", 3, args); Cyc_substring(data, cont, car(args), cadr(args), caddr(args));} void _cyc_string_91set_67(void *data, object cont, object args) { - Cyc_check_num_args("string-set!", 3, args); - { object s = Cyc_string_set(car(args), cadr(args), caddr(args)); + Cyc_check_num_args(data, "string-set!", 3, args); + { object s = Cyc_string_set(data, car(args), cadr(args), caddr(args)); return_closcall1(data, cont, s); }} void _cyc_string_91ref(void *data, object cont, object args) { - Cyc_check_num_args("string-ref", 2, args); - { object c = Cyc_string_ref(car(args), cadr(args)); + Cyc_check_num_args(data, "string-ref", 2, args); + { object c = Cyc_string_ref(data, car(args), cadr(args)); return_closcall1(data, cont, c); }} void _Cyc_91installation_91dir(void *data, object cont, object args) { - Cyc_check_num_args("Cyc-installation-dir", 1, args); + Cyc_check_num_args(data, "Cyc-installation-dir", 1, args); Cyc_installation_dir(data, cont, car(args));} void _command_91line_91arguments(void *data, object cont, object args) { - object cmdline = Cyc_command_line_arguments(cont); + object cmdline = Cyc_command_line_arguments(data, cont); return_closcall1(data, cont, cmdline); } void _cyc_system(void *data, object cont, object args) { - Cyc_check_num_args("system", 1, args); + Cyc_check_num_args(data, "system", 1, args); { integer_type i = Cyc_system(car(args)); return_closcall1(data, cont, &i);}} //void _error(void *data, object cont, object args) { @@ -1751,91 +1751,93 @@ void _Cyc_91default_91exception_91handler(void *data, object cont, object args) Cyc_default_exception_handler(data, 1, args, car(args)); } void _string_91cmp(void *data, object cont, object args) { - Cyc_check_num_args("string-cmp", 2, args); - { integer_type cmp = Cyc_string_cmp(car(args), cadr(args)); + Cyc_check_num_args(data, "string-cmp", 2, args); + { integer_type cmp = Cyc_string_cmp(data, car(args), cadr(args)); return_closcall1(data, cont, &cmp);}} void _string_91append(void *data, object cont, object args) { - integer_type argc = Cyc_length(args); + integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_string_91append, cont, cont, args); } void _make_91vector(void *data, object cont, object args) { - Cyc_check_num_args("make-vector", 1, args); - { integer_type argc = Cyc_length(args); + Cyc_check_num_args(data, "make-vector", 1, args); + { integer_type argc = Cyc_length(data, args); if (argc.value >= 2) { Cyc_make_vector(data, cont, car(args), cadr(args));} else { Cyc_make_vector(data, cont, car(args), boolean_f);}}} void _vector_91ref(void *data, object cont, object args) { - Cyc_check_num_args("vector-ref", 2, args); - { object ref = Cyc_vector_ref(car(args), cadr(args)); + Cyc_check_num_args(data, "vector-ref", 2, args); + { object ref = Cyc_vector_ref(data, car(args), cadr(args)); return_closcall1(data, cont, ref);}} void _vector_91set_67(void *data, object cont, object args) { - Cyc_check_num_args("vector-set!", 3, args); - { object ref = Cyc_vector_set(car(args), cadr(args), caddr(args)); + Cyc_check_num_args(data, "vector-set!", 3, args); + { object ref = Cyc_vector_set(data, car(args), cadr(args), caddr(args)); return_closcall1(data, cont, ref);}} void _list_91_125vector(void *data, object cont, object args) { - Cyc_check_num_args("list->vector", 1, args); + Cyc_check_num_args(data, "list->vector", 1, args); Cyc_list2vector(data, cont, car(args));} void _list_91_125string(void *data, object cont, object args) { - Cyc_check_num_args("list->string", 1, args); + Cyc_check_num_args(data, "list->string", 1, args); Cyc_list2string(data, cont, car(args));} void _string_91_125symbol(void *data, object cont, object args) { - Cyc_check_num_args("string->symbol", 1, args); - return_closcall1(data, cont, Cyc_string2symbol(car(args)));} + Cyc_check_num_args(data, "string->symbol", 1, args); + return_closcall1(data, cont, Cyc_string2symbol(data, car(args)));} void _symbol_91_125string(void *data, object cont, object args) { - Cyc_check_num_args("symbol->string", 1, args); + Cyc_check_num_args(data, "symbol->string", 1, args); Cyc_symbol2string(data, cont, car(args));} void _number_91_125string(void *data, object cont, object args) { - Cyc_check_num_args("number->string", 1, args); + Cyc_check_num_args(data, "number->string", 1, args); Cyc_number2string(data, cont, car(args));} void _open_91input_91file(void *data, object cont, object args) { - Cyc_check_num_args("open-input-file", 1, args); - { port_type p = Cyc_io_open_input_file(car(args)); + Cyc_check_num_args(data, "open-input-file", 1, args); + { port_type p = Cyc_io_open_input_file(data, car(args)); return_closcall1(data, cont, &p);}} void _open_91output_91file(void *data, object cont, object args) { - Cyc_check_num_args("open-output-file", 1, args); - { port_type p = Cyc_io_open_output_file(car(args)); + Cyc_check_num_args(data, "open-output-file", 1, args); + { port_type p = Cyc_io_open_output_file(data, car(args)); return_closcall1(data, cont, &p);}} void _close_91port(void *data, object cont, object args) { - Cyc_check_num_args("close-port", 1, args); - return_closcall1(data, cont, Cyc_io_close_port(car(args)));} + Cyc_check_num_args(data, "close-port", 1, args); + return_closcall1(data, cont, Cyc_io_close_port(data, car(args)));} void _close_91input_91port(void *data, object cont, object args) { - Cyc_check_num_args("close-input-port", 1, args); - return_closcall1(data, cont, Cyc_io_close_input_port(car(args)));} + Cyc_check_num_args(data, "close-input-port", 1, args); + return_closcall1(data, cont, Cyc_io_close_input_port(data, car(args)));} void _close_91output_91port(void *data, object cont, object args) { - Cyc_check_num_args("close-output-port", 1, args); - return_closcall1(data, cont, Cyc_io_close_output_port(car(args)));} + Cyc_check_num_args(data, "close-output-port", 1, args); + return_closcall1(data, cont, Cyc_io_close_output_port(data, car(args)));} void _Cyc_91flush_91output_91port(void *data, object cont, object args) { - Cyc_check_num_args("Cyc-flush-output-port", 1, args); - return_closcall1(data, cont, Cyc_io_flush_output_port(car(args)));} + Cyc_check_num_args(data, "Cyc-flush-output-port", 1, args); + return_closcall1(data, cont, Cyc_io_flush_output_port(data, car(args)));} void _file_91exists_127(void *data, object cont, object args) { - Cyc_check_num_args("file-exists?", 1, args); - return_closcall1(data, cont, Cyc_io_file_exists(car(args)));} + Cyc_check_num_args(data, "file-exists?", 1, args); + return_closcall1(data, cont, Cyc_io_file_exists(data, car(args)));} void _delete_91file(void *data, object cont, object args) { - Cyc_check_num_args("delete-file", 1, args); - return_closcall1(data, cont, Cyc_io_delete_file(car(args)));} + Cyc_check_num_args(data, "delete-file", 1, args); + return_closcall1(data, cont, Cyc_io_delete_file(data, car(args)));} void _read_91char(void *data, object cont, object args) { - Cyc_check_num_args("read-char", 1, args); - return_closcall1(data, cont, Cyc_io_read_char(car(args)));} + Cyc_check_num_args(data, "read-char", 1, args); + return_closcall1(data, cont, Cyc_io_read_char(data, car(args)));} void _peek_91char(void *data, object cont, object args) { - Cyc_check_num_args("peek-char", 1, args); - return_closcall1(data, cont, Cyc_io_peek_char(car(args)));} + Cyc_check_num_args(data, "peek-char", 1, args); + return_closcall1(data, cont, Cyc_io_peek_char(data, car(args)));} void _Cyc_91read_91line(void *data, object cont, object args) { - Cyc_check_num_args("Cyc-read-line", 1, args); + Cyc_check_num_args(data, "Cyc-read-line", 1, args); Cyc_io_read_line(data, cont, car(args));} void _Cyc_91write_91char(void *data, object cont, object args) { - Cyc_check_num_args("write-char", 2, args); + Cyc_check_num_args(data, "write-char", 2, args); return_closcall1(data, cont, Cyc_write_char(data, car(args), cadr(args)));} void _Cyc_91write(void *data, object cont, object args) { - Cyc_check_num_args("write", 1, args); - { integer_type argc = Cyc_length(args); + Cyc_check_num_args(data, "write", 1, args); + { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_write_va, cont, cont, args); }} void _display(void *data, object cont, object args) { - Cyc_check_num_args("display", 1, args); - { integer_type argc = Cyc_length(args); + Cyc_check_num_args(data, "display", 1, args); + { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_display_va, cont, cont, args); }} void _call_95cc(void *data, object cont, object args){ - Cyc_check_num_args("call/cc", 1, args); - Cyc_check_fnc(car(args)); + Cyc_check_num_args(data, "call/cc", 1, args); + if (eq(boolean_f, Cyc_is_procedure(data, car(args)))) { + Cyc_invalid_type_error(data, closure2_tag, car(args)); + } return_closcall2(data, __glo_call_95cc, cont, car(args)); } @@ -1871,7 +1873,7 @@ object apply(void *data, object cont, object func, object args){ case closureN_tag: buf.integer_t = Cyc_length(data, args); // TODO: validate number of args provided: - Cyc_check_num_args("", ((closure)func)->num_args, args); // TODO: could be more efficient, eg: cyc_length(args) is called twice. + Cyc_check_num_args(data, "", ((closure)func)->num_args, args); // TODO: could be more efficient, eg: cyc_length(args) is called twice. dispatch(data, buf.integer_t.value, ((closure)func)->fn, func, cont, args); break; @@ -1936,7 +1938,7 @@ void Cyc_apply(void *data, int argc, closure cont, object prim, ...){ // END apply /* Extract args from given array, assuming cont is the first arg in buf */ -void Cyc_apply_from_buf(data, int argc, object prim, object *buf) { +void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { list args; object cont; int i; @@ -2742,7 +2744,7 @@ void GC(void *data, closure cont, object *args, int num_args) } //fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG - longjmp(jmp_main, &data); // Return globals gc_cont, gc_ans + longjmp(jmp_main, (int)(&data)); // Return globals gc_cont, gc_ans } From ca7afc7c59de55902d46ef86d6e270d289fb5668 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 02:01:15 -0500 Subject: [PATCH 096/339] Added stub --- scheme/cyclone/cgen.sld | 127 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 2689cec6..1196b8c0 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -555,6 +555,133 @@ (else (error "unhandled primitive: " p)))) +TODO: +;; Does the primitive require passing thread data as its first argument? +(define (prim/data-arg? p) + (member p '( +; (cond +; ((eq? p 'Cyc-global-vars) "Cyc_get_global_variables") +; ((eq? p 'Cyc-get-cvar) "Cyc_get_cvar") +; ((eq? p 'Cyc-set-cvar!) "Cyc_set_cvar") +; ((eq? p 'Cyc-cvar?) "Cyc_is_cvar") +; ((eq? p 'Cyc-has-cycle?) "Cyc_has_cycle") +; ((eq? p 'Cyc-stdout) "Cyc_stdout") +; ((eq? p 'Cyc-stdin) "Cyc_stdin") +; ((eq? p 'Cyc-stderr) "Cyc_stderr") +; ((eq? p '+) "Cyc_sum") +; ((eq? p '-) "Cyc_sub") +; ((eq? p '*) "Cyc_mul") +; ((eq? p '/) "Cyc_div") +; ((eq? p '=) "__num_eq") +; ((eq? p '>) "__num_gt") +; ((eq? p '<) "__num_lt") +; ((eq? p '>=) "__num_gte") +; ((eq? p '<=) "__num_lte") +; ((eq? p 'apply) "apply") +; ((eq? p '%halt) "__halt") +; ((eq? p 'exit) "__halt") +; ((eq? p 'Cyc-default-exception-handler) "Cyc_default_exception_handler") +; ((eq? p 'Cyc-current-exception-handler) "Cyc_current_exception_handler") +; ((eq? p 'open-input-file) "Cyc_io_open_input_file") +; ((eq? p 'open-output-file) "Cyc_io_open_output_file") +; ((eq? p 'close-port) "Cyc_io_close_port") +; ((eq? p 'close-input-port) "Cyc_io_close_input_port") +; ((eq? p 'close-output-port) "Cyc_io_close_output_port") +; ((eq? p 'Cyc-flush-output-port) "Cyc_io_flush_output_port") +; ((eq? p 'file-exists?) "Cyc_io_file_exists") +; ((eq? p 'delete-file) "Cyc_io_delete_file") +; ((eq? p 'read-char) "Cyc_io_read_char") +; ((eq? p 'peek-char) "Cyc_io_peek_char") +; ((eq? p 'Cyc-read-line) "Cyc_io_read_line") +; ((eq? p 'Cyc-display) "Cyc_display_va") +; ((eq? p 'Cyc-write) "Cyc_write_va") +; ((eq? p 'Cyc-write-char) "Cyc_write_char") +; ((eq? p 'car) "car") +; ((eq? p 'cdr) "cdr") +; ((eq? p 'caar) "caar") +; ((eq? p 'cadr) "cadr") +; ((eq? p 'cdar) "cdar") +; ((eq? p 'cddr) "cddr") +; ((eq? p 'caaar) "caaar") +; ((eq? p 'caadr) "caadr") +; ((eq? p 'cadar) "cadar") +; ((eq? p 'caddr) "caddr") +; ((eq? p 'cdaar) "cdaar") +; ((eq? p 'cdadr) "cdadr") +; ((eq? p 'cddar) "cddar") +; ((eq? p 'cdddr) "cdddr") +; ((eq? p 'caaaar) "caaaar") +; ((eq? p 'caaadr) "caaadr") +; ((eq? p 'caadar) "caadar") +; ((eq? p 'caaddr) "caaddr") +; ((eq? p 'cadaar) "cadaar") +; ((eq? p 'cadadr) "cadadr") +; ((eq? p 'caddar) "caddar") +; ((eq? p 'cadddr) "cadddr") +; ((eq? p 'cdaaar) "cdaaar") +; ((eq? p 'cdaadr) "cdaadr") +; ((eq? p 'cdadar) "cdadar") +; ((eq? p 'cdaddr) "cdaddr") +; ((eq? p 'cddaar) "cddaar") +; ((eq? p 'cddadr) "cddadr") +; ((eq? p 'cdddar) "cdddar") +; ((eq? p 'cddddr) "cddddr") +; ((eq? p 'char->integer) "Cyc_char2integer") +; ((eq? p 'integer->char) "Cyc_integer2char") +; ((eq? p 'string->number)"Cyc_string2number") +; ((eq? p 'list->string) "Cyc_list2string") +; ((eq? p 'make-vector) "Cyc_make_vector") +; ((eq? p 'list->vector) "Cyc_list2vector") +; ((eq? p 'vector-length) "Cyc_vector_length") +; ((eq? p 'vector-ref) "Cyc_vector_ref") +; ((eq? p 'vector-set!) "Cyc_vector_set") +; ((eq? p 'string-append) "Cyc_string_append") +; ((eq? p 'string-cmp) "Cyc_string_cmp") +; ((eq? p 'string->symbol) "Cyc_string2symbol") +; ((eq? p 'symbol->string) "Cyc_symbol2string") +; ((eq? p 'number->string) "Cyc_number2string") +; ((eq? p 'string-length) "Cyc_string_length") +; ((eq? p 'string-ref) "Cyc_string_ref") +; ((eq? p 'string-set!) "Cyc_string_set") +; ((eq? p 'substring) "Cyc_substring") +; ((eq? p 'Cyc-installation-dir) "Cyc_installation_dir") +; ((eq? p 'command-line-arguments) "Cyc_command_line_arguments") +; ((eq? p 'system) "Cyc_system") +; ((eq? p 'assq) "assq") +; ((eq? p 'assv) "assq") +; ((eq? p 'assoc) "assoc") +; ((eq? p 'memq) "memqp") +; ((eq? p 'memv) "memqp") +; ((eq? p 'member) "memberp") +; ((eq? p 'length) "Cyc_length") +; ((eq? p 'set-car!) "Cyc_set_car") +; ((eq? p 'set-cdr!) "Cyc_set_cdr") +; ((eq? p 'eq?) "Cyc_eq") +; ((eq? p 'eqv?) "Cyc_eq") +; ((eq? p 'equal?) "equalp") +; ((eq? p 'boolean?) "Cyc_is_boolean") +; ((eq? p 'char?) "Cyc_is_char") +; ((eq? p 'null?) "Cyc_is_null") +; ((eq? p 'number?) "Cyc_is_number") +; ((eq? p 'real?) "Cyc_is_real") +; ((eq? p 'integer?) "Cyc_is_integer") +; ((eq? p 'pair?) "Cyc_is_cons") +; ((eq? p 'procedure?) "Cyc_is_procedure") +; ((eq? p 'macro?) "Cyc_is_macro") +; ((eq? p 'port?) "Cyc_is_port") +; ((eq? p 'vector?) "Cyc_is_vector") +; ((eq? p 'string?) "Cyc_is_string") +; ((eq? p 'eof-object?) "Cyc_is_eof_object") +; ((eq? p 'symbol?) "Cyc_is_symbol") +; ((eq? p 'cons) "make_cons") +; ((eq? p 'cell) "make_cell") +; ((eq? p 'cell-get) "cell_get") +; ((eq? p 'set-cell!) "Cyc_set_car") +; ((eq? p 'set-global!) "global_set") +; (else +; (error "unhandled primitive: " p)))) +)) + ;; Determine if primitive assigns (allocates) a C variable ;; EG: int v = prim(); (define (prim/c-var-assign p) From 0cd4d2e7961d5fe30acde603c7daa5e326296b95 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 02:25:50 -0500 Subject: [PATCH 097/339] Full version of (prim/data-arg? p) --- scheme/cyclone/cgen.sld | 176 ++++++++++++---------------------------- 1 file changed, 53 insertions(+), 123 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 1196b8c0..44c75577 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -555,132 +555,62 @@ (else (error "unhandled primitive: " p)))) -TODO: ;; Does the primitive require passing thread data as its first argument? (define (prim/data-arg? p) (member p '( -; (cond -; ((eq? p 'Cyc-global-vars) "Cyc_get_global_variables") -; ((eq? p 'Cyc-get-cvar) "Cyc_get_cvar") -; ((eq? p 'Cyc-set-cvar!) "Cyc_set_cvar") -; ((eq? p 'Cyc-cvar?) "Cyc_is_cvar") -; ((eq? p 'Cyc-has-cycle?) "Cyc_has_cycle") -; ((eq? p 'Cyc-stdout) "Cyc_stdout") -; ((eq? p 'Cyc-stdin) "Cyc_stdin") -; ((eq? p 'Cyc-stderr) "Cyc_stderr") -; ((eq? p '+) "Cyc_sum") -; ((eq? p '-) "Cyc_sub") -; ((eq? p '*) "Cyc_mul") -; ((eq? p '/) "Cyc_div") -; ((eq? p '=) "__num_eq") -; ((eq? p '>) "__num_gt") -; ((eq? p '<) "__num_lt") -; ((eq? p '>=) "__num_gte") -; ((eq? p '<=) "__num_lte") -; ((eq? p 'apply) "apply") -; ((eq? p '%halt) "__halt") -; ((eq? p 'exit) "__halt") -; ((eq? p 'Cyc-default-exception-handler) "Cyc_default_exception_handler") -; ((eq? p 'Cyc-current-exception-handler) "Cyc_current_exception_handler") -; ((eq? p 'open-input-file) "Cyc_io_open_input_file") -; ((eq? p 'open-output-file) "Cyc_io_open_output_file") -; ((eq? p 'close-port) "Cyc_io_close_port") -; ((eq? p 'close-input-port) "Cyc_io_close_input_port") -; ((eq? p 'close-output-port) "Cyc_io_close_output_port") -; ((eq? p 'Cyc-flush-output-port) "Cyc_io_flush_output_port") -; ((eq? p 'file-exists?) "Cyc_io_file_exists") -; ((eq? p 'delete-file) "Cyc_io_delete_file") -; ((eq? p 'read-char) "Cyc_io_read_char") -; ((eq? p 'peek-char) "Cyc_io_peek_char") -; ((eq? p 'Cyc-read-line) "Cyc_io_read_line") -; ((eq? p 'Cyc-display) "Cyc_display_va") -; ((eq? p 'Cyc-write) "Cyc_write_va") -; ((eq? p 'Cyc-write-char) "Cyc_write_char") -; ((eq? p 'car) "car") -; ((eq? p 'cdr) "cdr") -; ((eq? p 'caar) "caar") -; ((eq? p 'cadr) "cadr") -; ((eq? p 'cdar) "cdar") -; ((eq? p 'cddr) "cddr") -; ((eq? p 'caaar) "caaar") -; ((eq? p 'caadr) "caadr") -; ((eq? p 'cadar) "cadar") -; ((eq? p 'caddr) "caddr") -; ((eq? p 'cdaar) "cdaar") -; ((eq? p 'cdadr) "cdadr") -; ((eq? p 'cddar) "cddar") -; ((eq? p 'cdddr) "cdddr") -; ((eq? p 'caaaar) "caaaar") -; ((eq? p 'caaadr) "caaadr") -; ((eq? p 'caadar) "caadar") -; ((eq? p 'caaddr) "caaddr") -; ((eq? p 'cadaar) "cadaar") -; ((eq? p 'cadadr) "cadadr") -; ((eq? p 'caddar) "caddar") -; ((eq? p 'cadddr) "cadddr") -; ((eq? p 'cdaaar) "cdaaar") -; ((eq? p 'cdaadr) "cdaadr") -; ((eq? p 'cdadar) "cdadar") -; ((eq? p 'cdaddr) "cdaddr") -; ((eq? p 'cddaar) "cddaar") -; ((eq? p 'cddadr) "cddadr") -; ((eq? p 'cdddar) "cdddar") -; ((eq? p 'cddddr) "cddddr") -; ((eq? p 'char->integer) "Cyc_char2integer") -; ((eq? p 'integer->char) "Cyc_integer2char") -; ((eq? p 'string->number)"Cyc_string2number") -; ((eq? p 'list->string) "Cyc_list2string") -; ((eq? p 'make-vector) "Cyc_make_vector") -; ((eq? p 'list->vector) "Cyc_list2vector") -; ((eq? p 'vector-length) "Cyc_vector_length") -; ((eq? p 'vector-ref) "Cyc_vector_ref") -; ((eq? p 'vector-set!) "Cyc_vector_set") -; ((eq? p 'string-append) "Cyc_string_append") -; ((eq? p 'string-cmp) "Cyc_string_cmp") -; ((eq? p 'string->symbol) "Cyc_string2symbol") -; ((eq? p 'symbol->string) "Cyc_symbol2string") -; ((eq? p 'number->string) "Cyc_number2string") -; ((eq? p 'string-length) "Cyc_string_length") -; ((eq? p 'string-ref) "Cyc_string_ref") -; ((eq? p 'string-set!) "Cyc_string_set") -; ((eq? p 'substring) "Cyc_substring") -; ((eq? p 'Cyc-installation-dir) "Cyc_installation_dir") -; ((eq? p 'command-line-arguments) "Cyc_command_line_arguments") -; ((eq? p 'system) "Cyc_system") -; ((eq? p 'assq) "assq") -; ((eq? p 'assv) "assq") -; ((eq? p 'assoc) "assoc") -; ((eq? p 'memq) "memqp") -; ((eq? p 'memv) "memqp") -; ((eq? p 'member) "memberp") -; ((eq? p 'length) "Cyc_length") -; ((eq? p 'set-car!) "Cyc_set_car") -; ((eq? p 'set-cdr!) "Cyc_set_cdr") -; ((eq? p 'eq?) "Cyc_eq") -; ((eq? p 'eqv?) "Cyc_eq") -; ((eq? p 'equal?) "equalp") -; ((eq? p 'boolean?) "Cyc_is_boolean") -; ((eq? p 'char?) "Cyc_is_char") -; ((eq? p 'null?) "Cyc_is_null") -; ((eq? p 'number?) "Cyc_is_number") -; ((eq? p 'real?) "Cyc_is_real") -; ((eq? p 'integer?) "Cyc_is_integer") -; ((eq? p 'pair?) "Cyc_is_cons") -; ((eq? p 'procedure?) "Cyc_is_procedure") -; ((eq? p 'macro?) "Cyc_is_macro") -; ((eq? p 'port?) "Cyc_is_port") -; ((eq? p 'vector?) "Cyc_is_vector") -; ((eq? p 'string?) "Cyc_is_string") -; ((eq? p 'eof-object?) "Cyc_is_eof_object") -; ((eq? p 'symbol?) "Cyc_is_symbol") -; ((eq? p 'cons) "make_cons") -; ((eq? p 'cell) "make_cell") -; ((eq? p 'cell-get) "cell_get") -; ((eq? p 'set-cell!) "Cyc_set_car") -; ((eq? p 'set-global!) "global_set") -; (else -; (error "unhandled primitive: " p)))) -)) + + + - + * + / + = + > + < + >= + <= + apply + Cyc-default-exception-handler + open-input-file + open-output-file + close-port + close-input-port + close-output-port + Cyc-flush-output-port + file-exists? + delete-file + read-char + peek-char + Cyc-read-line + Cyc-write-char + integer->char + string->number + list->string + make-vector + list->vector + vector-length + vector-ref + vector-set! + string-append + string-cmp + string->symbol + symbol->string + number->string + string-length + string-ref + string-set! + substring + Cyc-installation-dir + command-line-arguments + assq + assv + assoc + memq + memv + member + length + set-car! + set-cdr! + procedure? + set-cell!)) ;; Determine if primitive assigns (allocates) a C variable ;; EG: int v = prim(); From a84c8b9339c9f8026cd9bc3987bec0d528d64702 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 3 Nov 2015 23:04:13 -0500 Subject: [PATCH 098/339] WIP --- Makefile | 9 ++--- include/cyclone/runtime-main.h | 6 ++-- scheme/cyclone/cgen.sld | 62 +++++++++++++++++++--------------- 3 files changed, 43 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index abafa8ca..6ca4e7fb 100644 --- a/Makefile +++ b/Makefile @@ -150,8 +150,9 @@ sld: .PHONY: debug debug: - cyclone scheme/cyclone/macros.sld && sudo cp scheme/cyclone/macros.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.o /usr/local/share/cyclone/scheme/cyclone/ && \ - cyclone scheme/cyclone/util.sld && sudo cp scheme/cyclone/util.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.o /usr/local/share/cyclone/scheme/cyclone/ && \ - cyclone scheme/cyclone/transforms.sld && sudo cp scheme/cyclone/transforms.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.o /usr/local/share/cyclone/scheme/cyclone/ && \ - cyclone -t cyclone.scm && cyclone -t icyc.scm && sudo make install-bin + cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ && cyclone cyclone.scm && sudo make install-includes && sudo make install-libs && ./cyclone generate-c.scm +### cyclone scheme/cyclone/macros.sld && sudo cp scheme/cyclone/macros.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.o /usr/local/share/cyclone/scheme/cyclone/ && \ +### cyclone scheme/cyclone/util.sld && sudo cp scheme/cyclone/util.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.o /usr/local/share/cyclone/scheme/cyclone/ && \ +### cyclone scheme/cyclone/transforms.sld && sudo cp scheme/cyclone/transforms.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.o /usr/local/share/cyclone/scheme/cyclone/ && \ +### cyclone -t cyclone.scm && cyclone -t icyc.scm && sudo make install-bin diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 13e58601..e189f067 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -14,7 +14,7 @@ long global_stack_size = 0; long global_heap_size = 0; -static void c_entry_pt(int,closure,closure); +static void c_entry_pt(void *,int,closure,closure); static void Cyc_main(long stack_size,long heap_size,char *stack_base); static void Cyc_main (stack_size,heap_size,stack_base) @@ -87,9 +87,9 @@ static void Cyc_main (stack_size,heap_size,stack_base) // JAE - note for the general case, setjmp will return the data pointer's addy if (type_of(gc_cont) == cons_tag || prim(gc_cont)) { - Cyc_apply_from_buf(gc_num_ans, gc_cont, gc_ans); + Cyc_apply_from_buf(Cyc_thread, gc_num_ans, gc_cont, gc_ans); } else { - do_dispatch(gc_num_ans, ((closure)gc_cont)->fn, gc_cont, gc_ans); + do_dispatch(Cyc_thread, gc_num_ans, ((closure)gc_cont)->fn, gc_cont, gc_ans); } printf("Internal error: should never have reached this line\n"); exit(0);}} diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 44c75577..65cfba86 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -110,12 +110,12 @@ (arry-assign (c-macro-array-assign num-args "buf" "a"))) (string-append "/* Check for GC, then call given continuation closure */\n" - "#define return_closcall" n "(cfn" args ") \\\n" + "#define return_closcall" n "(td,cfn" args ") \\\n" "{char stack; \\\n" " if (check_overflow(&stack,stack_limit1)) { \\\n" " object buf[" n "]; " arry-assign "\\\n" - " GC(cfn,buf," n "); return; \\\n" - " } else {closcall" n "((closure) (cfn)" args "); return;}}\n"))) + " GC(td,cfn,buf," n "); return; \\\n" + " } else {closcall" n "(td,(closure) (cfn)" args "); return;}}\n"))) (define (c-macro-return-direct num-args) (let ((args (c-macro-n-prefix num-args ",a")) @@ -123,13 +123,13 @@ (arry-assign (c-macro-array-assign num-args "buf" "a"))) (string-append "/* Check for GC, then call C function directly */\n" - "#define return_direct" n "(_fn" args ") { \\\n" + "#define return_direct" n "(td,_fn" args ") { \\\n" " char stack; \\\n" " if (check_overflow(&stack,stack_limit1)) { \\\n" " object buf[" n "]; " arry-assign " \\\n" " mclosure0(c1, _fn); \\\n" - " GC(&c1, buf, " n "); return; \\\n" - " } else { (_fn)(" n ",(closure)_fn" args "); }}\n"))) + " GC(td,&c1, buf, " n "); return; \\\n" + " } else { (_fn)(td," n ",(closure)_fn" args "); }}\n"))) (define (c-macro-closcall num-args) (let ((args (c-macro-n-prefix num-args ",a")) @@ -137,10 +137,10 @@ (n-1 (number->string (if (> num-args 0) (- num-args 1) 0))) (wrap (lambda (s) (if (> num-args 0) s "")))) (string-append - "#define closcall" n "(cfn" args ") " - (wrap (string-append "if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(" n-1 ", (closure)a1, cfn" (if (> num-args 1) (substring args 3 (string-length args)) "") "); }")) + "#define closcall" n "(td,cfn" args ") " + (wrap (string-append "if (type_of(cfn) == cons_tag || prim(cfn)) { Cyc_apply(td," n-1 ", (closure)a1, cfn" (if (> num-args 1) (substring args 3 (string-length args)) "") "); }")) (wrap " else { ") - "((cfn)->fn)(" n ",cfn" args ")" + "((cfn)->fn)(td," n ",cfn" args ")" (wrap ";}") ))) @@ -610,7 +610,7 @@ set-car! set-cdr! procedure? - set-cell!)) + set-cell!))) ;; Determine if primitive assigns (allocates) a C variable ;; EG: int v = prim(); @@ -713,6 +713,10 @@ "," cont "); ")) (else #f))) ;; END apply defs + (tdata (cond + ((prim/data-arg? p) "data ") + (else ""))) + (tdata-comma (if (> (string-length tdata) 0) "," "")) (c-var-assign (lambda (type) (let ((cv-name (mangle (gensym 'c)))) @@ -731,12 +735,16 @@ ;; Emit closure as first arg, if necessary (apply only) (cond (closure-def - (string-append "&" closure-sym + (string-append + tdata "," + "&" closure-sym (if (prim:cont-has-args? p) ", " ""))) ((prim:cont? p) - (string-append cont + (string-append + tdata "," + cont (if (prim:cont-has-args? p) ", " ""))) - (else ""))))))))) + (else tdata))))))))) (cond ((prim/c-var-assign p) (c-var-assign (prim/c-var-assign p))) @@ -753,9 +761,9 @@ cv-name ;; Already a pointer (string-append "&" cv-name)) ;; Point to data (list - (string-append c-func "(" cv-name))))) + (string-append c-func "(" cv-name tdata-comma tdata))))) (else - (c-code (string-append c-func "(")))))) + (c-code (string-append c-func "(" tdata tdata-comma)))))) ;; END primitives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -812,7 +820,7 @@ (string-append (c:allocs->str (c:allocs cgen)) "return_direct" (number->string num-cargs) - "(" this-cont + "(data," this-cont (if (> num-cargs 0) "," "") ; TODO: how to propagate continuation - cont " " (c:body cgen) ");")))) @@ -864,7 +872,7 @@ (c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cargs) "\n") "return_closcall" (number->string (c:num-args cargs)) - "(" + "(data," this-cont (if (> (c:num-args cargs) 0) "," "") (c:body cargs) @@ -883,7 +891,7 @@ (c:allocs->str (c:allocs cfun) "\n") (c:allocs->str (c:allocs cargs) "\n") "return_closcall" (number->string num-cargs) - "(" + "(data," this-cont (if (> num-cargs 0) "," "") (c:body cargs) @@ -1145,7 +1153,7 @@ (cons (lambda (name) (string-append "static void " name - "(int argc, " + "(void *data, int argc, " formals* ") {\n" preamble @@ -1231,7 +1239,7 @@ (lambda (l) (emit* "static void __lambda_" - (number->string (car l)) "(int argc, " + (number->string (car l)) "(void *data, int argc, " (cdadr l) ") ;")) lambdas) @@ -1247,14 +1255,14 @@ ; Emit entry point (cond (program? - (emit "static void c_entry_pt_first_lambda();") + (emit "static void c_entry_pt_first_lambda(void *data);") (for-each (lambda (lib-name) - (emit* "extern void c_" (lib:name->string lib-name) "_entry_pt(int argc, closure cont, object value);")) + (emit* "extern void c_" (lib:name->string lib-name) "_entry_pt(void *data, int argc, closure cont, object value);")) required-libs) - (emit "static void c_entry_pt(argc, env,cont) int argc; closure env,cont; { ")) + (emit "static void c_entry_pt(data, argc, env,cont) void *data; int argc; closure env,cont; { ")) (else - (emit* "void c_" (lib:name->string lib-name) "_entry_pt(argc, cont,value) int argc; closure cont; object value;{ ") + (emit* "void c_" (lib:name->string lib-name) "_entry_pt(data, argc, cont,value) void *data; int argc; closure cont; object value;{ ") ; DEBUG (emit (string-append "printf(\"init " (lib:name->string lib-name) "\\n\");")) )) @@ -1357,9 +1365,9 @@ (reverse required-libs)) ;; Init each lib's dependencies 1st (emit* ;; Start cont chain, but do not assume closcall1 macro was defined - "(" this-clo ".fn)(0, &" this-clo ", &" this-clo ");") + "(" this-clo ".fn)(data, 0, &" this-clo ", &" this-clo ");") (emit "}") - (emit "static void c_entry_pt_first_lambda(int argc, closure cont, object value) {") + (emit "static void c_entry_pt_first_lambda(void *data, int argc, closure cont, object value) {") ; DEBUG (emit (string-append "printf(\"init first lambda\\n\");")) (emit compiled-program))) (else @@ -1369,7 +1377,7 @@ (emit* "(((closure)" (mangle-global (lib:name->symbol lib-name)) - ")->fn)(1, cont, cont);") + ")->fn)(data, 1, cont, cont);") )) (emit "}") From ee5c79184d6c31190cee4eec6c68f9e1b6fbe9bd Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 23:14:30 -0500 Subject: [PATCH 099/339] Ease debugging --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6ca4e7fb..79e28006 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,7 @@ sld: .PHONY: debug debug: - cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ && cyclone cyclone.scm && sudo make install-includes && sudo make install-libs && ./cyclone generate-c.scm + sudo ls; cyclone scheme/cyclone/cgen.sld && sudo cp scheme/cyclone/cgen.* /usr/local/share/cyclone/scheme/cyclone/ && cyclone cyclone.scm && sudo make install-includes && sudo make install-libs && ./cyclone generate-c.scm ### cyclone scheme/cyclone/macros.sld && sudo cp scheme/cyclone/macros.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/macros.o /usr/local/share/cyclone/scheme/cyclone/ && \ ### cyclone scheme/cyclone/util.sld && sudo cp scheme/cyclone/util.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/util.o /usr/local/share/cyclone/scheme/cyclone/ && \ ### cyclone scheme/cyclone/transforms.sld && sudo cp scheme/cyclone/transforms.c /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.sld /usr/local/share/cyclone/scheme/cyclone/ && sudo cp scheme/cyclone/transforms.o /usr/local/share/cyclone/scheme/cyclone/ && \ From 95452007220a2c9f5b284615d8ded1802760f55e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 23:21:56 -0500 Subject: [PATCH 100/339] WIP --- scheme/cyclone/cgen.sld | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 65cfba86..997ee143 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -714,7 +714,7 @@ (else #f))) ;; END apply defs (tdata (cond - ((prim/data-arg? p) "data ") + ((prim/data-arg? p) "data") (else ""))) (tdata-comma (if (> (string-length tdata) 0) "," "")) (c-var-assign @@ -737,13 +737,11 @@ (closure-def (string-append tdata "," - "&" closure-sym - (if (prim:cont-has-args? p) ", " ""))) + "&" closure-sym)) ((prim:cont? p) (string-append tdata "," - cont - (if (prim:cont-has-args? p) ", " ""))) + cont)) (else tdata))))))))) (cond ((prim/c-var-assign p) @@ -763,7 +761,7 @@ (list (string-append c-func "(" cv-name tdata-comma tdata))))) (else - (c-code (string-append c-func "(" tdata tdata-comma)))))) + (c-code (string-append c-func "(" tdata)))))) ;; END primitives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -845,8 +843,19 @@ (c:allocs c-args*) ;; fun alloc depends upon arg allocs (list (string-append (car (c:allocs c-fun)) - (if (prim/c-var-assign fun) "" ",") ; Allocating C var - (c:body c-args*) ");")))) + (if (prim/c-var-assign fun) + ;; Add a comma if there were any args to the func + (let* ((fnc-str (car (c:allocs c-fun))) + (len (string-length fnc-str))) +(write (string-append "(JAE-DEBUG " fnc-str)) + (cond + ((and (> len 0) + (not (equal? "(" + (substring fnc-str (- len 1) len)))) + ",") + (else ""))) + ",") + (c:body c-args*) ");")))) ;; Args stay with body (c:append (c:append c-fun c-args*) @@ -1255,7 +1264,7 @@ ; Emit entry point (cond (program? - (emit "static void c_entry_pt_first_lambda(void *data);") + (emit "static void c_entry_pt_first_lambda(void *data, int argc, closure cont, object value);") (for-each (lambda (lib-name) (emit* "extern void c_" (lib:name->string lib-name) "_entry_pt(void *data, int argc, closure cont, object value);")) From 62b44d667a7d75a001b312e5a2e88e0870ec8f35 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 02:48:29 -0500 Subject: [PATCH 101/339] Add missing commas --- scheme/cyclone/cgen.sld | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 997ee143..f6401e19 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -693,6 +693,13 @@ (and (prim? exp) (member exp '()))) +;; Does string end with the given substring? +;; EG: ("test(" "(") ==> #t +(define (str-ending? str end) + (let ((len (string-length str))) + (and (> len 0) + (equal? end (substring str (- len 1) len))))) + ;; c-compile-prim : prim-exp -> string -> string (define (c-compile-prim p cont) (let* ((c-func (prim->c-func p)) @@ -847,7 +854,8 @@ ;; Add a comma if there were any args to the func (let* ((fnc-str (car (c:allocs c-fun))) (len (string-length fnc-str))) -(write (string-append "(JAE-DEBUG " fnc-str)) +;(write (string-append "(JAE-DEBUG " fnc-str)) +TODO: rewrite cond below in terms of (str-ending?) (cond ((and (> len 0) (not (equal? "(" @@ -858,7 +866,15 @@ (c:body c-args*) ");")))) ;; Args stay with body (c:append - (c:append c-fun c-args*) + (c:append + (let () +;(display "JAE DEBUG2: ") +;(write c-fun) + ;; Add a comma if necessary + (if (str-ending? (c:body c-fun) "(") + c-fun + (c:append c-fun (c-code ", ")))) + c-args*) (c-code ")"))))) ((equal? '%closure-ref fun) From 4905df626106f568a029441d6570e02f586bd20d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 02:49:07 -0500 Subject: [PATCH 102/339] Removed obsolete function --- scheme/cyclone/cgen.sld | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index f6401e19..3d7f7d3f 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -673,13 +673,6 @@ (member exp '(Cyc-read-line apply command-line-arguments number->string symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) -;; TODO: this is a hack, right answer is to include information about -;; how many args each primitive is supposed to take -(define (prim:cont-has-args? exp) - (and (prim? exp) - (member exp '(Cyc-read-line apply number->string symbol->string - list->string substring string-append - make-vector list->vector Cyc-installation-dir)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) From 2d68fde138c54549a77c636272db2cf530aaff4a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 20:55:27 -0500 Subject: [PATCH 103/339] Simplified code --- scheme/cyclone/cgen.sld | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 3d7f7d3f..69743427 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -844,25 +844,14 @@ (list (string-append (car (c:allocs c-fun)) (if (prim/c-var-assign fun) - ;; Add a comma if there were any args to the func - (let* ((fnc-str (car (c:allocs c-fun))) - (len (string-length fnc-str))) -;(write (string-append "(JAE-DEBUG " fnc-str)) -TODO: rewrite cond below in terms of (str-ending?) - (cond - ((and (> len 0) - (not (equal? "(" - (substring fnc-str (- len 1) len)))) - ",") - (else ""))) + ;; Add a comma if there were any args to the func added by comp-prim + (if (str-ending? (car (c:allocs c-fun)) "(") "" ",") ",") (c:body c-args*) ");")))) ;; Args stay with body (c:append (c:append (let () -;(display "JAE DEBUG2: ") -;(write c-fun) ;; Add a comma if necessary (if (str-ending? (c:body c-fun) "(") c-fun From 4e69bfb758ad75d4c90281236aad1f22e0868cff Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 22:02:57 -0500 Subject: [PATCH 104/339] Fix for functions with cont and no args --- scheme/cyclone/cgen.sld | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 69743427..c326cda1 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -674,6 +674,11 @@ symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) +;; Primitive functions that pass a continuation but have no other arguments +(define (prim:cont/no-args? exp) + (and (prim? exp) + (member exp '(command-line-arguments)))) + ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) (and (prim? exp) @@ -845,7 +850,10 @@ (car (c:allocs c-fun)) (if (prim/c-var-assign fun) ;; Add a comma if there were any args to the func added by comp-prim - (if (str-ending? (car (c:allocs c-fun)) "(") "" ",") + (if (or (str-ending? (car (c:allocs c-fun)) "(") + (prim:cont/no-args? fun)) + "" + ",") ",") (c:body c-args*) ");")))) ;; Args stay with body From 2b493b15f0947e3e3cd28df4e12931537d7c8019 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 22:26:33 -0500 Subject: [PATCH 105/339] Updated comment --- runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 219d81da..9c2fea1a 100644 --- a/runtime.c +++ b/runtime.c @@ -2743,7 +2743,7 @@ void GC(void *data, closure cont, object *args, int num_args) #endif } -//fprintf(stdout, "DEBUG, finished minor GC\n"); // JAE DEBUG + /* Let it all go, Neo... */ longjmp(jmp_main, (int)(&data)); // Return globals gc_cont, gc_ans } From c49044fce6d56a4b5e4e7fa17f73886996d05bcd Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 4 Nov 2015 23:02:28 -0500 Subject: [PATCH 106/339] Stub for migrating to gc struct --- gc.c | 9 +++++++++ include/cyclone/types.h | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/gc.c b/gc.c index 6b2da5bd..682b06c7 100644 --- a/gc.c +++ b/gc.c @@ -674,6 +674,15 @@ void gc_thread_data_init(gc_thread_data *thd) // TODO: } } +void gc_thread_data_free(gc_thread_data *thd) +{ + if (thd) { + if (thd->moveBuf) free(thd->moveBuf); + if (thd->mark_buffer) free(thd->mark_buffer); + free(thd); + } +} + //// Unit testing: //int main(int argc, char **argv) { // int a = 1, b = 2, c = 3, i; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 4cb0b5b8..9a38d798 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -22,6 +22,12 @@ typedef void *object; /* Thread data structures */ +typedef struct gc_thread_stack_t gc_thread_stack; +struct gc_thread_stack { + char *begin; + // TODO: move moveBuf stuff over here? +}; + typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { void **moveBuf; /* list of objects moved to heap during GC */ @@ -113,6 +119,7 @@ size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd); +void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); From 287f6608519a7a986ef17898a26daddb4b7d3e3a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 22:17:42 -0500 Subject: [PATCH 107/339] Moving stack limits away from global vars --- gc.c | 19 +++++++++++++++++-- include/cyclone/runtime-main.h | 2 +- include/cyclone/types.h | 16 +++++++--------- runtime.c | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index 682b06c7..1f9ccebe 100644 --- a/gc.c +++ b/gc.c @@ -657,9 +657,24 @@ void gc_empty_collector_stack() ///////////////////////////////////////////// -// Initialize a thread from scratch -void gc_thread_data_init(gc_thread_data *thd) +// Initialize runtime data structures for a thread. +// Must be called on the target thread itself during startup, +// to verify stack limits are setup correctly. +void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size) { + char stack_ref; + thd->stack_start = stack_base; +#if STACK_GROWS_DOWNWARD + thd->stack_limit = stack_base - stack_size; +#else + thd->stack_limit = stack_base + stack_size; +#endif + if (check_overflow(stack_base, &stack_ref)){ + fprintf(stderr, + "Error: recompile with STACK_GROWS_DOWNWARD set to %d\n", + (1 - STACK_GROWS_DOWNWARD)); + exit(1); + } thd->moveBufLen = 0; gc_thr_grow_move_buffer(thd); // TODO: depends on collector state: thd->gc_alloc_color = ATOMIC_GET(&gc_; diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index e189f067..da75c5b4 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -60,7 +60,7 @@ static void Cyc_main (stack_size,heap_size,stack_base) Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); //Cyc_heap = gc_heap_create(1024, 0, 0); Cyc_thread = malloc(sizeof(gc_thread_data)); - gc_thread_data_init(Cyc_thread); + gc_thread_data_init(Cyc_thread, stack_base, stack_size); // JAE TODO: clean up below (and all of this old code, really) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 9a38d798..88556bdd 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -22,17 +22,15 @@ typedef void *object; /* Thread data structures */ -typedef struct gc_thread_stack_t gc_thread_stack; -struct gc_thread_stack { - char *begin; - // TODO: move moveBuf stuff over here? -}; - typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { - void **moveBuf; /* list of objects moved to heap during GC */ + // Data needed for stack-based minor GC + char *stack_start; + char *stack_limit; + // List of objects moved to heap during minor GC + void **moveBuf; int moveBufLen; - // Data needed for tri-color marking + // Data needed for heap GC int gc_alloc_color; int gc_mut_status; int last_write; @@ -118,7 +116,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); -void gc_thread_data_init(gc_thread_data *thd); +void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size); void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mark_gray(gc_thread_data *thd, object obj); diff --git a/runtime.c b/runtime.c index 9c2fea1a..7b815a40 100644 --- a/runtime.c +++ b/runtime.c @@ -2594,7 +2594,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp, Cyc_thread, &alloci, &heap_grown); \ + (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown); \ } \ } @@ -2660,7 +2660,7 @@ void GC(void *data, closure cont, object *args, int num_args) // Check allocated objects, moving additional objects as needed while (scani < alloci) { - object obj = Cyc_thread->moveBuf[scani]; + object obj = ((gc_thread_data *)data)->moveBuf[scani]; switch(type_of(obj)) { case cons_tag: { gc_move2heap(car(obj)); From 6fb8d315972ff013dd8790e64b4e17f602efa310 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 23:00:30 -0500 Subject: [PATCH 108/339] Removed stack limit globals --- include/cyclone/runtime-main.h | 20 -------------------- include/cyclone/runtime.h | 3 --- runtime.c | 9 +++------ scheme/cyclone/cgen.sld | 4 ++-- 4 files changed, 5 insertions(+), 31 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index da75c5b4..a68c721b 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -23,25 +23,6 @@ static void Cyc_main (stack_size,heap_size,stack_base) mclosure0(clos_halt,&Cyc_halt); /* Halt program if final closure is reached */ gc_ans[0] = &clos_halt; gc_num_ans = 1; - /* Allocate stack buffer. */ - stack_begin = stack_base; -#if STACK_GROWS_DOWNWARD - stack_limit1 = stack_begin - stack_size; - stack_limit2 = stack_limit1 - 2000; -#else - stack_limit1 = stack_begin + stack_size; - stack_limit2 = stack_limit1 + 2000; -#endif -#if DEBUG_SHOW_DIAG - printf("main: sizeof(cons_type)=%ld\n",(long) sizeof(cons_type)); -#endif - if (check_overflow(stack_base,&in_my_frame)) - {printf("main: Recompile with STACK_GROWS_DOWNWARD set to %ld\n", - (long) (1-STACK_GROWS_DOWNWARD)); exit(0);} -#if DEBUG_SHOW_DIAG - printf("main: stack_size=%ld stack_base=%p stack_limit1=%p\n", - stack_size,(void *)stack_base,(void *)stack_limit1); -#endif /* Initialize stack trace table */ Cyc_st_init(); @@ -58,7 +39,6 @@ static void Cyc_main (stack_size,heap_size,stack_base) #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - //Cyc_heap = gc_heap_create(1024, 0, 0); Cyc_thread = malloc(sizeof(gc_thread_data)); gc_thread_data_init(Cyc_thread, stack_base, stack_size); diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index b531e1d4..63b98f1b 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -210,9 +210,6 @@ void do_dispatch(void *data, int argc, function_type func, object clo, object *b extern gc_heap *Cyc_heap; extern gc_thread_data *Cyc_thread; extern clock_t start; /* Starting time. */ -extern char *stack_begin; /* Initialized by main. */ -extern char *stack_limit1; /* Initialized by main. */ -extern char *stack_limit2; extern char *bottom; /* Bottom of tospace. */ extern char *allocp; /* Cheney allocate pointer. */ extern char *alloc_end; diff --git a/runtime.c b/runtime.c index 7b815a40..2f9f75e7 100644 --- a/runtime.c +++ b/runtime.c @@ -64,7 +64,7 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /* Return to continuation after checking for stack overflow. */ #define return_closcall1(td,cfn,a1) \ {char stack; \ - if (check_overflow(&stack,stack_limit1)) { \ + if (check_overflow(&stack,(((gc_thread_data *)data)->stack_limit))) { \ object buf[1]; buf[0] = a1;\ GC(td,cfn,buf,1); return; \ } else {closcall1(td,(closure) (cfn),a1); return;}} @@ -72,7 +72,7 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /* Return to continuation after checking for stack overflow. */ #define return_closcall2(td,cfn,a1,a2) \ {char stack; \ - if (check_overflow(&stack,stack_limit1)) { \ + if (check_overflow(&stack,(((gc_thread_data *)data)->stack_limit))) { \ object buf[2]; buf[0] = a1;buf[1] = a2;\ GC(td,cfn,buf,2); return; \ } else {closcall2(td,(closure) (cfn),a1,a2); return;}} @@ -82,9 +82,6 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { gc_heap *Cyc_heap; gc_thread_data *Cyc_thread; clock_t start; /* Starting time. */ -char *stack_begin; /* Initialized by main. */ -char *stack_limit1; /* Initialized by main. */ -char *stack_limit2; char *bottom; /* Bottom of tospace. */ char *allocp; /* Cheney allocate pointer. */ char *alloc_end; @@ -2603,7 +2600,7 @@ void GC(void *data, closure cont, object *args, int num_args) char tmp; object temp; object low_limit = &tmp; // This is one end of the stack... - object high_limit = stack_begin; // TODO: move to thread-specific struct + object high_limit = ((gc_thread_data *)data)->stack_start; int i; int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work int heap_grown = 0; diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index c326cda1..4fcc5ba3 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -112,7 +112,7 @@ "/* Check for GC, then call given continuation closure */\n" "#define return_closcall" n "(td,cfn" args ") \\\n" "{char stack; \\\n" - " if (check_overflow(&stack,stack_limit1)) { \\\n" + " if (check_overflow(&stack,(((gc_thread_data *)data)->stack_limit))) { \\\n" " object buf[" n "]; " arry-assign "\\\n" " GC(td,cfn,buf," n "); return; \\\n" " } else {closcall" n "(td,(closure) (cfn)" args "); return;}}\n"))) @@ -125,7 +125,7 @@ "/* Check for GC, then call C function directly */\n" "#define return_direct" n "(td,_fn" args ") { \\\n" " char stack; \\\n" - " if (check_overflow(&stack,stack_limit1)) { \\\n" + " if (check_overflow(&stack,(((gc_thread_data *)data)->stack_limit))) { \\\n" " object buf[" n "]; " arry-assign " \\\n" " mclosure0(c1, _fn); \\\n" " GC(td,&c1, buf, " n "); return; \\\n" From 7adc4f45861e19843a5f0b8eab36b67048d0b309 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 02:52:56 -0500 Subject: [PATCH 109/339] WIP --- include/cyclone/types.h | 30 +++++++++++++++++------------- runtime.c | 5 +++++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 88556bdd..54e30236 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -18,6 +18,19 @@ #include // TODO: #include +// Maximum number of args that GC will accept +#define NUM_GC_ANS 128 + +// Which way does the CPU grow its stack? +#define STACK_GROWS_DOWNWARD 1 + +// Size of the stack buffer, in bytes. +// This is used as the first generation of the GC. +#define STACK_SIZE 250000 + +// Size of a "page" on the heap (the 2nd generation), in bytes. +#define HEAP_SIZE 6000000 + /* Define general object type. */ typedef void *object; @@ -27,6 +40,10 @@ struct gc_thread_data_t { // Data needed for stack-based minor GC char *stack_start; char *stack_limit; +TODO: + object gc_cont; + object *gc_ans; //[NUM_GC_ANS]; + short gc_num_ans; // List of objects moved to heap during minor GC void **moveBuf; int moveBufLen; @@ -142,19 +159,6 @@ void gc_wait_handshake(); /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 -/* Maximum number of args that GC will accept */ -#define NUM_GC_ANS 128 - -/* Which way does the CPU grow its stack? */ -#define STACK_GROWS_DOWNWARD 1 - -/* Size of the stack buffer, in bytes. - This is used as the first generation of the GC. */ -#define STACK_SIZE 250000 - -/* Size of a "page" on the heap (the 2nd generation), in bytes. */ -#define HEAP_SIZE 6000000 - /* Define size of object tags */ typedef long tag_type; diff --git a/runtime.c b/runtime.c index 2f9f75e7..3527a3a4 100644 --- a/runtime.c +++ b/runtime.c @@ -81,6 +81,8 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /* Global variables. */ gc_heap *Cyc_heap; gc_thread_data *Cyc_thread; + +TODO: get rid of globals below that are not needed clock_t start; /* Starting time. */ char *bottom; /* Bottom of tospace. */ char *allocp; /* Cheney allocate pointer. */ @@ -92,8 +94,11 @@ char *dhbottom; /* Bottom of data heap */ char *dhallocp; /* Current place in data heap */ char *dhalloc_limit; /* GC beyond this limit */ char *dhalloc_end; + long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ + +TODO: after previous change, move these to thread data structure object gc_cont; /* GC continuation closure. */ object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ int gc_num_ans; From 19a4a9599cb5d3419a21d36ea88269345a813077 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 21:21:48 -0500 Subject: [PATCH 110/339] Move jmp_buf to thread data structure --- gc.c | 5 +++++ include/cyclone/runtime-main.h | 2 +- include/cyclone/runtime.h | 1 - include/cyclone/types.h | 4 ++-- runtime.c | 12 ++++++++---- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/gc.c b/gc.c index 1f9ccebe..fe6a8d75 100644 --- a/gc.c +++ b/gc.c @@ -675,6 +675,9 @@ void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size) (1 - STACK_GROWS_DOWNWARD)); exit(1); } + thd->jmp_start = malloc(sizeof(jmp_buf)); + thd->gc_ans = malloc(sizeof(object) * NUM_GC_ANS); + thd->gc_num_ans = 0; thd->moveBufLen = 0; gc_thr_grow_move_buffer(thd); // TODO: depends on collector state: thd->gc_alloc_color = ATOMIC_GET(&gc_; @@ -692,6 +695,8 @@ void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size) void gc_thread_data_free(gc_thread_data *thd) { if (thd) { + if (thd->jmp_start) free(thd->jmp_start); + if (thd->gc_ans) free(thd->gc_ans); if (thd->moveBuf) free(thd->moveBuf); if (thd->mark_buffer) free(thd->mark_buffer); free(thd); diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index a68c721b..0bc2cc76 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -60,7 +60,7 @@ static void Cyc_main (stack_size,heap_size,stack_base) start = clock(); /* Start the timing clock. */ /* Tank, load the jump program... */ - setjmp(jmp_main); + setjmp(*(Cyc_thread->jmp_start)); #if DEBUG_GC printf("Done with GC\n"); #endif diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 63b98f1b..c1568c6b 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -225,7 +225,6 @@ extern long no_major_gcs; /* Count the number of GC's. */ extern object gc_cont; /* GC continuation closure. */ extern object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ extern int gc_num_ans; -extern jmp_buf jmp_main; /* Where to jump to. */ /* Define Lisp constants we need. */ extern const object boolean_t; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 54e30236..fe8522a7 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -28,7 +28,7 @@ // This is used as the first generation of the GC. #define STACK_SIZE 250000 -// Size of a "page" on the heap (the 2nd generation), in bytes. +// Size of a "page" on the heap (the second generation), in bytes. #define HEAP_SIZE 6000000 /* Define general object type. */ @@ -40,7 +40,7 @@ struct gc_thread_data_t { // Data needed for stack-based minor GC char *stack_start; char *stack_limit; -TODO: + jmp_buf *jmp_start; object gc_cont; object *gc_ans; //[NUM_GC_ANS]; short gc_num_ans; diff --git a/runtime.c b/runtime.c index 3527a3a4..25a55c89 100644 --- a/runtime.c +++ b/runtime.c @@ -82,7 +82,7 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { gc_heap *Cyc_heap; gc_thread_data *Cyc_thread; -TODO: get rid of globals below that are not needed +//TODO: get rid of globals below that are not needed clock_t start; /* Starting time. */ char *bottom; /* Bottom of tospace. */ char *allocp; /* Cheney allocate pointer. */ @@ -98,11 +98,10 @@ char *dhalloc_end; long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ -TODO: after previous change, move these to thread data structure +//TODO: after previous change, move these to thread data structure object gc_cont; /* GC continuation closure. */ object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ int gc_num_ans; -jmp_buf jmp_main; /* Where to jump to. */ object Cyc_global_variables = nil; int _cyc_argc = 0; @@ -2746,7 +2745,12 @@ void GC(void *data, closure cont, object *args, int num_args) } /* Let it all go, Neo... */ - longjmp(jmp_main, (int)(&data)); // Return globals gc_cont, gc_ans + // TODO: apparently it is a bad idea to cast a pointer to an int on 64 bit platforms + // as a pointer may be larger than an int. so need to figure out another technique + // here to communicate back to the setjmp which data to use. need to store a data + // structure of thread buffers for heap gc, so maybe be able to use an int to index + // into that. + longjmp(*(((gc_thread_data *)data)->jmp_start), (int)(&data)); // Return globals gc_cont, gc_ans } From 8da3b29e89b8bafc522febdedefaa8906fa12305 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 21:57:22 -0500 Subject: [PATCH 111/339] Integrate gc_cont globals with thread data structure --- include/cyclone/runtime-main.h | 12 ++++++------ include/cyclone/runtime.h | 3 --- include/cyclone/types.h | 2 +- runtime.c | 12 ++++++------ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 0bc2cc76..9b2499b4 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -21,8 +21,6 @@ static void Cyc_main (stack_size,heap_size,stack_base) long stack_size,heap_size; char *stack_base; {char in_my_frame; mclosure0(clos_halt,&Cyc_halt); /* Halt program if final closure is reached */ - gc_ans[0] = &clos_halt; - gc_num_ans = 1; /* Initialize stack trace table */ Cyc_st_init(); @@ -30,7 +28,6 @@ static void Cyc_main (stack_size,heap_size,stack_base) { /* Setup first function to execute */ mclosure0(entry_pt,&c_entry_pt); - gc_cont = &entry_pt; /* Allocate heap area for second generation. */ /* Use calloc instead of malloc to assure pages are in main memory. */ @@ -42,6 +39,9 @@ static void Cyc_main (stack_size,heap_size,stack_base) Cyc_thread = malloc(sizeof(gc_thread_data)); gc_thread_data_init(Cyc_thread, stack_base, stack_size); + Cyc_thread->gc_cont = &entry_pt; + Cyc_thread->gc_ans[0] = &clos_halt; + Cyc_thread->gc_num_ans = 1; // JAE TODO: clean up below (and all of this old code, really) bottom = calloc(1,heap_size); @@ -66,10 +66,10 @@ static void Cyc_main (stack_size,heap_size,stack_base) #endif // JAE - note for the general case, setjmp will return the data pointer's addy - if (type_of(gc_cont) == cons_tag || prim(gc_cont)) { - Cyc_apply_from_buf(Cyc_thread, gc_num_ans, gc_cont, gc_ans); + if (type_of(Cyc_thread->gc_cont) == cons_tag || prim(Cyc_thread->gc_cont)) { + Cyc_apply_from_buf(Cyc_thread, Cyc_thread->gc_num_ans, Cyc_thread->gc_cont, Cyc_thread->gc_ans); } else { - do_dispatch(Cyc_thread, gc_num_ans, ((closure)gc_cont)->fn, gc_cont, gc_ans); + do_dispatch(Cyc_thread, Cyc_thread->gc_num_ans, ((closure)(Cyc_thread->gc_cont))->fn, Cyc_thread->gc_cont, Cyc_thread->gc_ans); } printf("Internal error: should never have reached this line\n"); exit(0);}} diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index c1568c6b..78a2a55f 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -222,9 +222,6 @@ extern char *dhalloc_limit; /* GC beyond this limit */ extern char *dhalloc_end; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ -extern object gc_cont; /* GC continuation closure. */ -extern object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ -extern int gc_num_ans; /* Define Lisp constants we need. */ extern const object boolean_t; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index fe8522a7..b86bf58e 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -42,7 +42,7 @@ struct gc_thread_data_t { char *stack_limit; jmp_buf *jmp_start; object gc_cont; - object *gc_ans; //[NUM_GC_ANS]; + object *gc_ans; short gc_num_ans; // List of objects moved to heap during minor GC void **moveBuf; diff --git a/runtime.c b/runtime.c index 25a55c89..282c5c69 100644 --- a/runtime.c +++ b/runtime.c @@ -99,9 +99,9 @@ long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ //TODO: after previous change, move these to thread data structure -object gc_cont; /* GC continuation closure. */ -object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ -int gc_num_ans; +//object gc_cont; /* GC continuation closure. */ +//object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ +//int gc_num_ans; object Cyc_global_variables = nil; int _cyc_argc = 0; @@ -2617,12 +2617,12 @@ void GC(void *data, closure cont, object *args, int num_args) } gc_move2heap(cont); - gc_cont = cont; - gc_num_ans = num_args; + ((gc_thread_data *)data)->gc_cont = cont; + ((gc_thread_data *)data)->gc_num_ans = num_args; for (i = 0; i < num_args; i++){ gc_move2heap(args[i]); - gc_ans[i] = args[i]; + ((gc_thread_data *)data)->gc_ans[i] = args[i]; } // Transport mutations From 23453d264b3f99058a1966ef1a6d9574e589b5b6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 5 Nov 2015 22:17:26 -0500 Subject: [PATCH 112/339] Removed unused globals --- include/cyclone/runtime-main.h | 16 ---------------- include/cyclone/runtime.h | 11 ----------- runtime.c | 19 ------------------- 3 files changed, 46 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 9b2499b4..2b5acc34 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -43,22 +43,6 @@ static void Cyc_main (stack_size,heap_size,stack_base) Cyc_thread->gc_ans[0] = &clos_halt; Cyc_thread->gc_num_ans = 1; - // JAE TODO: clean up below (and all of this old code, really) - bottom = calloc(1,heap_size); - allocp = (char *) ((((long) bottom)+7) & -8); - alloc_end = allocp + heap_size - 8; - - dhallocp = dhbottom = calloc(1, heap_size); - dhalloc_limit = dhallocp + (long)((heap_size - 8) * 0.90); - dhalloc_end = dhallocp + heap_size - 8; -#if DEBUG_SHOW_DIAG - printf("main: heap_size=%ld allocp=%p alloc_end=%p\n", - (long) heap_size,(void *)allocp,(void *)alloc_end); - printf("main: Try a larger heap_size if program bombs.\n"); - printf("Starting...\n"); -#endif - start = clock(); /* Start the timing clock. */ - /* Tank, load the jump program... */ setjmp(*(Cyc_thread->jmp_start)); #if DEBUG_GC diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 78a2a55f..9af39714 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -209,17 +209,6 @@ void do_dispatch(void *data, int argc, function_type func, object clo, object *b /* Global variables. */ extern gc_heap *Cyc_heap; extern gc_thread_data *Cyc_thread; -extern clock_t start; /* Starting time. */ -extern char *bottom; /* Bottom of tospace. */ -extern char *allocp; /* Cheney allocate pointer. */ -extern char *alloc_end; -/* TODO: not sure this is the best strategy for strings, especially if there - are a lot of long, later gen strings because that will cause a lot of - copying to occur during GC */ -extern char *dhbottom; /* Bottom of data heap */ -extern char *dhallocp; /* Current place in data heap */ -extern char *dhalloc_limit; /* GC beyond this limit */ -extern char *dhalloc_end; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ diff --git a/runtime.c b/runtime.c index 282c5c69..651598dc 100644 --- a/runtime.c +++ b/runtime.c @@ -81,28 +81,9 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /* Global variables. */ gc_heap *Cyc_heap; gc_thread_data *Cyc_thread; - -//TODO: get rid of globals below that are not needed -clock_t start; /* Starting time. */ -char *bottom; /* Bottom of tospace. */ -char *allocp; /* Cheney allocate pointer. */ -char *alloc_end; -/* TODO: not sure this is the best strategy for strings, especially if there - are a lot of long, later gen strings because that will cause a lot of - copying to occur during GC */ -char *dhbottom; /* Bottom of data heap */ -char *dhallocp; /* Current place in data heap */ -char *dhalloc_limit; /* GC beyond this limit */ -char *dhalloc_end; - long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ -//TODO: after previous change, move these to thread data structure -//object gc_cont; /* GC continuation closure. */ -//object gc_ans[NUM_GC_ANS]; /* argument for GC continuation closure. */ -//int gc_num_ans; - object Cyc_global_variables = nil; int _cyc_argc = 0; char **_cyc_argv = NULL; From 9219279613537a350e6a404806cd962561fcab92 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 20:28:27 -0500 Subject: [PATCH 113/339] Use mutator number instead of casting pointer to an int --- gc.c | 3 ++- include/cyclone/runtime-main.h | 28 +++++++++++++++++++--------- include/cyclone/runtime.h | 3 ++- include/cyclone/types.h | 4 +++- runtime.c | 11 ++++------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/gc.c b/gc.c index fe6a8d75..ad0f5bf4 100644 --- a/gc.c +++ b/gc.c @@ -660,7 +660,7 @@ void gc_empty_collector_stack() // Initialize runtime data structures for a thread. // Must be called on the target thread itself during startup, // to verify stack limits are setup correctly. -void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size) +void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size) { char stack_ref; thd->stack_start = stack_base; @@ -675,6 +675,7 @@ void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size) (1 - STACK_GROWS_DOWNWARD)); exit(1); } + thd->mutator_num = mut_num; thd->jmp_start = malloc(sizeof(jmp_buf)); thd->gc_ans = malloc(sizeof(object) * NUM_GC_ANS); thd->gc_num_ans = 0; diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 2b5acc34..502fc306 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -36,24 +36,34 @@ static void Cyc_main (stack_size,heap_size,stack_base) #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - Cyc_thread = malloc(sizeof(gc_thread_data)); - gc_thread_data_init(Cyc_thread, stack_base, stack_size); + Cyc_num_mutators = 1; // TODO: alloca this using a vpbuffer, or maybe another type of data structure + Cyc_mutators = malloc(sizeof(gc_thread_data *) * Cyc_num_mutators); + +// TODO: from here, break this out into a separate function that +// could spin up additional threads +// would need mutator_num, stack args. +// don't want to waste stack space though, so maybe inits above +// get moved to the caller of Cyc_main, and Cyc_main becomes +// that separate function +// int mutator_num = 0; + Cyc_mutators[0] = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(Cyc_mutators[0], 0, stack_base, stack_size); - Cyc_thread->gc_cont = &entry_pt; - Cyc_thread->gc_ans[0] = &clos_halt; - Cyc_thread->gc_num_ans = 1; + Cyc_mutators[0]->gc_cont = &entry_pt; + Cyc_mutators[0]->gc_ans[0] = &clos_halt; + Cyc_mutators[0]->gc_num_ans = 1; /* Tank, load the jump program... */ - setjmp(*(Cyc_thread->jmp_start)); + setjmp(*(Cyc_mutators[0]->jmp_start)); #if DEBUG_GC printf("Done with GC\n"); #endif // JAE - note for the general case, setjmp will return the data pointer's addy - if (type_of(Cyc_thread->gc_cont) == cons_tag || prim(Cyc_thread->gc_cont)) { - Cyc_apply_from_buf(Cyc_thread, Cyc_thread->gc_num_ans, Cyc_thread->gc_cont, Cyc_thread->gc_ans); + if (type_of(Cyc_mutators[0]->gc_cont) == cons_tag || prim(Cyc_mutators[0]->gc_cont)) { + Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_ans); } else { - do_dispatch(Cyc_thread, Cyc_thread->gc_num_ans, ((closure)(Cyc_thread->gc_cont))->fn, Cyc_thread->gc_cont, Cyc_thread->gc_ans); + do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_ans); } printf("Internal error: should never have reached this line\n"); exit(0);}} diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 9af39714..3b2533f6 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -208,7 +208,8 @@ void do_dispatch(void *data, int argc, function_type func, object clo, object *b /* Global variables. */ extern gc_heap *Cyc_heap; -extern gc_thread_data *Cyc_thread; +extern gc_thread_data **Cyc_mutators; +extern int Cyc_num_mutators; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index b86bf58e..b081432d 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -40,6 +40,8 @@ struct gc_thread_data_t { // Data needed for stack-based minor GC char *stack_start; char *stack_limit; + // Need the following to perform longjmp's + int mutator_num; jmp_buf *jmp_start; object gc_cont; object *gc_ans; @@ -133,7 +135,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); -void gc_thread_data_init(gc_thread_data *thd, char *stack_base, long stack_size); +void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mark_gray(gc_thread_data *thd, object obj); diff --git a/runtime.c b/runtime.c index 651598dc..5b7b26f6 100644 --- a/runtime.c +++ b/runtime.c @@ -80,7 +80,8 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /* Global variables. */ gc_heap *Cyc_heap; -gc_thread_data *Cyc_thread; +gc_thread_data **Cyc_mutators; +int Cyc_num_mutators; long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ @@ -2726,12 +2727,8 @@ void GC(void *data, closure cont, object *args, int num_args) } /* Let it all go, Neo... */ - // TODO: apparently it is a bad idea to cast a pointer to an int on 64 bit platforms - // as a pointer may be larger than an int. so need to figure out another technique - // here to communicate back to the setjmp which data to use. need to store a data - // structure of thread buffers for heap gc, so maybe be able to use an int to index - // into that. - longjmp(*(((gc_thread_data *)data)->jmp_start), (int)(&data)); // Return globals gc_cont, gc_ans + longjmp(*(((gc_thread_data *)data)->jmp_start), + (((gc_thread_data *)data)->mutator_num)); } From 70645643ca9e76b5647a04991d2f09875a23eff9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 20:29:50 -0500 Subject: [PATCH 114/339] Added TODO --- include/cyclone/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index b081432d..045fc35a 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -40,6 +40,7 @@ struct gc_thread_data_t { // Data needed for stack-based minor GC char *stack_start; char *stack_limit; +//TODO: store stack traces per thread // Need the following to perform longjmp's int mutator_num; jmp_buf *jmp_start; From 32465d5da8230c8dc2ee8e0cd9c480d98eea9207 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 22:31:31 -0500 Subject: [PATCH 115/339] Renamed minor GC args vars to be consistent with GC code --- gc.c | 6 +++--- include/cyclone/runtime-main.h | 8 ++++---- include/cyclone/types.h | 15 ++++++++------- runtime.c | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/gc.c b/gc.c index ad0f5bf4..1e116677 100644 --- a/gc.c +++ b/gc.c @@ -677,8 +677,8 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon } thd->mutator_num = mut_num; thd->jmp_start = malloc(sizeof(jmp_buf)); - thd->gc_ans = malloc(sizeof(object) * NUM_GC_ANS); - thd->gc_num_ans = 0; + thd->gc_args = malloc(sizeof(object) * NUM_GC_ANS); + thd->gc_num_args = 0; thd->moveBufLen = 0; gc_thr_grow_move_buffer(thd); // TODO: depends on collector state: thd->gc_alloc_color = ATOMIC_GET(&gc_; @@ -697,7 +697,7 @@ void gc_thread_data_free(gc_thread_data *thd) { if (thd) { if (thd->jmp_start) free(thd->jmp_start); - if (thd->gc_ans) free(thd->gc_ans); + if (thd->gc_args) free(thd->gc_args); if (thd->moveBuf) free(thd->moveBuf); if (thd->mark_buffer) free(thd->mark_buffer); free(thd); diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 502fc306..15be2636 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -50,8 +50,8 @@ static void Cyc_main (stack_size,heap_size,stack_base) gc_thread_data_init(Cyc_mutators[0], 0, stack_base, stack_size); Cyc_mutators[0]->gc_cont = &entry_pt; - Cyc_mutators[0]->gc_ans[0] = &clos_halt; - Cyc_mutators[0]->gc_num_ans = 1; + Cyc_mutators[0]->gc_args[0] = &clos_halt; + Cyc_mutators[0]->gc_num_args = 1; /* Tank, load the jump program... */ setjmp(*(Cyc_mutators[0]->jmp_start)); @@ -61,9 +61,9 @@ static void Cyc_main (stack_size,heap_size,stack_base) // JAE - note for the general case, setjmp will return the data pointer's addy if (type_of(Cyc_mutators[0]->gc_cont) == cons_tag || prim(Cyc_mutators[0]->gc_cont)) { - Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_ans); + Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); } else { - do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_ans); + do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); } printf("Internal error: should never have reached this line\n"); exit(0);}} diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 045fc35a..6cbdfde4 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -37,19 +37,20 @@ typedef void *object; /* Thread data structures */ typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { - // Data needed for stack-based minor GC + // Data needed to initiate stack-based minor GC char *stack_start; char *stack_limit; //TODO: store stack traces per thread - // Need the following to perform longjmp's - int mutator_num; - jmp_buf *jmp_start; - object gc_cont; - object *gc_ans; - short gc_num_ans; // List of objects moved to heap during minor GC void **moveBuf; int moveBufLen; + // Need the following to perform longjmp's + int mutator_num; + jmp_buf *jmp_start; + // After longjmp, pick up execution using continuation/arguments + object gc_cont; + object *gc_args; + short gc_num_args; // Data needed for heap GC int gc_alloc_color; int gc_mut_status; diff --git a/runtime.c b/runtime.c index 5b7b26f6..eb2f2b15 100644 --- a/runtime.c +++ b/runtime.c @@ -2600,11 +2600,11 @@ void GC(void *data, closure cont, object *args, int num_args) gc_move2heap(cont); ((gc_thread_data *)data)->gc_cont = cont; - ((gc_thread_data *)data)->gc_num_ans = num_args; + ((gc_thread_data *)data)->gc_num_args = num_args; for (i = 0; i < num_args; i++){ gc_move2heap(args[i]); - ((gc_thread_data *)data)->gc_ans[i] = args[i]; + ((gc_thread_data *)data)->gc_args[i] = args[i]; } // Transport mutations From 4f3a7f4b5bd39c24b79b665acc6e6b2266e35cfe Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 22:32:45 -0500 Subject: [PATCH 116/339] Missed these --- include/cyclone/runtime-main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 15be2636..43193da3 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -61,9 +61,9 @@ static void Cyc_main (stack_size,heap_size,stack_base) // JAE - note for the general case, setjmp will return the data pointer's addy if (type_of(Cyc_mutators[0]->gc_cont) == cons_tag || prim(Cyc_mutators[0]->gc_cont)) { - Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); + Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_args, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); } else { - do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_ans, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); + do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_args, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); } printf("Internal error: should never have reached this line\n"); exit(0);}} From 5fd25f977fbd7694647efa20b2fe976df73aa073 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 7 Nov 2015 02:56:38 -0500 Subject: [PATCH 117/339] Do a separate heap init on startup --- include/cyclone/runtime-main.h | 40 +++++++++++++++------------------- scheme/cyclone/cgen.sld | 3 ++- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 43193da3..da0c5b86 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -15,37 +15,28 @@ long global_stack_size = 0; long global_heap_size = 0; static void c_entry_pt(void *,int,closure,closure); -static void Cyc_main(long stack_size,long heap_size,char *stack_base); +static void Cyc_main(long stack_size, char *stack_base); +static void Cyc_heap_init(long heap_size); -static void Cyc_main (stack_size,heap_size,stack_base) - long stack_size,heap_size; char *stack_base; -{char in_my_frame; - mclosure0(clos_halt,&Cyc_halt); /* Halt program if final closure is reached */ - - /* Initialize stack trace table */ - Cyc_st_init(); - - { - /* Setup first function to execute */ - mclosure0(entry_pt,&c_entry_pt); +static void Cyc_heap_init(long heap_size) +{ + /* Initialize stack trace table + TODO: will eventually be relocated to a per-thread operation */ + Cyc_st_init(); /* Allocate heap area for second generation. */ - /* Use calloc instead of malloc to assure pages are in main memory. */ #if DEBUG_SHOW_DIAG printf("main: Allocating and initializing heap...\n"); #endif - Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - Cyc_num_mutators = 1; // TODO: alloca this using a vpbuffer, or maybe another type of data structure Cyc_mutators = malloc(sizeof(gc_thread_data *) * Cyc_num_mutators); + Cyc_num_mutators = 1; // TODO: alloca this using a vpbuffer, or maybe another type of data structure +} -// TODO: from here, break this out into a separate function that -// could spin up additional threads -// would need mutator_num, stack args. -// don't want to waste stack space though, so maybe inits above -// get moved to the caller of Cyc_main, and Cyc_main becomes -// that separate function -// int mutator_num = 0; +static void Cyc_main (long stack_size, char *stack_base) +{ + mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached + mclosure0(entry_pt,&c_entry_pt); // First function to execute Cyc_mutators[0] = malloc(sizeof(gc_thread_data)); gc_thread_data_init(Cyc_mutators[0], 0, stack_base, stack_size); @@ -55,6 +46,8 @@ static void Cyc_main (stack_size,heap_size,stack_base) /* Tank, load the jump program... */ setjmp(*(Cyc_mutators[0]->jmp_start)); +// TODO: note, if longjmp is passed 0 it will return 1. need to +// account for that there (add one to mut_num) and here (subtract 1 unless 0) #if DEBUG_GC printf("Done with GC\n"); #endif @@ -66,6 +59,7 @@ static void Cyc_main (stack_size,heap_size,stack_base) do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_args, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); } - printf("Internal error: should never have reached this line\n"); exit(0);}} + printf("Internal error: should never have reached this line\n"); exit(0); +} #endif /* CYCLONE_RUNTIME_MAIN_H */ diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 4fcc5ba3..7fac33dd 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -78,7 +78,8 @@ long heap_size = global_heap_size = HEAP_SIZE; _cyc_argc = argc; _cyc_argv = argv; - Cyc_main(stack_size,heap_size,(char *) &stack_size); + Cyc_heap_init(heap_size); + Cyc_main(stack_size, (char *) &stack_size); return 0;}") ;;; Auto-generation of C macros From e1063c4e19a87aa94ef4ce858fa92655572e0f4d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 7 Nov 2015 02:57:55 -0500 Subject: [PATCH 118/339] Added TODO --- include/cyclone/runtime-main.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index da0c5b86..5bd1d7ed 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -33,6 +33,9 @@ static void Cyc_heap_init(long heap_size) Cyc_num_mutators = 1; // TODO: alloca this using a vpbuffer, or maybe another type of data structure } +TODO: relocate this to a runtime function (that accepts gc_thread_data and does the setjmp/dispatch, and +to cgen (to setup a new gc_thread_data and call to the new function) + static void Cyc_main (long stack_size, char *stack_base) { mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached From 33abfc3bfa88670039d37d5a42879c305d25f8a5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 21:28:12 -0500 Subject: [PATCH 119/339] Relocate setjmp code to runtime --- gc.c | 2 +- include/cyclone/runtime-main.h | 35 +--------------------------------- include/cyclone/runtime.h | 3 ++- include/cyclone/types.h | 2 +- runtime.c | 22 +++++++++++++++++++-- scheme/cyclone/cgen.sld | 9 ++++++++- 6 files changed, 33 insertions(+), 40 deletions(-) diff --git a/gc.c b/gc.c index 1e116677..4fd5bdd0 100644 --- a/gc.c +++ b/gc.c @@ -675,7 +675,7 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon (1 - STACK_GROWS_DOWNWARD)); exit(1); } - thd->mutator_num = mut_num; + //thd->mutator_num = mut_num; thd->jmp_start = malloc(sizeof(jmp_buf)); thd->gc_args = malloc(sizeof(object) * NUM_GC_ANS); thd->gc_num_args = 0; diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 5bd1d7ed..bdc098e9 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -15,7 +15,6 @@ long global_stack_size = 0; long global_heap_size = 0; static void c_entry_pt(void *,int,closure,closure); -static void Cyc_main(long stack_size, char *stack_base); static void Cyc_heap_init(long heap_size); static void Cyc_heap_init(long heap_size) @@ -29,40 +28,8 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); + Cyc_num_mutators = 10; // TODO: alloca this using a vpbuffer, or maybe another type of data structure Cyc_mutators = malloc(sizeof(gc_thread_data *) * Cyc_num_mutators); - Cyc_num_mutators = 1; // TODO: alloca this using a vpbuffer, or maybe another type of data structure -} - -TODO: relocate this to a runtime function (that accepts gc_thread_data and does the setjmp/dispatch, and -to cgen (to setup a new gc_thread_data and call to the new function) - -static void Cyc_main (long stack_size, char *stack_base) -{ - mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached - mclosure0(entry_pt,&c_entry_pt); // First function to execute - Cyc_mutators[0] = malloc(sizeof(gc_thread_data)); - gc_thread_data_init(Cyc_mutators[0], 0, stack_base, stack_size); - - Cyc_mutators[0]->gc_cont = &entry_pt; - Cyc_mutators[0]->gc_args[0] = &clos_halt; - Cyc_mutators[0]->gc_num_args = 1; - - /* Tank, load the jump program... */ - setjmp(*(Cyc_mutators[0]->jmp_start)); -// TODO: note, if longjmp is passed 0 it will return 1. need to -// account for that there (add one to mut_num) and here (subtract 1 unless 0) -#if DEBUG_GC - printf("Done with GC\n"); -#endif - -// JAE - note for the general case, setjmp will return the data pointer's addy - if (type_of(Cyc_mutators[0]->gc_cont) == cons_tag || prim(Cyc_mutators[0]->gc_cont)) { - Cyc_apply_from_buf(Cyc_mutators[0], Cyc_mutators[0]->gc_num_args, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); - } else { - do_dispatch(Cyc_mutators[0], Cyc_mutators[0]->gc_num_args, ((closure)(Cyc_mutators[0]->gc_cont))->fn, Cyc_mutators[0]->gc_cont, Cyc_mutators[0]->gc_args); - } - - printf("Internal error: should never have reached this line\n"); exit(0); } #endif /* CYCLONE_RUNTIME_MAIN_H */ diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 3b2533f6..45968c1a 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -181,7 +181,8 @@ object get(object,object); object equalp(object,object); object memberp(void *,object,list); object memqp(void *,object,list); -char *transport(char *,int); + +void Cyc_start_thread(gc_thread_data *thd); void GC(void *,closure,object*,int); void Cyc_st_init(); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 6cbdfde4..2432cd11 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -45,7 +45,7 @@ struct gc_thread_data_t { void **moveBuf; int moveBufLen; // Need the following to perform longjmp's - int mutator_num; + //int mutator_num; jmp_buf *jmp_start; // After longjmp, pick up execution using continuation/arguments object gc_cont; diff --git a/runtime.c b/runtime.c index eb2f2b15..6df073cf 100644 --- a/runtime.c +++ b/runtime.c @@ -2343,6 +2343,25 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} +void Cyc_start_thread(gc_thread_data *thd) +{ + /* Tank, load the jump program... */ + setjmp(*(thd->jmp_start)); + +#if DEBUG_GC + printf("Done with GC\n"); +#endif + + if (type_of(thd->gc_cont) == cons_tag || prim(thd->gc_cont)) { + Cyc_apply_from_buf(thd, thd->gc_num_args, thd->gc_cont, thd->gc_args); + } else { + do_dispatch(thd, thd->gc_num_args, ((closure)(thd->gc_cont))->fn, thd->gc_cont, thd->gc_args); + } + + printf("Internal error: should never have reached this line\n"); + exit(0); +} + // Collect garbage using mark&sweep algorithm // Note non-global roots should be marked prior to calling this function. size_t gc_collect(gc_heap *h, size_t *sum_freed) @@ -2727,8 +2746,7 @@ void GC(void *data, closure cont, object *args, int num_args) } /* Let it all go, Neo... */ - longjmp(*(((gc_thread_data *)data)->jmp_start), - (((gc_thread_data *)data)->mutator_num)); + longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 7fac33dd..00e936f9 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -76,10 +76,17 @@ "main(int argc,char **argv) {long stack_size = global_stack_size = STACK_SIZE; long heap_size = global_heap_size = HEAP_SIZE; + mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached + mclosure0(entry_pt,&c_entry_pt); // First function to execute _cyc_argc = argc; _cyc_argv = argv; Cyc_heap_init(heap_size); - Cyc_main(stack_size, (char *) &stack_size); + Cyc_mutators[0] = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(Cyc_mutators[0], 0, (char *) &stack_size, stack_size); + Cyc_mutators[0]->gc_cont = &entry_pt; + Cyc_mutators[0]->gc_args[0] = &clos_halt; + Cyc_mutators[0]->gc_num_args = 1; + Cyc_start_thread(Cyc_mutators[0]); return 0;}") ;;; Auto-generation of C macros From fdc33e88afeeef0a8795363104974878e04fb7f0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 22:02:31 -0500 Subject: [PATCH 120/339] Cleanup --- include/cyclone/runtime-main.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index bdc098e9..7fb99c6a 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -28,8 +28,12 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - Cyc_num_mutators = 10; // TODO: alloca this using a vpbuffer, or maybe another type of data structure - Cyc_mutators = malloc(sizeof(gc_thread_data *) * Cyc_num_mutators); + // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? + // Will need this list for later use, but only by the collector thread. so it would be + // nice if there was a way to allocate mutators that avoids expensive synchronization... + // need to think on this when adding thread support, after upgrading the collector + Cyc_num_mutators = 1; + Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); } #endif /* CYCLONE_RUNTIME_MAIN_H */ From 24605735349539f2d37f19e8bd22ea8473c53bee Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 6 Nov 2015 23:21:13 -0500 Subject: [PATCH 121/339] Added GC4 --- gc-notes.txt | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index fd50c895..e4418e97 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -1,38 +1,4 @@ Phase 1 (gc-dev) - Add gc.h, make sure it compiles. Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and be compatible with a new GC algorithm. Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. - - -Notes for adding new thread data param -- primitives that will now need to accept the param: - ((eq? p 'Cyc-write-char) "Cyc_write_char") - Cyc_vector_set - Cyc_vector_ref - Cyc_vector_length(void *data, object v) { - Cyc_length - Cyc_number2string(void *data, object cont, object n) { -object Cyc_symbol2string(object cont, object sym) { -object Cyc_list2string(void *data, object cont, object lst){ -#define Cyc_string_append_va_list(data, argc) { \ -object Cyc_string_set(object str, object k, object chr) { -object Cyc_string_ref(void *data, object str, object k) { -object Cyc_substring(void *data, object cont, object str, object start, object end) { -object Cyc_installation_dir(object cont, object type) { -object Cyc_command_line_arguments(object cont) { -object Cyc_make_vector(object cont, object len, object fill) { -object Cyc_list2vector(void *data, object cont, object l) { -declare_num_op(Cyc_sum, Cyc_sum_op, dispatch_sum, +, 0); -declare_num_op(Cyc_sub, Cyc_sub_op, dispatch_sub, -, 0); -declare_num_op(Cyc_mul, Cyc_mul_op, dispatch_mul, *, 0); -declare_num_op(Cyc_div, Cyc_div_op, dispatch_div, /, 1); -port_type Cyc_io_open_input_file(void *data, object str) { -port_type Cyc_io_open_output_file(void *data, object str) { -object Cyc_io_read_line(void *data, object cont, object port) { - -- plan: - - update runtime, get it to compile - - have not adjusted any code that checks value of argc, will probably need to do that - EG for Cyc_num_op_va_list - - update any associated tools (dispatch.c, etc) - - update cgen - - integration +Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. From 2b2a96c84d14c872835638f068b5cf0997abbe03 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 9 Nov 2015 22:25:17 -0500 Subject: [PATCH 122/339] Relocate mutator data structure to gc module --- gc.c | 80 +++++++++++++++------------------- include/cyclone/runtime-main.h | 7 +-- include/cyclone/runtime.h | 2 - include/cyclone/types.h | 5 ++- 4 files changed, 38 insertions(+), 56 deletions(-) diff --git a/gc.c b/gc.c index 4fd5bdd0..72f7dd44 100644 --- a/gc.c +++ b/gc.c @@ -12,6 +12,19 @@ #include "cyclone/types.h" +static gc_thread_data **Cyc_mutators; +static int Cyc_num_mutators; + +void gc_init_mutators() +{ + // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? + // Will need this list for later use, but only by the collector thread. so it would be + // nice if there was a way to allocate mutators that avoids expensive synchronization... + // need to think on this when adding thread support, after upgrading the collector + Cyc_num_mutators = 1; + Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); +} + gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) { gc_free_list *free, *next; @@ -488,63 +501,38 @@ void gc_mark_gray(gc_thread_data *thd, object obj) // either object type or mark. Both should be stable once the object is placed // into the heap, with the collector being the only thread that changes marks. if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? -//TODO: // TODO: lock mark buffer (not ideal, but a possible first step)? -//TODO: pthread_mutex_lock(&(thd->lock)); -//TODO: thd->mark_buffer = vpbuffer_add(thd->mark_buffer, -//TODO: &(thd->mark_buffer_len), -//TODO: thd->last_write, -//TODO: obj); -//TODO: pthread_mutex_unlock(&(thd->lock)); -//TODO: ATOMIC_INC(&(thd->last_write)); + // Place marked object in a buffer to avoid repeated scans of the heap. +// TODO: +// Note that ideally this should be a lock-free data structure to make the +// algorithm more efficient. So this code (and the corresponding collector +// trace code) should be converted at some point. + pthread_mutex_lock(&(thd->lock)); + thd->mark_buffer = vpbuffer_add(thd->mark_buffer, + &(thd->mark_buffer_len), + thd->last_write, + obj); + (thd->last_write)++; // Already locked, just do it... + pthread_mutex_unlock(&(thd->lock)); } } void gc_collector_trace() { - int clean = 0; -// while (!clean) { -// clean = 1; -// } -// TODO: need a list of mutators. -// could keep a buffer or linked list of them. a list may be more efficient -// also need to consider how to map thread back to its gc_thread_data, -// which we will need during GC (cooperate). maybe use a (platform-specific) -// call like below to get a unique ID for the thread, and then use a -// hashtable to get the thread info. how often will we be accessing this data? -// seems we will need to be able to access it from 2 places: -// - from mutator (can compute thread id here) -// - from collector (need to be able to iterate across all mutators) -// #include -// printf("tid = %d\n", syscall(SYS_gettid)); -// -// TODO: -// ACTION - I think the most efficient solution is to have each thread pass around -// the pointer to it's thread data. this param would have to be passed to all -// continuation calls made by the thread. -// the collector/runtime will need to maintain a list of the thread data structures, -// and will need to maintain it when a thread is created or terminated (either -// explicitly or when it returns). -// practically the required changes are: -// - stabilize this branch so it builds and runs (hope this just means commenting out -// the pthread calls for right now) -// - extend the runtime and compiled code to have a new thread_data (sp?) param -// also need to judge if there are issues that would prevent being able to add -// one, but it seems like it should be no problem -// - build the code and test that the value is actually maintained across calls -// (maybe assign it to a global at start and exit from GC if cur val != global val) - -// note - can atomic operations be used for last read/write, to prevent -// coarser-grained synchronization there? -// TODO: -// clean = FALSE -// while (!(clean)) -// clean = TRUE + int clean = 0, i; + while (!clean) { + clean = 1; + // TODO: need to sync access to mutator int/void data, UNLESS + // the collector thread is the only one that is using these + // fields. + for (i = 0; i < Cyc_num_mutators; i++) { + } // For each m in mutators // while (lastread[m] < lastwrite[m]) // TODO: use atomic sub to compare? // clean = FALSE // lastread[m] = lastread[m] + 1 // TODO: atomic increment // markBlack(markbuffer[m][lastread[m]]) // EmptyCollectorStack() + } } // TODO: seriously consider changing the mark() macro to color(), diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 7fb99c6a..9f7edf8e 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -28,12 +28,7 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? - // Will need this list for later use, but only by the collector thread. so it would be - // nice if there was a way to allocate mutators that avoids expensive synchronization... - // need to think on this when adding thread support, after upgrading the collector - Cyc_num_mutators = 1; - Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); + gc_init_mutators(); } #endif /* CYCLONE_RUNTIME_MAIN_H */ diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 45968c1a..4b0232eb 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -209,8 +209,6 @@ void do_dispatch(void *data, int argc, function_type func, object clo, object *b /* Global variables. */ extern gc_heap *Cyc_heap; -extern gc_thread_data **Cyc_mutators; -extern int Cyc_num_mutators; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 2432cd11..330fb5d0 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -16,7 +16,7 @@ #include #include #include -// TODO: #include +#include // Maximum number of args that GC will accept #define NUM_GC_ANS 128 @@ -58,7 +58,7 @@ struct gc_thread_data_t { int last_read; void **mark_buffer; int mark_buffer_len; -// TODO: pthread_mutex_t lock; + pthread_mutex_t lock; }; /* GC data structures */ @@ -125,6 +125,7 @@ void **vpbuffer_add(void **buf, int *len, int i, void *obj); void vpbuffer_free(void **buf); /* GC prototypes */ +void gc_init_mutators(); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); void *gc_try_alloc(gc_heap *h, size_t size); From cfcce37982d2bbf4999ed64edaf0716563470496 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 9 Nov 2015 22:51:39 -0500 Subject: [PATCH 123/339] Build out of collector_trace Implementation may not be optimal, but should be good enough to prove collector works --- gc.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index 72f7dd44..55b79335 100644 --- a/gc.c +++ b/gc.c @@ -480,6 +480,13 @@ void gc_mut_update() // TODO: when is this called, is this good enough, etc?? void gc_mut_cooperate(gc_thread_data *thd) { + +// !!!! +// TODO: think about what else needs to be done here. for example, +// would want to reset last read/write at some point, to conserve +// amount of memory being used by the mark buffers + + if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access if (thd->gc_mut_status == STATUS_SYNC2) { // TODO: more sync?? // Since everything is on the stack, at this point probably only need @@ -518,6 +525,7 @@ void gc_mark_gray(gc_thread_data *thd, object obj) void gc_collector_trace() { + gc_thread_data *m; int clean = 0, i; while (!clean) { clean = 1; @@ -525,13 +533,18 @@ void gc_collector_trace() // the collector thread is the only one that is using these // fields. for (i = 0; i < Cyc_num_mutators; i++) { + m = Cyc_mutators[i]; +// TODO: ideally, want to use a lock-free data structure to prevent +// having to use a mutex here. see corresponding code in gc_mark_gray + pthread_mutex_lock(&(m->lock)); + while (m->last_read < m->last_write) { + clean = 0; + (m->last_read)++; + gc_mark_black((m->mark_buffer)[m->last_read]); + gc_empty_collector_stack(); + } + pthread_mutex_unlock(&(m->lock)); } -// For each m in mutators -// while (lastread[m] < lastwrite[m]) // TODO: use atomic sub to compare? -// clean = FALSE -// lastread[m] = lastread[m] + 1 // TODO: atomic increment -// markBlack(markbuffer[m][lastread[m]]) -// EmptyCollectorStack() } } From 23cf9bd14cd883ab8ea97fb1b24698c6106f52cb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 9 Nov 2015 23:22:27 -0500 Subject: [PATCH 124/339] Added stubs --- gc.c | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index 55b79335..b3199bab 100644 --- a/gc.c +++ b/gc.c @@ -626,24 +626,27 @@ void gc_empty_collector_stack() } } -// TODO: -//void gc_handshake(gc_status_type s) -//{ -// gc_post_handshake(s); -// gc_wait_handshake(); -//} +void gc_handshake(gc_status_type s) +{ + gc_post_handshake(s); + gc_wait_handshake(); +} -//void gc_post_handshake(gc_status_type s) -//{ -// TODO: use atomic to change value of gc_status_col -//} +void gc_post_handshake(gc_status_type s) +{ + TODO: use atomic to change value of gc_status_col +} -//void gc_wait_handshake() -//{ +void gc_wait_handshake() +{ + int i; + // TODO: same as in other places, need to either sync access to + // mutator vars, or ensure only the collector uses them + for (i = 0; i < Cyc_num_mutators; i++) { // // TODO: -// for each m in mutators // wait for statusm = statusc -//} + } +} ///////////////////////////////////////////// // GC Collection cycle @@ -651,6 +654,24 @@ void gc_empty_collector_stack() // TODO: //void gc_collector() //{ +// clear : stage clear-or-marking +// exchange values of markColor and clearColor +// weakRefsList:clear() +// Handshake(sync1) +// mark: Handshake(sync2) +// stage tracing +// postHandshake(async) +// mark global roots +// waitHandshake +// trace : CollectorTrace() +// stage refProcessing +// processRefs() +// stage sweeping +// sweep : For each object x in the heap: +// if (color(x) = clearColor) +// free free [ x +// color(x) blue +// stage resting //} ///////////////////////////////////////////// From af3aa141f1e2b8f91d9164bbf99a44e99ad48203 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 03:08:29 -0500 Subject: [PATCH 125/339] WIP --- gc.c | 2 ++ include/cyclone/types.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index b3199bab..fa3ca57b 100644 --- a/gc.c +++ b/gc.c @@ -634,7 +634,9 @@ void gc_handshake(gc_status_type s) void gc_post_handshake(gc_status_type s) { + int status = ATOMIC_GET(&gc_status_col); TODO: use atomic to change value of gc_status_col + while (!ATOMIC_SET_IF_EQ(&gc_status_col, status, s)){} } void gc_wait_handshake() diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 330fb5d0..a4b35417 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -405,6 +405,6 @@ typedef union { #define ATOMIC_INC(ptr) __sync_fetch_and_add((ptr),1) #define ATOMIC_DEC(ptr) __sync_fetch_and_sub((ptr),1) #define ATOMIC_GET(ptr) __sync_fetch_and_add((ptr),0) -#define ATOMIC_SET_IF_EQ(ptr, oldv, newv) __sync_val_compare_and_swap(ptr, oldv, newv) +#define ATOMIC_SET_IF_EQ(ptr, oldv, newv) __sync_bool_compare_and_swap(ptr, oldv, newv) #endif /* CYCLONE_TYPES_H */ From 0f040a0691b780fa90202fe6f46ae7a51ff35f26 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 03:08:54 -0500 Subject: [PATCH 126/339] Removed stale comment --- gc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gc.c b/gc.c index fa3ca57b..5053589a 100644 --- a/gc.c +++ b/gc.c @@ -635,7 +635,6 @@ void gc_handshake(gc_status_type s) void gc_post_handshake(gc_status_type s) { int status = ATOMIC_GET(&gc_status_col); - TODO: use atomic to change value of gc_status_col while (!ATOMIC_SET_IF_EQ(&gc_status_col, status, s)){} } From b24cc7398268fc9987506ba17d5d7e0659a98ee2 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 9 Nov 2015 21:46:01 -0500 Subject: [PATCH 127/339] Init globals, stubbed out wait handshake --- gc.c | 40 ++++++++++++++++++++++++++-------------- include/cyclone/types.h | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/gc.c b/gc.c index 5053589a..17fc7124 100644 --- a/gc.c +++ b/gc.c @@ -456,8 +456,8 @@ static int gc_color_clear = 3; // White, is swapped during GC //static const int gc_color_grey = 4; // TODO: appears unused, clean up // unfortunately this had to be split up; const colors are located in types.h -static int gc_status_col; -static int gc_stage; +static int gc_status_col = STATUS_SYNC1; +static int gc_stage = STAGE_CLEAR_OR_MARKING; // Does not need sync, only used by collector thread static void **mark_stack = NULL; @@ -487,15 +487,15 @@ void gc_mut_cooperate(gc_thread_data *thd) // amount of memory being used by the mark buffers - if (thd->gc_mut_status == gc_status_col) { // TODO: synchronization of var access - if (thd->gc_mut_status == STATUS_SYNC2) { // TODO: more sync?? + if (thd->gc_status == gc_status_col) { // TODO: synchronization of var access + if (thd->gc_status == STATUS_SYNC2) { // TODO: more sync?? // Since everything is on the stack, at this point probably only need // to worry about anything on the stack that is referencing a heap object // For each x in roots: // MarkGray(x) thd->gc_alloc_color = gc_color_mark; // TODO: synchronization for global?? } - thd->gc_mut_status = gc_status_col; // TODO: syncronization?? + thd->gc_status = gc_status_col; // TODO: syncronization?? } } @@ -640,12 +640,24 @@ void gc_post_handshake(gc_status_type s) void gc_wait_handshake() { - int i; + int i, statusm, statusc; + struct timespec tim; + tim.tv_sec = 0; + tim.tv_nsec = 1; + // TODO: same as in other places, need to either sync access to // mutator vars, or ensure only the collector uses them for (i = 0; i < Cyc_num_mutators; i++) { -// // TODO: -// wait for statusm = statusc + statusc = ATOMIC_GET(&gc_status_col); + statusm = ATOMIC_GET(&(Cyc_mutators[i]->gc_status)); + if (statusc != statusm) { + // At least for now, just give up quantum and come back to + // this quickly to test again. This probably could be more + // efficient. + // TODO: also need to consider mutators that are blocked and + // not cooperating. + nanosleep(&tim, NULL); + } } } @@ -704,16 +716,16 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->gc_num_args = 0; thd->moveBufLen = 0; gc_thr_grow_move_buffer(thd); -// TODO: depends on collector state: thd->gc_alloc_color = ATOMIC_GET(&gc_; -// TODO: depends on collector state: thd->gc_mut_status; + thd->gc_alloc_color = ATOMIC_GET(&gc_color_clear); + thd->gc_status = ATOMIC_GET(&gc_status_col); thd->last_write = 0; thd->last_read = 0; thd->mark_buffer_len = 128; thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); -// TODO: if (pthread_mutex(&(thd->lock), NULL) != 0) { -// TODO: fprintf(stderr, "Unable to initialize thread mutex\n"); -// TODO: exit(1); -// TODO: } + if (pthread_mutex(&(thd->lock), NULL) != 0) { + fprintf(stderr, "Unable to initialize thread mutex\n"); + exit(1); + } } void gc_thread_data_free(gc_thread_data *thd) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index a4b35417..5de7d56c 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -53,7 +53,7 @@ struct gc_thread_data_t { short gc_num_args; // Data needed for heap GC int gc_alloc_color; - int gc_mut_status; + int gc_status; int last_write; int last_read; void **mark_buffer; From d3a6418b0b4e15f8f9f2c14151f49040dff5958a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 9 Nov 2015 23:04:56 -0500 Subject: [PATCH 128/339] WIP --- gc.c | 49 +++++++++++++++++++++++------------------ include/cyclone/types.h | 2 +- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/gc.c b/gc.c index 17fc7124..2c369457 100644 --- a/gc.c +++ b/gc.c @@ -665,27 +665,34 @@ void gc_wait_handshake() // GC Collection cycle // TODO: -//void gc_collector() -//{ -// clear : stage clear-or-marking -// exchange values of markColor and clearColor -// weakRefsList:clear() -// Handshake(sync1) -// mark: Handshake(sync2) -// stage tracing -// postHandshake(async) -// mark global roots -// waitHandshake -// trace : CollectorTrace() -// stage refProcessing -// processRefs() -// stage sweeping -// sweep : For each object x in the heap: -// if (color(x) = clearColor) -// free free [ x -// color(x) blue -// stage resting -//} +void gc_collector() +{ + int tmp; + // TODO: what kind of sync is required here? + + //clear + gc_stage = STAGE_CLEAR_OR_MARKING; + // exchange values of markColor and clearColor + tmp = gc_color_clear; + gc_color_clear = gc_color_mark; + gc_color_mark = tmp; + gc_handshake(STATUS_SYNC1); + //mark: + gc_handshake(STATUS_SYNC2) + gc_stage = STAGE_TRACING; + gc_post_handshake(STATUS_ASYNC); + TODO: mark global roots + gc_wait_handshake(); + //trace : + CollectorTrace() + gc_stage = STAGE_SWEEPING; + //sweep : + For each object x in the heap: + if (color(x) = clearColor) + free free [ x + color(x) blue + gc_stage = STAGE_RESTING; +} ///////////////////////////////////////////// // END tri-color marking section diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 5de7d56c..69f2466e 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -108,7 +108,7 @@ typedef enum { STATUS_ASYNC typedef enum { STAGE_CLEAR_OR_MARKING , STAGE_TRACING - , STAGE_REF_PROCESSING + //, STAGE_REF_PROCESSING , STAGE_SWEEPING , STAGE_RESTING } gc_stage_type; From 41f2a9e6caa07ace4ee8a601a5c8febad0f3c51b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 21:16:40 -0500 Subject: [PATCH 129/339] Working on gc_collector() --- gc.c | 102 ++++++++++++++++++++-------------------- include/cyclone/types.h | 5 +- runtime.c | 90 ++++++++++++++++++++--------------- 3 files changed, 108 insertions(+), 89 deletions(-) diff --git a/gc.c b/gc.c index 2c369457..95f7bf5e 100644 --- a/gc.c +++ b/gc.c @@ -178,48 +178,48 @@ size_t gc_heap_total_size(gc_heap *h) return total_size; } -void gc_mark(gc_heap *h, object obj) -{ - if (nullp(obj) || is_value_type(obj) || mark(obj)) - return; - -#if GC_DEBUG_PRINTFS -// fprintf(stdout, "gc_mark %p\n", obj); -#endif - ((list)obj)->hdr.mark = 1; - // TODO: mark heap saves (??) - // could this be a write barrier? - - // Mark objects this one references - if (type_of(obj) == cons_tag) { - gc_mark(h, car(obj)); - gc_mark(h, cdr(obj)); - } else if (type_of(obj) == closure1_tag) { - gc_mark(h, ((closure1) obj)->elt1); - } else if (type_of(obj) == closure2_tag) { - gc_mark(h, ((closure2) obj)->elt1); - gc_mark(h, ((closure2) obj)->elt2); - } else if (type_of(obj) == closure3_tag) { - gc_mark(h, ((closure3) obj)->elt1); - gc_mark(h, ((closure3) obj)->elt2); - gc_mark(h, ((closure3) obj)->elt3); - } else if (type_of(obj) == closure4_tag) { - gc_mark(h, ((closure4) obj)->elt1); - gc_mark(h, ((closure4) obj)->elt2); - gc_mark(h, ((closure4) obj)->elt3); - gc_mark(h, ((closure4) obj)->elt4); - } else if (type_of(obj) == closureN_tag) { - int i, n = ((closureN) obj)->num_elt; - for (i = 0; i < n; i++) { - gc_mark(h, ((closureN) obj)->elts[i]); - } - } else if (type_of(obj) == vector_tag) { - int i, n = ((vector) obj)->num_elt; - for (i = 0; i < n; i++) { - gc_mark(h, ((vector) obj)->elts[i]); - } - } -} +//void gc_mark(gc_heap *h, object obj) +//{ +// if (nullp(obj) || is_value_type(obj) || mark(obj)) +// return; +// +//#if GC_DEBUG_PRINTFS +//// fprintf(stdout, "gc_mark %p\n", obj); +//#endif +// ((list)obj)->hdr.mark = 1; +// // TODO: mark heap saves (??) +// // could this be a write barrier? +// +// // Mark objects this one references +// if (type_of(obj) == cons_tag) { +// gc_mark(h, car(obj)); +// gc_mark(h, cdr(obj)); +// } else if (type_of(obj) == closure1_tag) { +// gc_mark(h, ((closure1) obj)->elt1); +// } else if (type_of(obj) == closure2_tag) { +// gc_mark(h, ((closure2) obj)->elt1); +// gc_mark(h, ((closure2) obj)->elt2); +// } else if (type_of(obj) == closure3_tag) { +// gc_mark(h, ((closure3) obj)->elt1); +// gc_mark(h, ((closure3) obj)->elt2); +// gc_mark(h, ((closure3) obj)->elt3); +// } else if (type_of(obj) == closure4_tag) { +// gc_mark(h, ((closure4) obj)->elt1); +// gc_mark(h, ((closure4) obj)->elt2); +// gc_mark(h, ((closure4) obj)->elt3); +// gc_mark(h, ((closure4) obj)->elt4); +// } else if (type_of(obj) == closureN_tag) { +// int i, n = ((closureN) obj)->num_elt; +// for (i = 0; i < n; i++) { +// gc_mark(h, ((closureN) obj)->elts[i]); +// } +// } else if (type_of(obj) == vector_tag) { +// int i, n = ((vector) obj)->num_elt; +// for (i = 0; i < n; i++) { +// gc_mark(h, ((vector) obj)->elts[i]); +// } +// } +//} size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) { @@ -670,28 +670,30 @@ void gc_collector() int tmp; // TODO: what kind of sync is required here? - //clear + //clear : gc_stage = STAGE_CLEAR_OR_MARKING; // exchange values of markColor and clearColor + // TODO: synchronize? tmp = gc_color_clear; gc_color_clear = gc_color_mark; gc_color_mark = tmp; gc_handshake(STATUS_SYNC1); - //mark: + //mark : gc_handshake(STATUS_SYNC2) gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); - TODO: mark global roots + gc_mark_globals(); gc_wait_handshake(); //trace : - CollectorTrace() + gc_collector_trace(); gc_stage = STAGE_SWEEPING; //sweep : - For each object x in the heap: - if (color(x) = clearColor) - free free [ x - color(x) blue + // TODO: For each object x in the heap: + // TODO: if (color(x) = clearColor) + // TODO: free free [ x + // TODO: color(x) blue gc_stage = STAGE_RESTING; + // TODO: how long to rest? } ///////////////////////////////////////////// diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 69f2466e..60b29bb5 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -133,9 +133,10 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown); size_t gc_allocated_bytes(object obj); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); -void gc_mark(gc_heap *h, object obj); +//size_t gc_collect(gc_heap *h, size_t *sum_freed); +//void gc_mark(gc_heap *h, object obj); +void gc_mark_globals(void); size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); -size_t gc_collect(gc_heap *h, size_t *sum_freed); void gc_thr_grow_move_buffer(gc_thread_data *d); void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); diff --git a/runtime.c b/runtime.c index 6df073cf..d0da084f 100644 --- a/runtime.c +++ b/runtime.c @@ -2362,34 +2362,50 @@ void Cyc_start_thread(gc_thread_data *thd) exit(0); } -// Collect garbage using mark&sweep algorithm -// Note non-global roots should be marked prior to calling this function. -size_t gc_collect(gc_heap *h, size_t *sum_freed) +//// Collect garbage using mark&sweep algorithm +//// Note non-global roots should be marked prior to calling this function. +//size_t gc_collect(gc_heap *h, size_t *sum_freed) +//{ +//#if GC_DEBUG_CONCISE_PRINTFS +// printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); +//#endif +// // Mark global variables +// gc_mark(h, Cyc_global_variables); // Internal global used by the runtime +// // Marking it ensures all glos are marked +// { +// list l = global_table; +// for(; !nullp(l); l = cdr(l)){ +// cvar_type *c = (cvar_type *)car(l); +// gc_mark(h, *(c->pvar)); // Mark actual object the global points to +// } +// } +// // TODO: what else to mark? gc_mark( +// // conservative mark? +// // weak refs? +// // finalize? +// return gc_sweep(h, sum_freed); +// // debug print free stats? +//} + +// Mark globals as part of the tracing collector +// This is called by the collector thread +void gc_mark_globals() { #if GC_DEBUG_CONCISE_PRINTFS - printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); #endif // Mark global variables - gc_mark(h, Cyc_global_variables); // Internal global used by the runtime - // Marking it ensures all glos are marked + gc_mark_black(Cyc_global_variables); // Internal global used by the runtime + // Marking it ensures all glos are marked { list l = global_table; for(; !nullp(l); l = cdr(l)){ cvar_type *c = (cvar_type *)car(l); - gc_mark(h, *(c->pvar)); // Mark actual object the global points to + gc_mark_black(*(c->pvar)); // Mark actual object the global points to } } - // TODO: what else to mark? gc_mark( - // conservative mark? - // weak refs? - // finalize? - return gc_sweep(h, sum_freed); - // debug print free stats? } -// TODO: move globals to thread-specific structures. -// for example - gc_cont, gc_ans, gc_num_ans - char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; @@ -2723,27 +2739,27 @@ void GC(void *data, closure cont, object *args, int num_args) //fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); - // Check if we need to do a major GC - if (heap_grown) { - size_t freed = 0, max_freed = 0; -#if GC_DEBUG_CONCISE_PRINTFS - time_t majorStart = time(NULL); - fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG -#endif - gc_mark(Cyc_heap, cont); - for (i = 0; i < num_args; i++){ - gc_mark(Cyc_heap, args[i]); - } - max_freed = gc_collect(Cyc_heap, &freed); -#if GC_DEBUG_CONCISE_PRINTFS - printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); - //JAE_DEBUG++; - //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG - for (i = 0; i < 20; i++){ - printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]); - } -#endif - } +// // Check if we need to do a major GC +// if (heap_grown) { +// size_t freed = 0, max_freed = 0; +//#if GC_DEBUG_CONCISE_PRINTFS +// time_t majorStart = time(NULL); +// fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG +//#endif +// gc_mark(Cyc_heap, cont); +// for (i = 0; i < num_args; i++){ +// gc_mark(Cyc_heap, args[i]); +// } +// max_freed = gc_collect(Cyc_heap, &freed); +//#if GC_DEBUG_CONCISE_PRINTFS +// printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); +// //JAE_DEBUG++; +// //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG +// for (i = 0; i < 20; i++){ +// printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]); +// } +//#endif +// } /* Let it all go, Neo... */ longjmp(*(((gc_thread_data *)data)->jmp_start), 1); From 62a9efc1f5e0f42d2257160549faf1e91ce88110 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 22:10:09 -0500 Subject: [PATCH 130/339] Relocated module globals, added heap lock var --- gc.c | 52 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/gc.c b/gc.c index 95f7bf5e..4976525d 100644 --- a/gc.c +++ b/gc.c @@ -12,9 +12,35 @@ #include "cyclone/types.h" +//////////////////// +// Global variables + +// Note: will need to use atomics and/or locking to access any +// variables shared between threads +static int gc_color_mark = 2; // Black, is swapped during GC +static int gc_color_clear = 3; // White, is swapped during GC +//static const int gc_color_grey = 4; // TODO: appears unused, clean up +// unfortunately this had to be split up; const colors are located in types.h + +static int gc_status_col = STATUS_SYNC1; +static int gc_stage = STAGE_CLEAR_OR_MARKING; + +// Does not need sync, only used by collector thread +static void **mark_stack = NULL; +static int mark_stack_len = 128; +static int mark_stack_i = 0; + +// Lock to protect the heap from concurrent modifications +static pthread_mutex_t heap_lock; + +// Data for each individual mutator thread static gc_thread_data **Cyc_mutators; static int Cyc_num_mutators; +///////////// +// Functions + +// Perform one-time initialization before mutators can be executed void gc_init_mutators() { // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? @@ -23,6 +49,12 @@ void gc_init_mutators() // need to think on this when adding thread support, after upgrading the collector Cyc_num_mutators = 1; Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); + + // Here is as good a place as any to do this... + if (pthread_mutex(&(heap_lock), NULL) != 0) { + fprintf(stderr, "Unable to initialize heap_lock mutex\n"); + exit(1); + } } gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) @@ -91,6 +123,11 @@ void *gc_try_alloc(gc_heap *h, size_t size) return NULL; } +//TODO: need a heap lock. +//lock during - alloc, sweep? but now sweep becomes a stop the world... +// maybe only lock during each individual operation, not for a whole +// sweep or alloc + void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) { void *result = NULL; @@ -448,21 +485,6 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): */ // tri-color GC section, WIP -// -// Note: will need to use atomics and/or locking to access any -// variables shared between threads -static int gc_color_mark = 2; // Black, is swapped during GC -static int gc_color_clear = 3; // White, is swapped during GC -//static const int gc_color_grey = 4; // TODO: appears unused, clean up -// unfortunately this had to be split up; const colors are located in types.h - -static int gc_status_col = STATUS_SYNC1; -static int gc_stage = STAGE_CLEAR_OR_MARKING; - -// Does not need sync, only used by collector thread -static void **mark_stack = NULL; -static int mark_stack_len = 128; -static int mark_stack_i = 0; ///////////////////////////////////////////// // GC functions called by the Mutator threads From ca27d4a5d40e48ebda4245a64108fa1df75698ca Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 22:34:48 -0500 Subject: [PATCH 131/339] Added TODO --- gc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gc.c b/gc.c index 4976525d..aa29a9a9 100644 --- a/gc.c +++ b/gc.c @@ -709,6 +709,12 @@ void gc_collector() //trace : gc_collector_trace(); gc_stage = STAGE_SWEEPING; + +TODO: before updating sweep to make it work w/new GC, need to +update the heap functions to be thread safe. ideally want to +try to minimize amount of locking - IE, lock on individual ops +IF POSSIBLE, instead of whole operations like 'alloc' and 'sweep'. + // //sweep : // TODO: For each object x in the heap: // TODO: if (color(x) = clearColor) From 0db95aa1c5c5e6b643f72270a88f3bf6c86c9fc4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 11 Nov 2015 02:48:50 -0500 Subject: [PATCH 132/339] Added notes --- gc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gc.c b/gc.c index aa29a9a9..2ac825a6 100644 --- a/gc.c +++ b/gc.c @@ -714,6 +714,14 @@ TODO: before updating sweep to make it work w/new GC, need to update the heap functions to be thread safe. ideally want to try to minimize amount of locking - IE, lock on individual ops IF POSSIBLE, instead of whole operations like 'alloc' and 'sweep'. +functions that modify heap: + gc_try_alloc + gc_sweep + gc_grow_heap +think that's it? +consider what is being modified, and what is being read + + // //sweep : // TODO: For each object x in the heap: From 6e6f07943040f7551cda5f05bfe691be7e443efb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 10 Nov 2015 23:01:48 -0500 Subject: [PATCH 133/339] Added coarse-grained heap locking --- gc.c | 64 +++++++++++++++++++++------------------ include/cyclone/runtime.h | 1 - include/cyclone/types.h | 1 + runtime.c | 9 ++++-- 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/gc.c b/gc.c index 2ac825a6..a98219ff 100644 --- a/gc.c +++ b/gc.c @@ -91,17 +91,22 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) { size_t cur_size, new_size; - gc_heap *h_last = gc_heap_last(h); + gc_heap *h_last, *h_new; + pthread_mutex_lock(&heap_lock); + h_last = gc_heap_last(h); cur_size = h_last->size; // JAE - For now, just add a new page new_size = cur_size; //gc_heap_align(((cur_size > size) ? cur_size : size) * 2); - h_last->next = gc_heap_create(new_size, h_last->max_size, chunk_size); - return (h_last->next != NULL); + h_new = gc_heap_create(new_size, h_last->max_size, chunk_size); + h_last->next = h_new; + pthread_mutex_unlock(&heap_lock); + return (h_new != NULL); } void *gc_try_alloc(gc_heap *h, size_t size) { gc_free_list *f1, *f2, *f3; + pthread_mutex_lock(&heap_lock); for (; h; h = h->next) { // All heaps // TODO: chunk size (ignoring for now) @@ -120,6 +125,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) } } } + pthread_mutex_unlock(&heap_lock); return NULL; } @@ -208,10 +214,12 @@ gc_heap *gc_heap_last(gc_heap *h) size_t gc_heap_total_size(gc_heap *h) { size_t total_size = 0; + //pthread_mutex_lock(&heap_lock); while(h) { total_size += h->size; h = h->next; } + //pthread_mutex_unlock(&heap_lock); return total_size; } @@ -263,6 +271,16 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) size_t freed, max_freed=0, sum_freed=0, size; object p, end; gc_free_list *q, *r, *s; + + // + // Lock the heap to prevent issues with allocations during sweep + // It sucks to have to use a coarse-grained lock like this, but let's + // be safe and prevent threading issues right now. Once the new GC + // works we can go back and try to speed things up (if possible) + // by using more fine-grained locking. Can also profile to see + // how much time is even spent sweeping + // + pthread_mutex_lock(&heap_lock); for (; h; h = h->next) { // All heaps #if GC_DEBUG_CONCISE_PRINTFS fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); @@ -295,10 +313,11 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) // END DEBUG #endif - if (!mark(p)) { + if (mark(p) == gc_color_clear) { #if GC_DEBUG_PRINTFS fprintf(stdout, "sweep: object is not marked %p\n", p); #endif + mark(p) = gc_color_blue; // Needed? // free p sum_freed += size; if (((((char *)q) + q->size) == (char *)p) && (q != h->free_list)) { @@ -335,16 +354,11 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) #if GC_DEBUG_PRINTFS // fprintf(stdout, "sweep: object is marked %p\n", p); #endif - //if (mark(p) != 1) { - // printf("unexpected mark value %d\n", mark(p)); - // exit(1); - //} - - ((list)p)->hdr.mark = 0; p = (object)(((char *)p) + size); } } } + pthread_mutex_unlock(&heap_lock); if (sum_freed_ptr) *sum_freed_ptr = sum_freed; return max_freed; } @@ -686,10 +700,14 @@ void gc_wait_handshake() ///////////////////////////////////////////// // GC Collection cycle -// TODO: +// Main collector function void gc_collector() { int tmp; + size_t freed = 0, max_freed = 0; +#if GC_DEBUG_CONCISE_PRINTFS + time_t sweep_start = time(NULL); +#endif // TODO: what kind of sync is required here? //clear : @@ -701,7 +719,7 @@ void gc_collector() gc_color_mark = tmp; gc_handshake(STATUS_SYNC1); //mark : - gc_handshake(STATUS_SYNC2) + gc_handshake(STATUS_SYNC2); gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); gc_mark_globals(); @@ -709,27 +727,13 @@ void gc_collector() //trace : gc_collector_trace(); gc_stage = STAGE_SWEEPING; - -TODO: before updating sweep to make it work w/new GC, need to -update the heap functions to be thread safe. ideally want to -try to minimize amount of locking - IE, lock on individual ops -IF POSSIBLE, instead of whole operations like 'alloc' and 'sweep'. -functions that modify heap: - gc_try_alloc - gc_sweep - gc_grow_heap -think that's it? -consider what is being modified, and what is being read - - // //sweep : - // TODO: For each object x in the heap: - // TODO: if (color(x) = clearColor) - // TODO: free free [ x - // TODO: color(x) blue + max_freed = gc_sweep(Cyc_get_heap(), &freed); +#if GC_DEBUG_CONCISE_PRINTFS + printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - sweep_start); +#endif gc_stage = STAGE_RESTING; - // TODO: how long to rest? } ///////////////////////////////////////////// diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 4b0232eb..9c287782 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -208,7 +208,6 @@ void dispatch_va(void *data, int argc, function_type_va func, object clo, object void do_dispatch(void *data, int argc, function_type func, object clo, object *buffer); /* Global variables. */ -extern gc_heap *Cyc_heap; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 60b29bb5..c680fbdc 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -150,6 +150,7 @@ void gc_empty_collector_stack(); void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); +gc_heap *Cyc_get_heap(); ///////////////////////////////////////////// // GC Collection cycle diff --git a/runtime.c b/runtime.c index d0da084f..c5d7332b 100644 --- a/runtime.c +++ b/runtime.c @@ -79,9 +79,7 @@ void Cyc_check_bounds(void *data, const char *label, int len, int index) { /*END closcall section */ /* Global variables. */ -gc_heap *Cyc_heap; -gc_thread_data **Cyc_mutators; -int Cyc_num_mutators; +static gc_heap *Cyc_heap; long no_gcs = 0; /* Count the number of GC's. */ long no_major_gcs = 0; /* Count the number of GC's. */ @@ -92,6 +90,11 @@ char **_cyc_argv = NULL; static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of custom type const object Cyc_EOF = &__EOF; +gc_heap *Cyc_get_heap() +{ + return Cyc_heap; +} + object cell_get(object cell){ return car(cell); } From c9d24c9a025ad8879e78bcc4bd8438fce76b145f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 11 Nov 2015 21:33:30 -0500 Subject: [PATCH 134/339] startup collector thread --- gc.c | 21 ++++++++++++++++++++- include/cyclone/runtime-main.h | 1 + include/cyclone/types.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index a98219ff..87263319 100644 --- a/gc.c +++ b/gc.c @@ -731,11 +731,30 @@ void gc_collector() //sweep : max_freed = gc_sweep(Cyc_get_heap(), &freed); #if GC_DEBUG_CONCISE_PRINTFS - printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - sweep_start); + printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", + freed, max_freed, time(NULL) - sweep_start); #endif gc_stage = STAGE_RESTING; } +void *collector_main(void *arg) +{ + while (1) { + gc_collector(); + sleep(1); // TODO: how to schedule this thread? + } +} + +static pthread_t collector_thread; + +void gc_start_collector() +{ + if (pthread_create(&collector_thread, NULL, collector_main, &collector_thread)) { + fprintf(stderr, "Error creating collector thread\n"); + exit(1); + } +} + ///////////////////////////////////////////// // END tri-color marking section ///////////////////////////////////////////// diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 9f7edf8e..2ab0b1ab 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -29,6 +29,7 @@ static void Cyc_heap_init(long heap_size) #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); gc_init_mutators(); + gc_start_collector(); } #endif /* CYCLONE_RUNTIME_MAIN_H */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index c680fbdc..a1bfc527 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -150,6 +150,7 @@ void gc_empty_collector_stack(); void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); +void gc_start_collector(); gc_heap *Cyc_get_heap(); ///////////////////////////////////////////// From cb7274526ca214d2255868ddaa2a2de8c9ae80d7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 11 Nov 2015 22:58:53 -0500 Subject: [PATCH 135/339] WIP --- gc.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/gc.c b/gc.c index 87263319..4c0925e4 100644 --- a/gc.c +++ b/gc.c @@ -100,6 +100,7 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) h_new = gc_heap_create(new_size, h_last->max_size, chunk_size); h_last->next = h_new; pthread_mutex_unlock(&heap_lock); +printf("DEBUG - grew heap\n"); return (h_new != NULL); } @@ -214,12 +215,12 @@ gc_heap *gc_heap_last(gc_heap *h) size_t gc_heap_total_size(gc_heap *h) { size_t total_size = 0; - //pthread_mutex_lock(&heap_lock); + pthread_mutex_lock(&heap_lock); while(h) { total_size += h->size; h = h->next; } - //pthread_mutex_unlock(&heap_lock); + pthread_mutex_unlock(&heap_lock); return total_size; } @@ -529,7 +530,7 @@ void gc_mut_cooperate(gc_thread_data *thd) // to worry about anything on the stack that is referencing a heap object // For each x in roots: // MarkGray(x) - thd->gc_alloc_color = gc_color_mark; // TODO: synchronization for global?? + thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); // TODO: synchronization for global?? } thd->gc_status = gc_status_col; // TODO: syncronization?? } @@ -593,7 +594,7 @@ void gc_mark_black(object obj) // TODO: is sync required to get colors? probably not on the collector // thread (at least) since colors are only changed once during the clear // phase and before the first handshake. - int markColor = gc_color_mark; //TODO: is atomic require here?? ATOMIC_GET(&gc_color_mark); + int markColor = ATOMIC_GET(&gc_color_mark); if (is_object_type(obj) && mark(obj) != markColor) { // Gray any child objects // Note we probably should use some form of atomics/synchronization @@ -703,20 +704,21 @@ void gc_wait_handshake() // Main collector function void gc_collector() { - int tmp; - size_t freed = 0, max_freed = 0; -#if GC_DEBUG_CONCISE_PRINTFS + int old_clear, old_mark; + size_t freed = 0, max_freed = 0, total_size; +//#if GC_DEBUG_CONCISE_PRINTFS time_t sweep_start = time(NULL); -#endif +//#endif // TODO: what kind of sync is required here? //clear : gc_stage = STAGE_CLEAR_OR_MARKING; // exchange values of markColor and clearColor - // TODO: synchronize? - tmp = gc_color_clear; - gc_color_clear = gc_color_mark; - gc_color_mark = tmp; + old_clear = ATOMIC_GET(&gc_color_clear); + old_mark = ATOMIC_GET(&gc_color_mark); + while(!ATOMIC_SET_IF_EQ(&gc_color_clear, old_clear, old_mark)){} + while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} +printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_handshake(STATUS_SYNC1); //mark : gc_handshake(STATUS_SYNC2); @@ -730,10 +732,11 @@ void gc_collector() // //sweep : max_freed = gc_sweep(Cyc_get_heap(), &freed); -#if GC_DEBUG_CONCISE_PRINTFS + // TODO: grow heap if it is mostly full after collection?? +//#if GC_DEBUG_CONCISE_PRINTFS printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - sweep_start); -#endif +//#endif gc_stage = STAGE_RESTING; } @@ -741,7 +744,11 @@ void *collector_main(void *arg) { while (1) { gc_collector(); - sleep(1); // TODO: how to schedule this thread? + // TODO: how to schedule this thread? + // this is inefficient but it should be good enough to + // at least stand up this collector. then we'll have to + // come back and improve it + sleep(1); } } From 4bb24a4eddb5b6b944b5bf172adca7a376e62bc2 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 12 Nov 2015 22:33:34 -0500 Subject: [PATCH 136/339] Added mutator cooperation function --- gc.c | 32 ++++++++++++++++---------------- include/cyclone/types.h | 1 + runtime.c | 5 ++++- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/gc.c b/gc.c index 4c0925e4..a35e8554 100644 --- a/gc.c +++ b/gc.c @@ -514,25 +514,25 @@ void gc_mut_update() // ideally want to do this without needing sync. we need to sync to get markColor in coop, though //void gc_mut_create() -// TODO: when is this called, is this good enough, etc?? +// TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd) { - -// !!!! -// TODO: think about what else needs to be done here. for example, -// would want to reset last read/write at some point, to conserve -// amount of memory being used by the mark buffers - - - if (thd->gc_status == gc_status_col) { // TODO: synchronization of var access - if (thd->gc_status == STATUS_SYNC2) { // TODO: more sync?? - // Since everything is on the stack, at this point probably only need - // to worry about anything on the stack that is referencing a heap object - // For each x in roots: - // MarkGray(x) - thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); // TODO: synchronization for global?? + int i, status = ATOMIC_GET(&gc_status_col); + if (thd->gc_status != status) { + if (thd->gc_status == STATUS_ASYNC) { + // Async is done, so clean up old mark data from the last collection + thd->last_write = 0; + thd->last_read = 0; } - thd->gc_status = gc_status_col; // TODO: syncronization?? + else if (thd->gc_status == STATUS_SYNC2) { + // Mark thread "roots" + gc_mark_gray(thd, thd->gc_cont); + for (i = 0; i < thd->gc_num_args; i++) { + gc_mark_gray(thd, thd->gc_args[i]); + } + thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); + } + thd->gc_status = status; } } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index a1bfc527..4f6a7c1e 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -142,6 +142,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: +void gc_mut_cooperate(gc_thread_data *thd); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); void gc_mark_black(object obj); diff --git a/runtime.c b/runtime.c index c5d7332b..9b2f48c8 100644 --- a/runtime.c +++ b/runtime.c @@ -2764,7 +2764,10 @@ void GC(void *data, closure cont, object *args, int num_args) //#endif // } - /* Let it all go, Neo... */ + // Cooperate with the collector thread + gc_mut_cooperate((gc_thread_data *)data); + + // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } From ae3ba3cd1ac3c478864e84ff90bdb87f2f575d02 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 12 Nov 2015 22:49:51 -0500 Subject: [PATCH 137/339] Added notes regarding update() --- gc.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index a35e8554..db39b460 100644 --- a/gc.c +++ b/gc.c @@ -504,15 +504,32 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): ///////////////////////////////////////////// // GC functions called by the Mutator threads -void gc_mut_update() +void gc_mut_update(object heapO) { // TODO: how does this fit in with the write buffer? // this part is important, especially during tracing -} -// Done as part of gc_move -// ideally want to do this without needing sync. we need to sync to get markColor in coop, though -//void gc_mut_create() + the paper marks both the heap location being written to and the + value being written. not sure it makes sense to mark the value + as it will always be on the stack - issue is if any obj's it is + referencing are on the heap. this is where that stack bit might + come in handy. + + do we want to mark gray immediately during add mutator, or wait + until minor GC? YES - I think for mutators we need to mark the + object gray immediately. otherwise if we delay until GC, a sweep + may have already finished up and freed such an obj that would + otherwise not have been freed if we had waited. + + again, only potential issue seems to be if a stack obj could ref + something else on the heap - can that happen? I think this can only + happen if the heap obj it refs is linked to a root, because stack + objs are so short lived?? + + also we already know if objects are on the stack due to their color (RED). + so can use this to not mark red values. otherwise probably do want + to mark the 'y' as well (per paper) to prevent timing issues when we wait +} // TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd) From f1443979e6417d8a64f5f4efe0fdba58a05767db Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 02:19:23 -0500 Subject: [PATCH 138/339] Added heap write barrier --- gc.c | 62 +++++++++++++++++++++++++---------------- include/cyclone/types.h | 1 + runtime.c | 6 ++++ 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/gc.c b/gc.c index db39b460..6ceb823e 100644 --- a/gc.c +++ b/gc.c @@ -504,31 +504,45 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): ///////////////////////////////////////////// // GC functions called by the Mutator threads -void gc_mut_update(object heapO) +// Write barrier for updates to heap-allocated objects +void gc_mut_update(gc_thread_data *thd, object old_obj, object value) { - // TODO: how does this fit in with the write buffer? - // this part is important, especially during tracing - - the paper marks both the heap location being written to and the - value being written. not sure it makes sense to mark the value - as it will always be on the stack - issue is if any obj's it is - referencing are on the heap. this is where that stack bit might - come in handy. - - do we want to mark gray immediately during add mutator, or wait - until minor GC? YES - I think for mutators we need to mark the - object gray immediately. otherwise if we delay until GC, a sweep - may have already finished up and freed such an obj that would - otherwise not have been freed if we had waited. - - again, only potential issue seems to be if a stack obj could ref - something else on the heap - can that happen? I think this can only - happen if the heap obj it refs is linked to a root, because stack - objs are so short lived?? - - also we already know if objects are on the stack due to their color (RED). - so can use this to not mark red values. otherwise probably do want - to mark the 'y' as well (per paper) to prevent timing issues when we wait + int status = ATOMIC_GET(&gc_status_col), + stage = ATOMIC_GET(&gc_stage); + if (thd->gc_status != STATUS_ASYNC) { + gc_mark_gray(thd, old_obj); + gc_mark_gray(thd, value); + } else if (stage == STAGE_TRACING) { + gc_mark_gray(thd, old_obj); + } +// TODO: concerned there may be an issue here with a stack object +// having a 'tree' of references that contains heap objects. these +// objects would be skipped and would never be grayed by the current +// code: +// +// the paper marks both the heap location being written to and the +// value being written. not sure it makes sense to mark the value +// as it will always be on the stack - issue is if any obj's it is +// referencing are on the heap. this is where that stack bit might +// come in handy. +// +// do we want to mark gray immediately during add mutator, or wait +// until minor GC? YES - I think for mutators we need to mark the +// object gray immediately. otherwise if we delay until GC, a sweep +// may have already finished up and freed such an obj that would +// otherwise not have been freed if we had waited. +// +// again, only potential issue seems to be if a stack obj could ref +// something else on the heap - can that happen? I think this can only +// happen if the heap obj it refs is linked to a root, because stack +// objs are so short lived?? +// +// also we already know if objects are on the stack due to their color (RED). +// so can use this to not mark red values. otherwise probably do want +// to mark the 'y' as well (per paper) to prevent timing issues when we wait +// +// do have some concern though that mark_gray will stop when a stack obj +// is detected, and the code will not examine any refs held by the stack obj. } // TODO: still need to handle case where a mutator is blocked diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 4f6a7c1e..aaf8d84a 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -142,6 +142,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: +void gc_mut_update(gc_thread_data *thd, object old_obj, object value); void gc_mut_cooperate(gc_thread_data *thd); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); diff --git a/runtime.c b/runtime.c index 9b2f48c8..e8f9dfd6 100644 --- a/runtime.c +++ b/runtime.c @@ -775,6 +775,7 @@ object Cyc_eq(object x, object y) { object Cyc_set_car(void *data, object l, object val) { if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); + gc_mut_update((gc_thread_data *)data, car(l), val); car(l) = val; add_mutation(l, val); return l; @@ -782,6 +783,7 @@ object Cyc_set_car(void *data, object l, object val) { object Cyc_set_cdr(void *data, object l, object val) { if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); + gc_mut_update((gc_thread_data *)data, cdr(l), val); cdr(l) = val; add_mutation(l, val); return l; @@ -797,6 +799,10 @@ object Cyc_vector_set(void *data, object v, object k, object obj) { Cyc_rt_raise2(data, "vector-set! - invalid index", k); } + gc_mut_update((gc_thread_data *)data, + ((vector)v)->elts[idx], + obj); + ((vector)v)->elts[idx] = obj; // TODO: probably could be more efficient here and also pass // index, so only that one entry needs GC. From 149aea2c0aba50899f2f634e4c2ad1af144901ee Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 02:20:54 -0500 Subject: [PATCH 139/339] Added note --- gc-notes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/gc-notes.txt b/gc-notes.txt index e4418e97..2af6c93c 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -2,3 +2,4 @@ Phase 1 (gc-dev) - Add gc.h, make sure it compiles. Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and be compatible with a new GC algorithm. Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. +Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. From df53ec99a631ec07bf6e9f0e3b6cffbe3e28c252 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 02:39:22 -0500 Subject: [PATCH 140/339] Fixed heap init --- include/cyclone/runtime-main.h | 2 +- include/cyclone/runtime.h | 1 + runtime.c | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 2ab0b1ab..a0487d0f 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -27,7 +27,7 @@ static void Cyc_heap_init(long heap_size) #if DEBUG_SHOW_DIAG printf("main: Allocating and initializing heap...\n"); #endif - Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); + gc_init_heap(); gc_init_mutators(); gc_start_collector(); } diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 9c287782..03475028 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -84,6 +84,7 @@ object cell_get(object cell); extern object Cyc_global_variables; int _cyc_argc; char **_cyc_argv; +void Cyc_init_heap(long heap_size); object Cyc_get_global_variables(); object Cyc_get_cvar(object var); object Cyc_set_cvar(object var, object value); diff --git a/runtime.c b/runtime.c index e8f9dfd6..e8fc4d5e 100644 --- a/runtime.c +++ b/runtime.c @@ -90,6 +90,11 @@ char **_cyc_argv = NULL; static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of custom type const object Cyc_EOF = &__EOF; +void Cyc_init_heap(long heap_size) +{ + Cyc_heap = gc_heap_create(heap_size, 0, 0); +} + gc_heap *Cyc_get_heap() { return Cyc_heap; From f4b62156baf825c5dca1c2d87631cb5e1464dda1 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 02:51:19 -0500 Subject: [PATCH 141/339] Added gc_add_mutator --- gc.c | 17 +++++++++++++++++ include/cyclone/types.h | 1 + 2 files changed, 18 insertions(+) diff --git a/gc.c b/gc.c index 6ceb823e..103afa85 100644 --- a/gc.c +++ b/gc.c @@ -57,6 +57,23 @@ void gc_init_mutators() } } +// Add data for a new mutator +void gc_add_mutator(gc_thread_data *thd) +{ + // TODO: need to sync access to these static variables. both here and + // elsewhere in the module!! + int i; + for (i = 0; i < Cyc_num_mutators; i++) { + if (!Cyc_mutators[i]) { + Cyc_mutators[i] = thd; + return; + } + } + // TODO: unable to create any more mutators. what to do??? + fprintf(stderr, "Unable to create a new thread, exiting\n"); + exit(1); +} + gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) { gc_free_list *free, *next; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index aaf8d84a..dbf06449 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -126,6 +126,7 @@ void vpbuffer_free(void **buf); /* GC prototypes */ void gc_init_mutators(); +void gc_add_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); void *gc_try_alloc(gc_heap *h, size_t size); From dfc8bb76b5596e3a3b80963ffbe6a30b129e62e9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 12 Nov 2015 21:40:26 -0500 Subject: [PATCH 142/339] Fixes --- gc.c | 2 +- include/cyclone/runtime-main.h | 2 +- include/cyclone/runtime.h | 2 +- include/cyclone/types.h | 2 +- runtime.c | 4 ++-- scheme/cyclone/cgen.sld | 16 +++++++++------- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/gc.c b/gc.c index 103afa85..ea8218e4 100644 --- a/gc.c +++ b/gc.c @@ -779,7 +779,7 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_stage = STAGE_SWEEPING; // //sweep : - max_freed = gc_sweep(Cyc_get_heap(), &freed); + max_freed = gc_sweep(gc_get_heap(), &freed); // TODO: grow heap if it is mostly full after collection?? //#if GC_DEBUG_CONCISE_PRINTFS printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index a0487d0f..7a3264da 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -27,7 +27,7 @@ static void Cyc_heap_init(long heap_size) #if DEBUG_SHOW_DIAG printf("main: Allocating and initializing heap...\n"); #endif - gc_init_heap(); + gc_init_heap(heap_size); gc_init_mutators(); gc_start_collector(); } diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 03475028..8e9b8193 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -84,7 +84,7 @@ object cell_get(object cell); extern object Cyc_global_variables; int _cyc_argc; char **_cyc_argv; -void Cyc_init_heap(long heap_size); +void gc_init_heap(long heap_size); object Cyc_get_global_variables(); object Cyc_get_cvar(object var); object Cyc_set_cvar(object var, object value); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index dbf06449..68cdf0e4 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -154,7 +154,7 @@ void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); void gc_start_collector(); -gc_heap *Cyc_get_heap(); +gc_heap *gc_get_heap(); ///////////////////////////////////////////// // GC Collection cycle diff --git a/runtime.c b/runtime.c index e8fc4d5e..1e3107c5 100644 --- a/runtime.c +++ b/runtime.c @@ -90,12 +90,12 @@ char **_cyc_argv = NULL; static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of custom type const object Cyc_EOF = &__EOF; -void Cyc_init_heap(long heap_size) +void gc_init_heap(long heap_size) { Cyc_heap = gc_heap_create(heap_size, 0, 0); } -gc_heap *Cyc_get_heap() +gc_heap *gc_get_heap() { return Cyc_heap; } diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 00e936f9..2c218a1d 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -74,19 +74,21 @@ (define *c-main-function* "main(int argc,char **argv) -{long stack_size = global_stack_size = STACK_SIZE; +{gc_thread_data *thd; + long stack_size = global_stack_size = STACK_SIZE; long heap_size = global_heap_size = HEAP_SIZE; mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached mclosure0(entry_pt,&c_entry_pt); // First function to execute _cyc_argc = argc; _cyc_argv = argv; Cyc_heap_init(heap_size); - Cyc_mutators[0] = malloc(sizeof(gc_thread_data)); - gc_thread_data_init(Cyc_mutators[0], 0, (char *) &stack_size, stack_size); - Cyc_mutators[0]->gc_cont = &entry_pt; - Cyc_mutators[0]->gc_args[0] = &clos_halt; - Cyc_mutators[0]->gc_num_args = 1; - Cyc_start_thread(Cyc_mutators[0]); + thd = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(thd, 0, (char *) &stack_size, stack_size); + thd->gc_cont = &entry_pt; + thd->gc_args[0] = &clos_halt; + thd->gc_num_args = 1; + gc_add_mutator(thd); + Cyc_start_thread(thd); return 0;}") ;;; Auto-generation of C macros From 60b5256dba1bc3b27c189c595e2f6ce898e577f5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 12 Nov 2015 21:44:36 -0500 Subject: [PATCH 143/339] Fixed compilation errors --- gc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index ea8218e4..791fd28b 100644 --- a/gc.c +++ b/gc.c @@ -51,7 +51,7 @@ void gc_init_mutators() Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); // Here is as good a place as any to do this... - if (pthread_mutex(&(heap_lock), NULL) != 0) { + if (pthread_mutex_init(&(heap_lock), NULL) != 0) { fprintf(stderr, "Unable to initialize heap_lock mutex\n"); exit(1); } @@ -845,7 +845,7 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->last_read = 0; thd->mark_buffer_len = 128; thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); - if (pthread_mutex(&(thd->lock), NULL) != 0) { + if (pthread_mutex_init(&(thd->lock), NULL) != 0) { fprintf(stderr, "Unable to initialize thread mutex\n"); exit(1); } From c4acbe0605418379f35fe811e955af94472d083d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 21:09:20 -0500 Subject: [PATCH 144/339] Added debug code --- gc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gc.c b/gc.c index 791fd28b..f6201c07 100644 --- a/gc.c +++ b/gc.c @@ -768,14 +768,19 @@ void gc_collector() while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_handshake(STATUS_SYNC1); +printf("DEBUG - after handshake sync 1\n"); //mark : gc_handshake(STATUS_SYNC2); +printf("DEBUG - after handshake sync 2\n"); gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); +printf("DEBUG - after post_handshake aync\n"); gc_mark_globals(); gc_wait_handshake(); +printf("DEBUG - after wait_handshake aync\n"); //trace : gc_collector_trace(); +printf("DEBUG - after trace\n"); gc_stage = STAGE_SWEEPING; // //sweep : From f27e4874f29ab9c8e89bc6d8437dbb6a92165576 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 23:37:12 -0500 Subject: [PATCH 145/339] Ensure mutex is unlocked --- gc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gc.c b/gc.c index f6201c07..8f2cea3f 100644 --- a/gc.c +++ b/gc.c @@ -139,6 +139,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) } else { /* Take the whole chunk */ f1->next = f2->next; } + pthread_mutex_unlock(&heap_lock); return f2; } } From d50ae96505c4c14f7d0958f43e40edd3cea549a0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 23:59:34 -0500 Subject: [PATCH 146/339] Initialize mark stack --- gc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index 8f2cea3f..a561dffa 100644 --- a/gc.c +++ b/gc.c @@ -27,7 +27,7 @@ static int gc_stage = STAGE_CLEAR_OR_MARKING; // Does not need sync, only used by collector thread static void **mark_stack = NULL; -static int mark_stack_len = 128; +static int mark_stack_len = 0; static int mark_stack_i = 0; // Lock to protect the heap from concurrent modifications @@ -41,7 +41,7 @@ static int Cyc_num_mutators; // Functions // Perform one-time initialization before mutators can be executed -void gc_init_mutators() +void gc_initialize() { // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? // Will need this list for later use, but only by the collector thread. so it would be @@ -50,6 +50,10 @@ void gc_init_mutators() Cyc_num_mutators = 1; Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); + // Initialize collector's mark stack + mark_stack_len = 128; + mark_stack = vpbuffer_realloc(mark_stack, &(mark_stack_len)); + // Here is as good a place as any to do this... if (pthread_mutex_init(&(heap_lock), NULL) != 0) { fprintf(stderr, "Unable to initialize heap_lock mutex\n"); From 65e2a1a18bd48ca9ce8aaabc21a796eee9c1e4a7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 13 Nov 2015 23:59:40 -0500 Subject: [PATCH 147/339] Refactoring --- include/cyclone/runtime-main.h | 2 +- include/cyclone/types.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 7a3264da..9e7a26f4 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -28,7 +28,7 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif gc_init_heap(heap_size); - gc_init_mutators(); + gc_initialize(); gc_start_collector(); } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 68cdf0e4..685a9a45 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -125,7 +125,7 @@ void **vpbuffer_add(void **buf, int *len, int i, void *obj); void vpbuffer_free(void **buf); /* GC prototypes */ -void gc_init_mutators(); +void gc_initialize(); void gc_add_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); From 1b0e1aed364d9e3d28f6ed2bc1e2eb13da3c83a4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 14 Nov 2015 00:21:02 -0500 Subject: [PATCH 148/339] Decremented wrong variable --- gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gc.c b/gc.c index a561dffa..df20726f 100644 --- a/gc.c +++ b/gc.c @@ -711,7 +711,7 @@ void gc_empty_collector_stack() { // Mark stack is only used by the collector thread, so no sync needed while (mark_stack_i > 0) { // not empty - mark_stack--; + mark_stack_i--; gc_mark_black(mark_stack[mark_stack_i]); } } From f4773216c619dee1dc152dd3d2ba74b44d2e3169 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 14 Nov 2015 00:21:15 -0500 Subject: [PATCH 149/339] Unnecessary getchar --- runtime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 1e3107c5..4804d8b2 100644 --- a/runtime.c +++ b/runtime.c @@ -494,7 +494,9 @@ object Cyc_display(object x, FILE *port) fprintf(port, ")"); break; default: - fprintf(port, "Cyc_display: bad tag x=%ld\n", ((closure)x)->tag); getchar(); exit(0);} + fprintf(port, "Cyc_display: bad tag x=%ld\n", ((closure)x)->tag); + exit(1); + } return quote_void;} object dispatch_write_va(void *data, int argc, object clo, object cont, object x, ...) { From 2be274d1be834dde0669c6da05fbbc3481e66ca7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 14 Nov 2015 02:49:18 -0500 Subject: [PATCH 150/339] Added TODO --- gc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gc.c b/gc.c index df20726f..f0d7df6b 100644 --- a/gc.c +++ b/gc.c @@ -613,6 +613,28 @@ void gc_mark_gray(gc_thread_data *thd, object obj) } } +TODO: +// TODO: before doing this, may want to debug a bit and see what is +// being passed to gc_mut_update. see if those objects tend to have +// any heap refs. may need to add debug code to do that... +// +// +//// This is called from the heap write barrier. The issue here is that +//// this is not called during GC, so obj and some of its refs may be +//// on the stack. So scan all refs and mark the ones that are on the heap +//void gc_mark_gray_rec(gc_thread_data *thd, object obj) +//{ +// int mark; +// +// if (is_object_type(obj)) { +// mark = mark(obj); +// +//// TODO: if we leave red as red and keep going, this could hang +//// if there is a cycle!! +// }&& mark(obj) == gc_color_clear) { // TODO: sync?? +// +//} + void gc_collector_trace() { gc_thread_data *m; From 3d41425e883e8afabcda690d80ba18b73a38939c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 17 Nov 2015 02:05:55 -0500 Subject: [PATCH 151/339] Debugging... --- gc-notes.txt | 8 ++++++++ gc.c | 21 ++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 2af6c93c..55cf5e22 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -3,3 +3,11 @@ Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and b Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. + + +Debugging notes: +__glo_list_91ref - +tag is 0 +car appears corrupt +cdr is set to 0x2 during a segfault. +how could this have happened? this variable should always be assigned a closure diff --git a/gc.c b/gc.c index f0d7df6b..f3f67433 100644 --- a/gc.c +++ b/gc.c @@ -532,9 +532,18 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) int status = ATOMIC_GET(&gc_status_col), stage = ATOMIC_GET(&gc_stage); if (thd->gc_status != STATUS_ASYNC) { +printf("DEBUG - GC sync marking heap obj "); +Cyc_display(old_obj, stdout); +printf(" and new value "); +Cyc_display(value, stdout); +//printf(" for heap object "); +printf("\n"); gc_mark_gray(thd, old_obj); gc_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { +printf("DEBUG - GC async tracing marking heap obj "); +Cyc_display(old_obj, stdout); +printf("\n"); gc_mark_gray(thd, old_obj); } // TODO: concerned there may be an issue here with a stack object @@ -613,7 +622,6 @@ void gc_mark_gray(gc_thread_data *thd, object obj) } } -TODO: // TODO: before doing this, may want to debug a bit and see what is // being passed to gc_mut_update. see if those objects tend to have // any heap refs. may need to add debug code to do that... @@ -710,10 +718,17 @@ void gc_mark_black(object obj) } break; } + case cvar_tag: { + gc_collector_mark_gray( *(((cvar_type *)obj)->pvar) ); + break; + } default: break; } - mark(obj) = markColor; + if (mark(obj) != gc_color_red) { + // Only blacken objects on the heap + mark(obj) = markColor; + } } } @@ -828,7 +843,7 @@ void *collector_main(void *arg) // this is inefficient but it should be good enough to // at least stand up this collector. then we'll have to // come back and improve it - sleep(1); +// sleep(1); } } From 426bfe03650e308c9581232f32fef6649e688f7d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 16 Nov 2015 23:06:26 -0500 Subject: [PATCH 152/339] Added additional locking --- gc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gc.c b/gc.c index f3f67433..f7bc528f 100644 --- a/gc.c +++ b/gc.c @@ -583,8 +583,10 @@ void gc_mut_cooperate(gc_thread_data *thd) if (thd->gc_status != status) { if (thd->gc_status == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection + pthread_mutex_lock(&(thd->lock)); thd->last_write = 0; thd->last_read = 0; + pthread_mutex_unlock(&(thd->lock)); } else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" From b609e1556f3753b40ae684f6acfb847a9d8d2bdc Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 17 Nov 2015 23:29:57 -0500 Subject: [PATCH 153/339] WIP --- gc.c | 16 +++++++++++----- runtime.c | 26 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index f7bc528f..1cfc1759 100644 --- a/gc.c +++ b/gc.c @@ -793,6 +793,11 @@ void gc_wait_handshake() ///////////////////////////////////////////// // GC Collection cycle +//TODO: create function to print globals, ideally want names and the mark flag. +//then call before/after tracing to see if we can catch a global not being marked. +//want to rule out an issue here, since we have seen globals that were corrupted (IE, appears they were collected) +void debug_dump_globals(); + // Main collector function void gc_collector() { @@ -812,19 +817,20 @@ void gc_collector() while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_handshake(STATUS_SYNC1); -printf("DEBUG - after handshake sync 1\n"); +//printf("DEBUG - after handshake sync 1\n"); //mark : gc_handshake(STATUS_SYNC2); -printf("DEBUG - after handshake sync 2\n"); +//printf("DEBUG - after handshake sync 2\n"); gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); -printf("DEBUG - after post_handshake aync\n"); +//printf("DEBUG - after post_handshake aync\n"); gc_mark_globals(); gc_wait_handshake(); -printf("DEBUG - after wait_handshake aync\n"); +//printf("DEBUG - after wait_handshake aync\n"); //trace : gc_collector_trace(); -printf("DEBUG - after trace\n"); +//printf("DEBUG - after trace\n"); +debug_dump_globals(); gc_stage = STAGE_SWEEPING; // //sweep : diff --git a/runtime.c b/runtime.c index 4804d8b2..4f7c18d5 100644 --- a/runtime.c +++ b/runtime.c @@ -206,6 +206,27 @@ void add_global(object *glo) { // this is more expedient global_table = mcons(mcvar(glo), global_table); } + +void debug_dump_globals() +{ + list l = global_table; + for(; !nullp(l); l = cdr(l)){ + cvar_type *c = (cvar_type *)car(l); + //gc_mark(h, *(c->pvar)); // Mark actual object the global points to + printf("DEBUG %p ", c->pvar); + if (*c->pvar){ + printf("mark = %d ", mark(*c->pvar)); + if (mark(*c->pvar) == gc_color_red) { + printf("obj = "); + Cyc_display(*c->pvar, stdout); + } + printf("\n"); + } else { + printf(" is NULL\n"); + } + } +} + /* END Global table */ /* Mutation table @@ -2417,7 +2438,10 @@ void gc_mark_globals() list l = global_table; for(; !nullp(l); l = cdr(l)){ cvar_type *c = (cvar_type *)car(l); - gc_mark_black(*(c->pvar)); // Mark actual object the global points to + object glo = *(c->pvar); + if (!nullp(glo)) { + gc_mark_black(glo); // Mark actual object the global points to + } } } } From 56c9d48c89a156ca0bb655ee4ff0d6a848e291b8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 18 Nov 2015 01:21:44 -0500 Subject: [PATCH 154/339] Fixed wait for handshake --- gc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index 1cfc1759..e673ff26 100644 --- a/gc.c +++ b/gc.c @@ -532,16 +532,16 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) int status = ATOMIC_GET(&gc_status_col), stage = ATOMIC_GET(&gc_stage); if (thd->gc_status != STATUS_ASYNC) { -printf("DEBUG - GC sync marking heap obj "); +printf("DEBUG - GC sync marking heap obj %p ", old_obj); Cyc_display(old_obj, stdout); -printf(" and new value "); +printf(" and new value %p ", value); Cyc_display(value, stdout); //printf(" for heap object "); printf("\n"); gc_mark_gray(thd, old_obj); gc_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { -printf("DEBUG - GC async tracing marking heap obj "); +printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); Cyc_display(old_obj, stdout); printf("\n"); gc_mark_gray(thd, old_obj); @@ -777,9 +777,14 @@ void gc_wait_handshake() // TODO: same as in other places, need to either sync access to // mutator vars, or ensure only the collector uses them for (i = 0; i < Cyc_num_mutators; i++) { - statusc = ATOMIC_GET(&gc_status_col); - statusm = ATOMIC_GET(&(Cyc_mutators[i]->gc_status)); - if (statusc != statusm) { + while (1) { + statusc = ATOMIC_GET(&gc_status_col); + statusm = ATOMIC_GET(&(Cyc_mutators[i]->gc_status)); + if (statusc == statusm) { + // Handshake succeeded, check next mutator + break; + } + // At least for now, just give up quantum and come back to // this quickly to test again. This probably could be more // efficient. From 4e30e6d551241cef3b984d762470d2b0a749f81c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 17 Nov 2015 21:23:12 -0500 Subject: [PATCH 155/339] Removed printf's, and broken case statement --- gc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index e673ff26..a2874551 100644 --- a/gc.c +++ b/gc.c @@ -532,18 +532,18 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) int status = ATOMIC_GET(&gc_status_col), stage = ATOMIC_GET(&gc_stage); if (thd->gc_status != STATUS_ASYNC) { -printf("DEBUG - GC sync marking heap obj %p ", old_obj); -Cyc_display(old_obj, stdout); -printf(" and new value %p ", value); -Cyc_display(value, stdout); -//printf(" for heap object "); -printf("\n"); +//printf("DEBUG - GC sync marking heap obj %p ", old_obj); +//Cyc_display(old_obj, stdout); +//printf(" and new value %p ", value); +//Cyc_display(value, stdout); +////printf(" for heap object "); +//printf("\n"); gc_mark_gray(thd, old_obj); gc_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { -printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); -Cyc_display(old_obj, stdout); -printf("\n"); +//printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); +//Cyc_display(old_obj, stdout); +//printf("\n"); gc_mark_gray(thd, old_obj); } // TODO: concerned there may be an issue here with a stack object @@ -720,10 +720,10 @@ void gc_mark_black(object obj) } break; } - case cvar_tag: { - gc_collector_mark_gray( *(((cvar_type *)obj)->pvar) ); - break; - } + //case cvar_tag: { + // gc_collector_mark_gray( *(((cvar_type *)obj)->pvar) ); + // break; + //} default: break; } @@ -835,7 +835,7 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); //trace : gc_collector_trace(); //printf("DEBUG - after trace\n"); -debug_dump_globals(); +//debug_dump_globals(); gc_stage = STAGE_SWEEPING; // //sweep : From e4c4148a74837bf0f830b423e0940f25ce4a469b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 17 Nov 2015 23:03:11 -0500 Subject: [PATCH 156/339] Attemping to add write barrier for set operations --- include/cyclone/runtime.h | 3 ++- runtime.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 8e9b8193..e857b586 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -41,7 +41,8 @@ extern const object Cyc_EOF; object cell_get(object cell); -#define global_set(glo,value) (glo=value) +#define global_set(glo,value) Cyc_global_set(data, (object *)&glo, value) +object Cyc_global_set(void *thd, object *glo, object value); /* Variable argument count support diff --git a/runtime.c b/runtime.c index 4f7c18d5..840fc374 100644 --- a/runtime.c +++ b/runtime.c @@ -12,6 +12,16 @@ //int JAE_DEBUG = 0; //int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +TODO: still not good enough, need to be smarter when marking grey objs that are +still on the stack (??). see reg-port in read.sld + +object Cyc_global_set(void *thd, object *glo, object value) +{ + gc_mut_update((gc_thread_data *)thd, *glo, value); + *(glo) = value; + return value; +} + /* Error checking section - type mismatch, num args, etc */ /* Type names to use for error messages */ const char *tag_names[21] = { \ From ee8aec58870ac71fb218a7f336d22a5db0b5654f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 18 Nov 2015 22:44:02 -0500 Subject: [PATCH 157/339] Added stack scanning to write barrier. Does not seem to help, though --- gc-notes.txt | 8 ++---- gc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- runtime.c | 3 -- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 55cf5e22..4009b2fb 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -5,9 +5,5 @@ Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. -Debugging notes: -__glo_list_91ref - -tag is 0 -car appears corrupt -cdr is set to 0x2 during a segfault. -how could this have happened? this variable should always be assigned a closure +TODO: +- add_mutation will need to be brought into thread local data diff --git a/gc.c b/gc.c index a2874551..fa6f18e4 100644 --- a/gc.c +++ b/gc.c @@ -526,7 +526,81 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): ///////////////////////////////////////////// // GC functions called by the Mutator threads -// Write barrier for updates to heap-allocated objects +// Scan the given object and its refs, marking all heap objects. The issue +// here is that the heap's write barrier can be invoked at any time and +// we need to ensure any heap objects affected are traced +void gc_stack_mark_gray(gc_thread_data *thd, object obj) +{ + int color; + + if (is_object_type(obj)) { + color = mark(obj); + if (color == gc_color_clear) { + gc_mark_gray(thd, obj); + } else if (color == gc_color_red) { + gc_stack_mark_refs_gray(thd, obj); + } + } +} + +// Should only be called from above function as a helper +// +// TODO: this will probably hang procssing circular +// references!!!! need to extend this once the concept is proven +// +// ideally would need some way of recording which nodes have +// been visited. trick is that, unlike in other places, the +// nodes may be visited multiple times so cannot destructively +// alter them. +void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj) +{ + switch(type_of(obj)) { + case cons_tag: { + gc_stack_mark_gray(thd, car(obj)); + gc_stack_mark_gray(thd, cdr(obj)); + break; + } + case closure1_tag: + gc_stack_mark_gray(thd, ((closure1) obj)->elt1); + break; + case closure2_tag: + gc_stack_mark_gray(thd, ((closure2) obj)->elt1); + gc_stack_mark_gray(thd, ((closure2) obj)->elt2); + case closure3_tag: + gc_stack_mark_gray(thd, ((closure3) obj)->elt1); + gc_stack_mark_gray(thd, ((closure3) obj)->elt2); + gc_stack_mark_gray(thd, ((closure3) obj)->elt3); + case closure4_tag: + gc_stack_mark_gray(thd, ((closure4) obj)->elt1); + gc_stack_mark_gray(thd, ((closure4) obj)->elt2); + gc_stack_mark_gray(thd, ((closure4) obj)->elt3); + gc_stack_mark_gray(thd, ((closure4) obj)->elt4); + break; + case closureN_tag: { + int i, n = ((closureN) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_stack_mark_gray(thd, ((closureN) obj)->elts[i]); + } + break; + } + case vector_tag: { + int i, n = ((vector) obj)->num_elt; + for (i = 0; i < n; i++) { + gc_stack_mark_gray(thd, ((vector) obj)->elts[i]); + } + break; + } + default: + break; + } +} + +/** +Write barrier for updates to heap-allocated objects +Plans: +The key for this barrier is to identify stack objects that contain +heap references, so they can be marked to avoid collection. +*/ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) { int status = ATOMIC_GET(&gc_status_col), @@ -539,7 +613,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) ////printf(" for heap object "); //printf("\n"); gc_mark_gray(thd, old_obj); - gc_mark_gray(thd, value); + gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { //printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stdout); diff --git a/runtime.c b/runtime.c index 840fc374..ef0d3bdd 100644 --- a/runtime.c +++ b/runtime.c @@ -12,9 +12,6 @@ //int JAE_DEBUG = 0; //int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; -TODO: still not good enough, need to be smarter when marking grey objs that are -still on the stack (??). see reg-port in read.sld - object Cyc_global_set(void *thd, object *glo, object value) { gc_mut_update((gc_thread_data *)thd, *glo, value); From fc29269a26306e17806ea23100e480f7a490f8ba Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 02:51:22 -0500 Subject: [PATCH 158/339] Debugging --- gc.c | 4 ++-- runtime.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index fa6f18e4..9010c4ce 100644 --- a/gc.c +++ b/gc.c @@ -325,7 +325,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) size = gc_heap_align(gc_allocated_bytes(p)); //fprintf(stdout, "check object %p, size = %d\n", p, size); -#if GC_DEBUG_CONCISE_PRINTFS +//#if GC_DEBUG_CONCISE_PRINTFS // DEBUG if (!is_object_type(p)) fprintf(stderr, "sweep: invalid object at %p", p); @@ -334,7 +334,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (r && ((char *)p) + size > (char *)r) fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); // END DEBUG -#endif +//#endif if (mark(p) == gc_color_clear) { #if GC_DEBUG_PRINTFS diff --git a/runtime.c b/runtime.c index ef0d3bdd..5ec6623f 100644 --- a/runtime.c +++ b/runtime.c @@ -2784,7 +2784,7 @@ void GC(void *data, closure cont, object *args, int num_args) scani++; } -//fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); +fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); // // Check if we need to do a major GC // if (heap_grown) { From 173e1ca407be471a4db08c3caa56e4078d08e5b7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 02:57:32 -0500 Subject: [PATCH 159/339] At least for now, exit on error so we can try to track them down --- gc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 9010c4ce..5b7bb0d1 100644 --- a/gc.c +++ b/gc.c @@ -327,12 +327,18 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) //#if GC_DEBUG_CONCISE_PRINTFS // DEBUG - if (!is_object_type(p)) + if (!is_object_type(p)) { fprintf(stderr, "sweep: invalid object at %p", p); - if ((char *)q + q->size > (char *)p) + exit(1); + } + if ((char *)q + q->size > (char *)p) { fprintf(stderr, "bad size at %p < %p + %u", p, q, q->size); - if (r && ((char *)p) + size > (char *)r) + exit(1); + } + if (r && ((char *)p) + size > (char *)r) { fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); + exit(1); + } // END DEBUG //#endif From 8bf20a05b5da1a61cae95b8a2ee944737044d8c0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 23:00:53 -0500 Subject: [PATCH 160/339] Copy objects into heap while we have the heap lock Attempting to prevent issues with unitialized memory. Unfortunately this is not the primary cause of the errors. --- gc.c | 163 +++++++++++++++++++++++++++++++++++++++- include/cyclone/types.h | 5 +- runtime.c | 113 ++++++---------------------- 3 files changed, 183 insertions(+), 98 deletions(-) diff --git a/gc.c b/gc.c index 5b7bb0d1..480d7b51 100644 --- a/gc.c +++ b/gc.c @@ -109,6 +109,159 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) return h; } +// Copy given object into given heap object +char *gc_copy_obj(object dest, char *obj, gc_thread_data *thd) +{ + // NOTE: no additional type checking because this is called from gc_move + // which already does that + + switch(type_of(obj)){ + case cons_tag: { + list hp = dest; + hp->hdr.mark = thd->gc_alloc_color; + type_of(hp) = cons_tag; + car(hp) = car(obj); + cdr(hp) = cdr(obj); + return (char *)hp; + } + case macro_tag: { + macro_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = macro_tag; + hp->fn = ((macro) obj)->fn; + hp->num_args = ((macro) obj)->num_args; + return (char *)hp; + } + case closure0_tag: { + closure0_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closure0_tag; + hp->fn = ((closure0) obj)->fn; + hp->num_args = ((closure0) obj)->num_args; + return (char *)hp; + } + case closure1_tag: { + closure1_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closure1_tag; + hp->fn = ((closure1) obj)->fn; + hp->num_args = ((closure1) obj)->num_args; + hp->elt1 = ((closure1) obj)->elt1; + return (char *)hp; + } + case closure2_tag: { + closure2_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closure2_tag; + hp->fn = ((closure2) obj)->fn; + hp->num_args = ((closure2) obj)->num_args; + hp->elt1 = ((closure2) obj)->elt1; + hp->elt2 = ((closure2) obj)->elt2; + return (char *)hp; + } + case closure3_tag: { + closure3_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closure3_tag; + hp->fn = ((closure3) obj)->fn; + hp->num_args = ((closure3) obj)->num_args; + hp->elt1 = ((closure3) obj)->elt1; + hp->elt2 = ((closure3) obj)->elt2; + hp->elt3 = ((closure3) obj)->elt3; + return (char *)hp; + } + case closure4_tag: { + closure4_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closure4_tag; + hp->fn = ((closure4) obj)->fn; + hp->num_args = ((closure4) obj)->num_args; + hp->elt1 = ((closure4) obj)->elt1; + hp->elt2 = ((closure4) obj)->elt2; + hp->elt3 = ((closure4) obj)->elt3; + hp->elt4 = ((closure4) obj)->elt4; + return (char *)hp; + } + case closureN_tag: { + int i; + closureN_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = closureN_tag; + hp->fn = ((closureN) obj)->fn; + hp->num_args = ((closureN) obj)->num_args; + hp->num_elt = ((closureN) obj)-> num_elt; + hp->elts = (object *)(((char *)hp) + sizeof(closureN_type)); + for (i = 0; i < hp->num_elt; i++) { + hp->elts[i] = ((closureN) obj)->elts[i]; + } + return (char *)hp; + } + case vector_tag: { + int i; + vector_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = vector_tag; + hp->num_elt = ((vector) obj)-> num_elt; + hp->elts = (object *)(((char *)hp) + sizeof(vector_type)); + for (i = 0; i < hp->num_elt; i++) { + hp->elts[i] = ((vector) obj)->elts[i]; + } + return (char *)hp; + } + case string_tag: { + char *s; + string_type *hp = dest; + s = ((char *)hp) + sizeof(string_type); + memcpy(s, string_str(obj), string_len(obj) + 1); + mark(hp) = thd->gc_alloc_color; + type_of(hp) = string_tag; + string_len(hp) = string_len(obj); + string_str(hp) = s; + return (char *)hp; + } + case integer_tag: { + integer_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = integer_tag; + hp->value = ((integer_type *) obj)->value; + return (char *)hp; + } + case double_tag: { + double_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = double_tag; + hp->value = ((double_type *) obj)->value; + return (char *)hp; + } + case port_tag: { + port_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = port_tag; + hp->fp = ((port_type *) obj)->fp; + hp->mode = ((port_type *) obj)->mode; + return (char *)hp; + } + case cvar_tag: { + cvar_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = cvar_tag; + hp->pvar = ((cvar_type *) obj)->pvar; + return (char *)hp; + } + case forward_tag: + return (char *)forward(obj); + case eof_tag: + case primitive_tag: + case boolean_tag: + case symbol_tag: + break; + default: + fprintf(stderr, "gc_copy_obj: bad tag obj=%p obj.tag=%ld\n",(object) obj, type_of(obj)); + exit(1); + } + return (char *)obj; +} + int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) { size_t cur_size, new_size; @@ -125,7 +278,7 @@ printf("DEBUG - grew heap\n"); return (h_new != NULL); } -void *gc_try_alloc(gc_heap *h, size_t size) +void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd) { gc_free_list *f1, *f2, *f3; pthread_mutex_lock(&heap_lock); @@ -143,6 +296,8 @@ void *gc_try_alloc(gc_heap *h, size_t size) } else { /* Take the whole chunk */ f1->next = f2->next; } + // Copy object into heap now to avoid any uninitialized memory issues + gc_copy_obj(f2, obj, thd); pthread_mutex_unlock(&heap_lock); return f2; } @@ -157,7 +312,7 @@ void *gc_try_alloc(gc_heap *h, size_t size) // maybe only lock during each individual operation, not for a whole // sweep or alloc -void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) +void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown) { void *result = NULL; size_t max_freed = 0, sum_freed = 0, total_size; @@ -166,7 +321,7 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) // the allowed ratio, try growing heap. // then try realloc. if cannot alloc now, then throw out of memory error size = gc_heap_align(size); - result = gc_try_alloc(h, size); + result = gc_try_alloc(h, size, obj, thd); if (!result) { // TODO: may want to consider not doing this now, and implementing gc_collect as // part of the runtime, since we would have all of the roots, stack args, @@ -181,7 +336,7 @@ void *gc_alloc(gc_heap *h, size_t size, int *heap_grown) gc_grow_heap(h, size, 0); *heap_grown = 1; // } - result = gc_try_alloc(h, size); + result = gc_try_alloc(h, size, obj, thd); if (!result) { fprintf(stderr, "out of memory error allocating %d bytes\n", size); exit(1); // TODO: throw error??? diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 685a9a45..1e2f2703 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -129,8 +129,9 @@ void gc_initialize(); void gc_add_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); -void *gc_try_alloc(gc_heap *h, size_t size); -void *gc_alloc(gc_heap *h, size_t size, int *heap_grown); +char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); +void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd); +void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown); size_t gc_allocated_bytes(object obj); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); diff --git a/runtime.c b/runtime.c index 5ec6623f..f938944e 100644 --- a/runtime.c +++ b/runtime.c @@ -2456,16 +2456,17 @@ void gc_mark_globals() char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; -//gcMoveCountsDEBUG[type_of(obj)]++; +// !!! +// TODO: clean up code below and consolidate with gc_copy_obj in gc.c: +// !!! + + +//gcMoveCountsDEBUG[type_of(obj)]++; //printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ case cons_tag: { - list hp = gc_alloc(Cyc_heap, sizeof(cons_type), heap_grown); // hp ==> new heap object - hp->hdr.mark = thd->gc_alloc_color; - type_of(hp) = cons_tag; - car(hp) = car(obj); - cdr(hp) = cdr(obj); + list hp = gc_alloc(Cyc_heap, sizeof(cons_type), obj, thd, heap_grown); // hp ==> new heap object forward(obj) = hp; type_of(obj) = forward_tag; // keep track of each allocation so we can scan/move @@ -2474,169 +2475,97 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { return (char *)hp; } case macro_tag: { - macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = macro_tag; - hp->fn = ((macro) obj)->fn; - hp->num_args = ((macro) obj)->num_args; + macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closure0_tag: { - closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closure0_tag; - hp->fn = ((closure0) obj)->fn; - hp->num_args = ((closure0) obj)->num_args; + closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closure1_tag: { - closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closure1_tag; - hp->fn = ((closure1) obj)->fn; - hp->num_args = ((closure1) obj)->num_args; - hp->elt1 = ((closure1) obj)->elt1; + closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closure2_tag: { - closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closure2_tag; - hp->fn = ((closure2) obj)->fn; - hp->num_args = ((closure2) obj)->num_args; - hp->elt1 = ((closure2) obj)->elt1; - hp->elt2 = ((closure2) obj)->elt2; + closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closure3_tag: { - closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closure3_tag; - hp->fn = ((closure3) obj)->fn; - hp->num_args = ((closure3) obj)->num_args; - hp->elt1 = ((closure3) obj)->elt1; - hp->elt2 = ((closure3) obj)->elt2; - hp->elt3 = ((closure3) obj)->elt3; + closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closure4_tag: { - closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closure4_tag; - hp->fn = ((closure4) obj)->fn; - hp->num_args = ((closure4) obj)->num_args; - hp->elt1 = ((closure4) obj)->elt1; - hp->elt2 = ((closure4) obj)->elt2; - hp->elt3 = ((closure4) obj)->elt3; - hp->elt4 = ((closure4) obj)->elt4; + closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case closureN_tag: { - int i; closureN_type *hp = gc_alloc(Cyc_heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), - heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = closureN_tag; - hp->fn = ((closureN) obj)->fn; - hp->num_args = ((closureN) obj)->num_args; - hp->num_elt = ((closureN) obj)-> num_elt; - hp->elts = (object *)(((char *)hp) + sizeof(closureN_type)); - for (i = 0; i < hp->num_elt; i++) { - hp->elts[i] = ((closureN) obj)->elts[i]; - } + obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case vector_tag: { - int i; vector_type *hp = gc_alloc(Cyc_heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), - heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = vector_tag; - hp->num_elt = ((vector) obj)-> num_elt; - hp->elts = (object *)(((char *)hp) + sizeof(vector_type)); - for (i = 0; i < hp->num_elt; i++) { - hp->elts[i] = ((vector) obj)->elts[i]; - } + obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case string_tag: { - char *s; string_type *hp = gc_alloc(Cyc_heap, sizeof(string_type) + ((string_len(obj) + 1)), - heap_grown); - s = ((char *)hp) + sizeof(string_type); - memcpy(s, string_str(obj), string_len(obj) + 1); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = string_tag; - string_len(hp) = string_len(obj); - string_str(hp) = s; + obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case integer_tag: { - integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = integer_tag; - hp->value = ((integer_type *) obj)->value; + integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case double_tag: { - double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = double_tag; - hp->value = ((double_type *) obj)->value; + double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case port_tag: { - port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = port_tag; - hp->fp = ((port_type *) obj)->fp; - hp->mode = ((port_type *) obj)->mode; + port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); return (char *)hp; } case cvar_tag: { - cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), heap_grown); - mark(hp) = thd->gc_alloc_color; - type_of(hp) = cvar_tag; - hp->pvar = ((cvar_type *) obj)->pvar; + cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown); forward(obj) = hp; type_of(obj) = forward_tag; gc_thr_add_to_move_buffer(thd, alloci, hp); @@ -2649,7 +2578,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { case boolean_tag: break; case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag) default: - fprintf(stderr, "gc_move: bad tag x=%p x.tag=%ld\n",(object) obj, type_of(obj)); + fprintf(stderr, "gc_move: bad tag obj=%p obj.tag=%ld\n",(object) obj, type_of(obj)); exit(1); } return (char *)obj; From 8945773e1ce8359fd3ed4455de32931fb977adfd Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 23:09:27 -0500 Subject: [PATCH 161/339] Added notes --- gc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gc.c b/gc.c index 480d7b51..9b2cc8a0 100644 --- a/gc.c +++ b/gc.c @@ -1091,6 +1091,13 @@ void *collector_main(void *arg) // this is inefficient but it should be good enough to // at least stand up this collector. then we'll have to // come back and improve it +// +// some ideas: +// - maybe check amount of free space in heap, and collect if less than a certain amount/percentage. +// otherwise just sleep for awhile and check again. +// once that works, might consider a way to let a mutator alert the collector that it should kick off +// - after collection, maybe grow heap if usage is above a certain percentage +// // sleep(1); } } From 2de1ce0d5c29feeba29fa621cf0d2a8f8549242f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 20 Nov 2015 02:05:10 -0500 Subject: [PATCH 162/339] Added missing prototypes, init mark in make_cons --- include/cyclone/types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 1e2f2703..75cae0a5 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -146,6 +146,8 @@ void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mut_update(gc_thread_data *thd, object old_obj, object value); void gc_mut_cooperate(gc_thread_data *thd); +void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj); +void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); void gc_mark_black(object obj); @@ -342,7 +344,7 @@ typedef cons_type *list; #define cddddr(x) (cdr(cdr(cdr(cdr(x))))) #define make_cons(n,a,d) \ -cons_type n; n.tag = cons_tag; n.cons_car = a; n.cons_cdr = d; +cons_type n; n.hdr.mark = gc_color_red; n.tag = cons_tag; n.cons_car = a; n.cons_cdr = d; /* Closure types */ From d1acb301c191bcf7a5421a7637cbfab0d7167a81 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 20 Nov 2015 02:12:11 -0500 Subject: [PATCH 163/339] Initialize mark for load_varargs --- include/cyclone/runtime.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index e857b586..240abbaf 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -72,6 +72,7 @@ object Cyc_global_set(void *thd, object *glo, object value); } else { \ tmp = arg_var; \ } \ + var[i].hdr.mark = gc_color_red; \ var[i].tag = cons_tag; \ var[i].cons_car = tmp; \ var[i].cons_cdr = (i == (count-1)) ? nil : &var[i + 1]; \ From ec6140b3a4d304ca8d4034138f129b2d900e41d9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 20 Nov 2015 02:50:46 -0500 Subject: [PATCH 164/339] Ensure stack objects are properly marked --- runtime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime.c b/runtime.c index f938944e..f65df1c7 100644 --- a/runtime.c +++ b/runtime.c @@ -939,10 +939,12 @@ common_type Cyc_string2number(void *data, object str){ n = atof(((string_type *) str)->str); if (ceilf(n) == n) { + result.integer_t.hdr.mark = gc_color_red; result.integer_t.tag = integer_tag; result.integer_t.value = (int)n; } else { + result.double_t.hdr.mark = gc_color_red; result.double_t.tag = double_tag; result.double_t.value = n; } From 91e018c78b9ed71a6d414f4845b52a97d8ebaba6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 20 Nov 2015 02:56:59 -0500 Subject: [PATCH 165/339] Testing in isolation without gc_sweep enabled --- gc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 9b2cc8a0..c43cf0f5 100644 --- a/gc.c +++ b/gc.c @@ -692,10 +692,23 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): // we need to ensure any heap objects affected are traced void gc_stack_mark_gray(gc_thread_data *thd, object obj) { + char tmp; + object low_limit = &tmp; + object high_limit = ((gc_thread_data *)thd)->stack_start; int color; if (is_object_type(obj)) { color = mark(obj); +// TODO: no need to run this all the time. enclose in an "ifdef DEBUG" once +// the GC is stabilized +if (check_overflow(low_limit, obj) && + check_overflow(obj, high_limit) && + color != gc_color_red){ + printf("stack object has wrong color %d!\n", color); + Cyc_display(obj, stdout); + printf("\n"); + exit(1); +} if (color == gc_color_clear) { gc_mark_gray(thd, obj); } else if (color == gc_color_red) { @@ -1074,7 +1087,7 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_stage = STAGE_SWEEPING; // //sweep : - max_freed = gc_sweep(gc_get_heap(), &freed); + //max_freed = gc_sweep(gc_get_heap(), &freed); // TODO: grow heap if it is mostly full after collection?? //#if GC_DEBUG_CONCISE_PRINTFS printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", From 2215807a7cdf6af20792cac28c9653eb57bd85a7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 21:18:52 -0500 Subject: [PATCH 166/339] WIP, need to get sweep (trace?) working --- gc.c | 5 +++-- runtime.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index c43cf0f5..29f7be1d 100644 --- a/gc.c +++ b/gc.c @@ -787,7 +787,8 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) ////printf(" for heap object "); //printf("\n"); gc_mark_gray(thd, old_obj); - gc_stack_mark_gray(thd, value); + // TODO: need this too??? + //gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { //printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stdout); @@ -1087,7 +1088,7 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); gc_stage = STAGE_SWEEPING; // //sweep : - //max_freed = gc_sweep(gc_get_heap(), &freed); + max_freed = gc_sweep(gc_get_heap(), &freed); // TODO: grow heap if it is mostly full after collection?? //#if GC_DEBUG_CONCISE_PRINTFS printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", diff --git a/runtime.c b/runtime.c index f65df1c7..0d33c4d9 100644 --- a/runtime.c +++ b/runtime.c @@ -2715,7 +2715,7 @@ void GC(void *data, closure cont, object *args, int num_args) scani++; } -fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); +//fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); // // Check if we need to do a major GC // if (heap_grown) { From b4659a563a2129ee05b6604928221259305c040b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 19 Nov 2015 23:00:41 -0500 Subject: [PATCH 167/339] WIP --- gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 29f7be1d..b85e3cac 100644 --- a/gc.c +++ b/gc.c @@ -788,7 +788,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //printf("\n"); gc_mark_gray(thd, old_obj); // TODO: need this too??? - //gc_stack_mark_gray(thd, value); + gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { //printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stdout); @@ -969,6 +969,8 @@ void gc_mark_black(object obj) } break; } +TODO:??? should not matter t hough? +maybe open this up but error out if we drop into it? //case cvar_tag: { // gc_collector_mark_gray( *(((cvar_type *)obj)->pvar) ); // break; From f5c60589b08becdf483a47af9f34d13bed296def Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 21 Nov 2015 01:45:23 -0500 Subject: [PATCH 168/339] Debugging --- gc.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index b85e3cac..6d41c738 100644 --- a/gc.c +++ b/gc.c @@ -499,7 +499,10 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (mark(p) == gc_color_clear) { #if GC_DEBUG_PRINTFS - fprintf(stdout, "sweep: object is not marked %p\n", p); + //fprintf(stdout, "sweep: object is not marked %p\n", p); + fprintf(stdout, "sweeping obj: %p ", p); + Cyc_display(p, stdout); + fprintf(stdout, "\n"); #endif mark(p) = gc_color_blue; // Needed? // free p @@ -969,12 +972,14 @@ void gc_mark_black(object obj) } break; } -TODO:??? should not matter t hough? -maybe open this up but error out if we drop into it? - //case cvar_tag: { - // gc_collector_mark_gray( *(((cvar_type *)obj)->pvar) ); - // break; - //} + case cvar_tag: { + cvar_type *c = (cvar_type *)obj; + object pvar = *(c->pvar); + if (pvar) { + gc_collector_mark_gray(pvar); + } + break; + } default: break; } From d13327cfd40968e80ad1b51835f7d462d0394f6d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 21 Nov 2015 02:14:57 -0500 Subject: [PATCH 169/339] Debugging --- gc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gc.c b/gc.c index 6d41c738..fe05c426 100644 --- a/gc.c +++ b/gc.c @@ -499,10 +499,10 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (mark(p) == gc_color_clear) { #if GC_DEBUG_PRINTFS - //fprintf(stdout, "sweep: object is not marked %p\n", p); - fprintf(stdout, "sweeping obj: %p ", p); - Cyc_display(p, stdout); - fprintf(stdout, "\n"); + fprintf(stdout, "sweep: object is not marked %p\n", p); + //fprintf(stdout, "sweep is freeing obj: %p ", p); + //Cyc_display(p, stdout); + //fprintf(stdout, "\n"); #endif mark(p) = gc_color_blue; // Needed? // free p From 469cfa4c08ea4f044c6246972576e20d73f1aad4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 21 Nov 2015 02:57:32 -0500 Subject: [PATCH 170/339] Debugging - how could gc_sweep/p be a value type? --- gc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index fe05c426..f212b1bb 100644 --- a/gc.c +++ b/gc.c @@ -345,14 +345,23 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea #if GC_DEBUG_PRINTFS fprintf(stdout, "alloc %p size = %d\n", result, size); #endif + +// TODO: Debug check, remove (ifdef it) once GC is stabilized +if (is_value_type(result)) { + printf("Invalid allocated address - is a value type %p\n", result); +} + return result; } size_t gc_allocated_bytes(object obj) { tag_type t; - if (is_value_type(obj)) - return gc_heap_align(1); + if (is_value_type(obj)) { + fprintf(stdout, "gc_allocated_bytes - passed value type %p\n", obj); + exit(1); + //return gc_heap_align(1); + } t = type_of(obj); if (t == cons_tag) return gc_heap_align(sizeof(cons_type)); if (t == macro_tag) return gc_heap_align(sizeof(macro_type)); From 3e7877b402f68ab6b4ad7e47a8eb2ec42de8a500 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 24 Nov 2015 23:09:49 -0500 Subject: [PATCH 171/339] Working around mark-free-list problem for now, need to revisit this. --- gc.c | 2 +- include/cyclone/types.h | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index f212b1bb..88ffeb52 100644 --- a/gc.c +++ b/gc.c @@ -17,7 +17,7 @@ // Note: will need to use atomics and/or locking to access any // variables shared between threads -static int gc_color_mark = 2; // Black, is swapped during GC +static int gc_color_mark = 1; // Black, is swapped during GC static int gc_color_clear = 3; // White, is swapped during GC //static const int gc_color_grey = 4; // TODO: appears unused, clean up // unfortunately this had to be split up; const colors are located in types.h diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 75cae0a5..c3c7ab45 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -65,6 +65,9 @@ struct gc_thread_data_t { typedef struct gc_free_list_t gc_free_list; struct gc_free_list_t { +// somehow this size param is being overwritten by a "mark() =". +// how could that happen? +unsigned int dummy; // just for testing/evaluation unsigned int size; gc_free_list *next; }; @@ -117,7 +120,7 @@ typedef enum { STAGE_CLEAR_OR_MARKING // The mark/clear colors are defined in the gc module because // the collector swaps their values as an optimization. #define gc_color_red 0 // Memory not to be GC'd, such as on the stack -#define gc_color_blue 1 // Unallocated memory +#define gc_color_blue 2 // Unallocated memory /* Utility functions */ void **vpbuffer_realloc(void **buf, int *len); From b6dc8c8285b6252ce8f9fdda4c40d6c2e6c62e78 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 24 Nov 2015 23:18:24 -0500 Subject: [PATCH 172/339] Added notes --- include/cyclone/types.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index c3c7ab45..5bfba6a1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -67,7 +67,12 @@ typedef struct gc_free_list_t gc_free_list; struct gc_free_list_t { // somehow this size param is being overwritten by a "mark() =". // how could that happen? -unsigned int dummy; // just for testing/evaluation +somehow it appears free list pointers are being used where heap objects are +expected. could this be as simple as objects being sweeped that should not +have been? unfortunately it is harder to figure how why the objects were +sweeped. were they not marked properly? is there a race condition? maybe +more than one issue? what is going on? +unsigned int dummy; // just for testing/evaluation, this line is NOT a fix!! unsigned int size; gc_free_list *next; }; From 46dff7fc38b45ac460d490dd6412405e8e63dc68 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 24 Nov 2015 23:29:44 -0500 Subject: [PATCH 173/339] notes --- include/cyclone/types.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 5bfba6a1..fe0cfc26 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -67,12 +67,18 @@ typedef struct gc_free_list_t gc_free_list; struct gc_free_list_t { // somehow this size param is being overwritten by a "mark() =". // how could that happen? -somehow it appears free list pointers are being used where heap objects are -expected. could this be as simple as objects being sweeped that should not -have been? unfortunately it is harder to figure how why the objects were -sweeped. were they not marked properly? is there a race condition? maybe -more than one issue? what is going on? -unsigned int dummy; // just for testing/evaluation, this line is NOT a fix!! +//somehow it appears free list pointers are being used where heap objects are +//expected. could this be as simple as objects being sweeped that should not +//have been? unfortunately it is harder to figure how why the objects were +//sweeped. were they not marked properly? is there a race condition? maybe +//more than one issue? what is going on? +// +// the following line does not solve the problem. in fact, with this in +// place there are still cases where the tag is a multiple of 32, implying +// again that a free list node is being used as a heap object. IE, the +// size value is being read into the tag field by code expecting a heap obj. +// +//unsigned int dummy; // just for testing/evaluation, this line is NOT a fix!! unsigned int size; gc_free_list *next; }; From 6ad6f6e254fe563ab17f48da355436906015d419 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 25 Nov 2015 02:58:05 -0500 Subject: [PATCH 174/339] Added debug traces --- gc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 88ffeb52..9a34e7bd 100644 --- a/gc.c +++ b/gc.c @@ -481,9 +481,9 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if ((char *)r == (char *)p) { // this is a free block, skip it p = (object) (((char *)p) + r->size); -#if GC_DEBUG_PRINTFS +//#if GC_DEBUG_PRINTFS fprintf(stdout, "skip free block %p size = %d\n", p, r->size); -#endif +//#endif continue; } size = gc_heap_align(gc_allocated_bytes(p)); @@ -806,6 +806,9 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //Cyc_display(old_obj, stdout); //printf("\n"); gc_mark_gray(thd, old_obj); + printf("added to mark buffer (trace) from write barrier %p:", old_obj); + Cyc_display(old_obj, stdout); + printf("\n"); } // TODO: concerned there may be an issue here with a stack object // having a 'tree' of references that contains heap objects. these @@ -1099,7 +1102,7 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); //printf("DEBUG - after wait_handshake aync\n"); //trace : gc_collector_trace(); -//printf("DEBUG - after trace\n"); +printf("DEBUG - after trace\n"); //debug_dump_globals(); gc_stage = STAGE_SWEEPING; // From ff1fc10a90057dcd63e7aa8951c9e672b67efbc7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 25 Nov 2015 23:46:50 -0500 Subject: [PATCH 175/339] Added debug statements --- gc.c | 20 ++++++++++---------- include/cyclone/types.h | 2 +- runtime.c | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/gc.c b/gc.c index 9a34e7bd..906e7d13 100644 --- a/gc.c +++ b/gc.c @@ -354,11 +354,13 @@ if (is_value_type(result)) { return result; } -size_t gc_allocated_bytes(object obj) +size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r) { tag_type t; if (is_value_type(obj)) { - fprintf(stdout, "gc_allocated_bytes - passed value type %p\n", obj); + fprintf(stdout, + "gc_allocated_bytes - passed value type %p q=[%p, %d] r=[%p, %d]\n", + obj, q, q->size, r, r->size); exit(1); //return gc_heap_align(1); } @@ -486,7 +488,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) //#endif continue; } - size = gc_heap_align(gc_allocated_bytes(p)); + size = gc_heap_align(gc_allocated_bytes(p, q, r)); //fprintf(stdout, "check object %p, size = %d\n", p, size); //#if GC_DEBUG_CONCISE_PRINTFS @@ -507,12 +509,10 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) //#endif if (mark(p) == gc_color_clear) { -#if GC_DEBUG_PRINTFS - fprintf(stdout, "sweep: object is not marked %p\n", p); - //fprintf(stdout, "sweep is freeing obj: %p ", p); - //Cyc_display(p, stdout); - //fprintf(stdout, "\n"); -#endif +//#if GC_DEBUG_PRINTFS + //fprintf(stdout, "sweep: object is not marked %p\n", p); + fprintf(stdout, "sweep is freeing obj: %p with tag %d\n", p, type_of(p)); +//#endif mark(p) = gc_color_blue; // Needed? // free p sum_freed += size; @@ -800,7 +800,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //printf("\n"); gc_mark_gray(thd, old_obj); // TODO: need this too??? - gc_stack_mark_gray(thd, value); + //gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { //printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stdout); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index fe0cfc26..38388f3b 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -146,7 +146,7 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd); void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown); -size_t gc_allocated_bytes(object obj); +size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); //size_t gc_collect(gc_heap *h, size_t *sum_freed); diff --git a/runtime.c b/runtime.c index 0d33c4d9..da652d1e 100644 --- a/runtime.c +++ b/runtime.c @@ -2742,6 +2742,7 @@ void GC(void *data, closure cont, object *args, int num_args) // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data); +printf("done with minor GC\n"); // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } From e95eeb8732fa5e2a841e6ae4642b00a1846786ec Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 25 Nov 2015 23:51:13 -0500 Subject: [PATCH 176/339] Record marking --- gc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gc.c b/gc.c index 906e7d13..f76c7479 100644 --- a/gc.c +++ b/gc.c @@ -998,6 +998,7 @@ void gc_mark_black(object obj) if (mark(obj) != gc_color_red) { // Only blacken objects on the heap mark(obj) = markColor; + printf("marked %p %d\n", obj, markColor); } } } From a257423999ae44f0704b5ff3f0c5715c175ca8f1 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 25 Nov 2015 23:54:16 -0500 Subject: [PATCH 177/339] More debugging --- gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index f76c7479..680b4ea3 100644 --- a/gc.c +++ b/gc.c @@ -342,9 +342,9 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea exit(1); // TODO: throw error??? } } -#if GC_DEBUG_PRINTFS +//#if GC_DEBUG_PRINTFS fprintf(stdout, "alloc %p size = %d\n", result, size); -#endif +//#endif // TODO: Debug check, remove (ifdef it) once GC is stabilized if (is_value_type(result)) { @@ -511,7 +511,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (mark(p) == gc_color_clear) { //#if GC_DEBUG_PRINTFS //fprintf(stdout, "sweep: object is not marked %p\n", p); - fprintf(stdout, "sweep is freeing obj: %p with tag %d\n", p, type_of(p)); + fprintf(stdout, "sweep is freeing obj: %p with tag %ld\n", p, type_of(p)); //#endif mark(p) = gc_color_blue; // Needed? // free p From c8d82f899ffb6353487c892f26ae3c79e72fec76 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 26 Nov 2015 00:15:43 -0500 Subject: [PATCH 178/339] Debug alloc info --- gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 680b4ea3..a2c1b8db 100644 --- a/gc.c +++ b/gc.c @@ -343,7 +343,9 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea } } //#if GC_DEBUG_PRINTFS - fprintf(stdout, "alloc %p size = %d\n", result, size); + fprintf(stdout, "alloc %p size = %d, obj=%p, tag=%ld\n", result, size, obj, type_of(obj)); + //Cyc_display(obj, stdout); + //fprintf(stdout, "\n"); //#endif // TODO: Debug check, remove (ifdef it) once GC is stabilized From 604eb682c51b03e07f90bdd76b542ee86e7c6b0f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 26 Nov 2015 01:52:42 -0500 Subject: [PATCH 179/339] Trace object graph used to mark --- gc.c | 41 ++++++++++++++++++++++------------------- include/cyclone/types.h | 2 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/gc.c b/gc.c index a2c1b8db..84006494 100644 --- a/gc.c +++ b/gc.c @@ -808,9 +808,11 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //Cyc_display(old_obj, stdout); //printf("\n"); gc_mark_gray(thd, old_obj); - printf("added to mark buffer (trace) from write barrier %p:", old_obj); - Cyc_display(old_obj, stdout); - printf("\n"); + if (is_object_type(old_obj)) { + printf("added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); + Cyc_display(old_obj, stdout); + printf("\n"); + } } // TODO: concerned there may be an issue here with a stack object // having a 'tree' of references that contains heap objects. these @@ -952,37 +954,37 @@ void gc_mark_black(object obj) // for cons and vector types, as these pointers could change. switch(type_of(obj)) { case cons_tag: { - gc_collector_mark_gray(car(obj)); - gc_collector_mark_gray(cdr(obj)); + gc_collector_mark_gray(obj, car(obj)); + gc_collector_mark_gray(obj, cdr(obj)); break; } case closure1_tag: - gc_collector_mark_gray(((closure1) obj)->elt1); + gc_collector_mark_gray(obj, ((closure1) obj)->elt1); break; case closure2_tag: - gc_collector_mark_gray(((closure2) obj)->elt1); - gc_collector_mark_gray(((closure2) obj)->elt2); + gc_collector_mark_gray(obj, ((closure2) obj)->elt1); + gc_collector_mark_gray(obj, ((closure2) obj)->elt2); case closure3_tag: - gc_collector_mark_gray(((closure3) obj)->elt1); - gc_collector_mark_gray(((closure3) obj)->elt2); - gc_collector_mark_gray(((closure3) obj)->elt3); + gc_collector_mark_gray(obj, ((closure3) obj)->elt1); + gc_collector_mark_gray(obj, ((closure3) obj)->elt2); + gc_collector_mark_gray(obj, ((closure3) obj)->elt3); case closure4_tag: - gc_collector_mark_gray(((closure4) obj)->elt1); - gc_collector_mark_gray(((closure4) obj)->elt2); - gc_collector_mark_gray(((closure4) obj)->elt3); - gc_collector_mark_gray(((closure4) obj)->elt4); + gc_collector_mark_gray(obj, ((closure4) obj)->elt1); + gc_collector_mark_gray(obj, ((closure4) obj)->elt2); + gc_collector_mark_gray(obj, ((closure4) obj)->elt3); + gc_collector_mark_gray(obj, ((closure4) obj)->elt4); break; case closureN_tag: { int i, n = ((closureN) obj)->num_elt; for (i = 0; i < n; i++) { - gc_collector_mark_gray(((closureN) obj)->elts[i]); + gc_collector_mark_gray(obj, ((closureN) obj)->elts[i]); } break; } case vector_tag: { int i, n = ((vector) obj)->num_elt; for (i = 0; i < n; i++) { - gc_collector_mark_gray(((vector) obj)->elts[i]); + gc_collector_mark_gray(obj, ((vector) obj)->elts[i]); } break; } @@ -990,7 +992,7 @@ void gc_mark_black(object obj) cvar_type *c = (cvar_type *)obj; object pvar = *(c->pvar); if (pvar) { - gc_collector_mark_gray(pvar); + gc_collector_mark_gray(obj, pvar); } break; } @@ -1005,7 +1007,7 @@ void gc_mark_black(object obj) } } -void gc_collector_mark_gray(object obj) +void gc_collector_mark_gray(object parent, object obj) { // "Color" objects gray by adding them to the mark stack for further processing. // @@ -1014,6 +1016,7 @@ void gc_collector_mark_gray(object obj) // could lead to stack corruption. if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); +printf("mark gray parent = %p obj = %p\n", parent, obj); } } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 38388f3b..02ee8f02 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -165,7 +165,7 @@ void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); void gc_mark_black(object obj); -void gc_collector_mark_gray(object obj); +void gc_collector_mark_gray(object parent, object obj); void gc_empty_collector_stack(); void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); From b5849e10ed1c9f8402e917e16bb5b4f305c36d06 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 26 Nov 2015 22:45:22 -0500 Subject: [PATCH 180/339] Added debug traces --- gc.c | 4 +++- runtime.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 84006494..38dcde1a 100644 --- a/gc.c +++ b/gc.c @@ -858,8 +858,10 @@ void gc_mut_cooperate(gc_thread_data *thd) } else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" +printf("gc_cont %p\n", thd->gc_cont); gc_mark_gray(thd, thd->gc_cont); for (i = 0; i < thd->gc_num_args; i++) { +printf("gc_args[%d] %p\n", i, thd->gc_args[i]); gc_mark_gray(thd, thd->gc_args[i]); } thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); @@ -1016,7 +1018,7 @@ void gc_collector_mark_gray(object parent, object obj) // could lead to stack corruption. if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); -printf("mark gray parent = %p obj = %p\n", parent, obj); +printf("mark gray parent = %p (%ld) obj = %p\n", parent, type_of(parent), obj); } } diff --git a/runtime.c b/runtime.c index da652d1e..9114ec66 100644 --- a/runtime.c +++ b/runtime.c @@ -2441,6 +2441,7 @@ void gc_mark_globals() printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); #endif // Mark global variables +printf("Cyc_global_variables %p\n"); gc_mark_black(Cyc_global_variables); // Internal global used by the runtime // Marking it ensures all glos are marked { @@ -2449,6 +2450,7 @@ void gc_mark_globals() cvar_type *c = (cvar_type *)car(l); object glo = *(c->pvar); if (!nullp(glo)) { +printf("global pvar %p\n", glo); gc_mark_black(glo); // Mark actual object the global points to } } From 7276eea7731822899689eca6ee7e683bc6e3094c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 30 Nov 2015 23:00:30 -0500 Subject: [PATCH 181/339] Added debugging --- gc.c | 6 ++++++ runtime.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 38dcde1a..bdce29ae 100644 --- a/gc.c +++ b/gc.c @@ -932,6 +932,9 @@ void gc_collector_trace() while (m->last_read < m->last_write) { clean = 0; (m->last_read)++; +printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", +(m->mark_buffer)[m->last_read], +m->last_read, m->last_write); gc_mark_black((m->mark_buffer)[m->last_read]); gc_empty_collector_stack(); } @@ -1006,6 +1009,9 @@ void gc_mark_black(object obj) mark(obj) = markColor; printf("marked %p %d\n", obj, markColor); } + else { + printf("not marking stack obj %p %d\n", obj, markColor); + } } } diff --git a/runtime.c b/runtime.c index 9114ec66..69b9904d 100644 --- a/runtime.c +++ b/runtime.c @@ -2441,7 +2441,7 @@ void gc_mark_globals() printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); #endif // Mark global variables -printf("Cyc_global_variables %p\n"); +printf("Cyc_global_variables %p\n", Cyc_global_variables); gc_mark_black(Cyc_global_variables); // Internal global used by the runtime // Marking it ensures all glos are marked { From ae46e39c45365cfd07a4ddb513c6c0b6ad8d1afd Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 1 Dec 2015 00:22:54 -0500 Subject: [PATCH 182/339] Added TODO --- gc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gc.c b/gc.c index bdce29ae..2761bc18 100644 --- a/gc.c +++ b/gc.c @@ -932,6 +932,12 @@ void gc_collector_trace() while (m->last_read < m->last_write) { clean = 0; (m->last_read)++; +TODO: I think there is an off-by-one error here. inspect last read/write. +is the code going one too many? per paper it is not, but based on +logs it looks like it is reading past end of buffer. (ie, errors always seem +to be on the last object traced, and checking the history, an object +incorrectly marked at position X can be seen to have been stored at position +X in a previous collection. printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", (m->mark_buffer)[m->last_read], m->last_read, m->last_write); From e29633f2b25f88159fac5a411bb4fc05252dad80 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 1 Dec 2015 03:07:34 -0500 Subject: [PATCH 183/339] Fixed off-by-one error WRT last read/write --- gc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index 2761bc18..eabeb290 100644 --- a/gc.c +++ b/gc.c @@ -931,18 +931,18 @@ void gc_collector_trace() pthread_mutex_lock(&(m->lock)); while (m->last_read < m->last_write) { clean = 0; - (m->last_read)++; -TODO: I think there is an off-by-one error here. inspect last read/write. -is the code going one too many? per paper it is not, but based on -logs it looks like it is reading past end of buffer. (ie, errors always seem -to be on the last object traced, and checking the history, an object -incorrectly marked at position X can be seen to have been stored at position -X in a previous collection. +//TODO: I think there is an off-by-one error here. inspect last read/write. +//is the code going one too many? per paper it is not, but based on +//logs it looks like it is reading past end of buffer. (ie, errors always seem +//to be on the last object traced, and checking the history, an object +//incorrectly marked at position X can be seen to have been stored at position +//X in a previous collection. printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", (m->mark_buffer)[m->last_read], m->last_read, m->last_write); gc_mark_black((m->mark_buffer)[m->last_read]); gc_empty_collector_stack(); + (m->last_read)++; // Inc here to try to prevent off-by-one errors } pthread_mutex_unlock(&(m->lock)); } From 52f0868d24986a3acd9a2e81a9bd7bffcbefabed Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 30 Nov 2015 21:40:16 -0500 Subject: [PATCH 184/339] Selectively compile debug traces --- gc.c | 130 +++++++++++++++++++++------------------- include/cyclone/types.h | 10 +++- runtime.c | 61 +++---------------- 3 files changed, 82 insertions(+), 119 deletions(-) diff --git a/gc.c b/gc.c index eabeb290..4a1ad76c 100644 --- a/gc.c +++ b/gc.c @@ -88,9 +88,7 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) h->size = size; h->chunk_size = chunk_size; h->max_size = max_size; -//printf("DEBUG h->data addr: %p\n", &(h->data)); h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); -//printf("DEBUG h->data addr: %p\n", h->data); h->next = NULL; free = h->free_list = (gc_free_list *)h->data; next = (gc_free_list *)(((char *) free) + gc_heap_align(gc_free_chunk_size)); @@ -99,6 +97,8 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) next->size = size - gc_heap_align(gc_free_chunk_size); next->next = NULL; #if GC_DEBUG_PRINTFS + fprintf(stderr, "DEBUG h->data addr: %p\n", &(h->data)); + fprintf(stderr, "DEBUG h->data addr: %p\n", h->data); fprintf(stderr, ("heap: %p-%p data: %p-%p size: %d\n"), h, ((char*)h)+gc_heap_pad_size(size), h->data, h->data + size, size); fprintf(stderr, ("first: %p end: %p\n"), @@ -274,7 +274,9 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) h_new = gc_heap_create(new_size, h_last->max_size, chunk_size); h_last->next = h_new; pthread_mutex_unlock(&heap_lock); -printf("DEBUG - grew heap\n"); +#if GC_DEBUG_TRACE + printf("DEBUG - grew heap\n"); +#endif return (h_new != NULL); } @@ -342,30 +344,27 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea exit(1); // TODO: throw error??? } } -//#if GC_DEBUG_PRINTFS +#if GC_DEBUG_TRACE fprintf(stdout, "alloc %p size = %d, obj=%p, tag=%ld\n", result, size, obj, type_of(obj)); - //Cyc_display(obj, stdout); - //fprintf(stdout, "\n"); -//#endif - -// TODO: Debug check, remove (ifdef it) once GC is stabilized -if (is_value_type(result)) { - printf("Invalid allocated address - is a value type %p\n", result); -} - + //// TODO: Debug check, remove (ifdef it) once GC is stabilized + //if (is_value_type(result)) { + // printf("Invalid allocated address - is a value type %p\n", result); + //} +#endif return result; } size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r) { tag_type t; +#if GC_SAFETY_CHECKS if (is_value_type(obj)) { fprintf(stdout, "gc_allocated_bytes - passed value type %p q=[%p, %d] r=[%p, %d]\n", obj, q, q->size, r, r->size); exit(1); - //return gc_heap_align(1); } +#endif t = type_of(obj); if (t == cons_tag) return gc_heap_align(sizeof(cons_type)); if (t == macro_tag) return gc_heap_align(sizeof(macro_type)); @@ -388,10 +387,8 @@ size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r) if (t == port_tag) return gc_heap_align(sizeof(port_type)); if (t == cvar_tag) return gc_heap_align(sizeof(cvar_type)); -//#if GC_DEBUG_PRINTFS fprintf(stderr, "gc_allocated_bytes: unexpected object %p of type %ld\n", obj, t); exit(1); -//#endif return 0; } @@ -473,7 +470,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) // pthread_mutex_lock(&heap_lock); for (; h; h = h->next) { // All heaps -#if GC_DEBUG_CONCISE_PRINTFS +#if GC_DEBUG_TRACE fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); #endif p = gc_heap_first_block(h); @@ -485,16 +482,14 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if ((char *)r == (char *)p) { // this is a free block, skip it p = (object) (((char *)p) + r->size); -//#if GC_DEBUG_PRINTFS +#if GC_DEBUG_TRACE fprintf(stdout, "skip free block %p size = %d\n", p, r->size); -//#endif +#endif continue; } size = gc_heap_align(gc_allocated_bytes(p, q, r)); -//fprintf(stdout, "check object %p, size = %d\n", p, size); -//#if GC_DEBUG_CONCISE_PRINTFS - // DEBUG +#if GC_SAFETY_CHECKS if (!is_object_type(p)) { fprintf(stderr, "sweep: invalid object at %p", p); exit(1); @@ -507,14 +502,12 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) fprintf(stderr, "sweep: bad size at %p + %d > %p", p, size, r); exit(1); } - // END DEBUG -//#endif +#endif if (mark(p) == gc_color_clear) { -//#if GC_DEBUG_PRINTFS - //fprintf(stdout, "sweep: object is not marked %p\n", p); - fprintf(stdout, "sweep is freeing obj: %p with tag %ld\n", p, type_of(p)); -//#endif +#if GC_DEBUG_VERBOSE + fprintf(stdout, "sweep is freeing unmarked obj: %p with tag %ld\n", p, type_of(p)); +#endif mark(p) = gc_color_blue; // Needed? // free p sum_freed += size; @@ -549,9 +542,9 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (freed > max_freed) max_freed = freed; } else { -#if GC_DEBUG_PRINTFS +//#if GC_DEBUG_VERBOSE // fprintf(stdout, "sweep: object is marked %p\n", p); -#endif +//#endif p = (object)(((char *)p) + size); } } @@ -573,7 +566,7 @@ void gc_thr_grow_move_buffer(gc_thread_data *d) } d->moveBuf = realloc(d->moveBuf, d->moveBufLen * sizeof(void *)); -#if GC_DEBUG_CONCISE_PRINTFS +#if GC_DEBUG_TRACE printf("grew moveBuffer, len = %d\n", d->moveBufLen); #endif } @@ -713,16 +706,16 @@ void gc_stack_mark_gray(gc_thread_data *thd, object obj) if (is_object_type(obj)) { color = mark(obj); -// TODO: no need to run this all the time. enclose in an "ifdef DEBUG" once -// the GC is stabilized -if (check_overflow(low_limit, obj) && - check_overflow(obj, high_limit) && - color != gc_color_red){ - printf("stack object has wrong color %d!\n", color); - Cyc_display(obj, stdout); - printf("\n"); - exit(1); -} +#if GC_SAFETY_CHECKS + if (check_overflow(low_limit, obj) && + check_overflow(obj, high_limit) && + color != gc_color_red){ + printf("stack object has wrong color %d!\n", color); + Cyc_display(obj, stdout); + printf("\n"); + exit(1); + } +#endif if (color == gc_color_clear) { gc_mark_gray(thd, obj); } else if (color == gc_color_red) { @@ -808,11 +801,13 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //Cyc_display(old_obj, stdout); //printf("\n"); gc_mark_gray(thd, old_obj); +#if GC_DEBUG_VERBOSE if (is_object_type(old_obj)) { printf("added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); Cyc_display(old_obj, stdout); printf("\n"); } +#endif } // TODO: concerned there may be an issue here with a stack object // having a 'tree' of references that contains heap objects. these @@ -858,10 +853,14 @@ void gc_mut_cooperate(gc_thread_data *thd) } else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" +#if GC_DEBUG_VERBOSE printf("gc_cont %p\n", thd->gc_cont); +#endif gc_mark_gray(thd, thd->gc_cont); for (i = 0; i < thd->gc_num_args; i++) { +#if GC_DEBUG_VERBOSE printf("gc_args[%d] %p\n", i, thd->gc_args[i]); +#endif gc_mark_gray(thd, thd->gc_args[i]); } thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); @@ -931,18 +930,14 @@ void gc_collector_trace() pthread_mutex_lock(&(m->lock)); while (m->last_read < m->last_write) { clean = 0; -//TODO: I think there is an off-by-one error here. inspect last read/write. -//is the code going one too many? per paper it is not, but based on -//logs it looks like it is reading past end of buffer. (ie, errors always seem -//to be on the last object traced, and checking the history, an object -//incorrectly marked at position X can be seen to have been stored at position -//X in a previous collection. -printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", -(m->mark_buffer)[m->last_read], -m->last_read, m->last_write); +#if GC_DEBUG_VERBOSE + printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", + (m->mark_buffer)[m->last_read], + m->last_read, m->last_write); +#endif gc_mark_black((m->mark_buffer)[m->last_read]); gc_empty_collector_stack(); - (m->last_read)++; // Inc here to try to prevent off-by-one errors + (m->last_read)++; // Inc here to prevent off-by-one error } pthread_mutex_unlock(&(m->lock)); } @@ -1013,11 +1008,14 @@ void gc_mark_black(object obj) if (mark(obj) != gc_color_red) { // Only blacken objects on the heap mark(obj) = markColor; - printf("marked %p %d\n", obj, markColor); } - else { +#if GC_DEBUG_VERBOSE + if (mark(obj) != gc_color_red) { + printf("marked %p %d\n", obj, markColor); + } else { printf("not marking stack obj %p %d\n", obj, markColor); } +#endif } } @@ -1030,7 +1028,9 @@ void gc_collector_mark_gray(object parent, object obj) // could lead to stack corruption. if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); -printf("mark gray parent = %p (%ld) obj = %p\n", parent, type_of(parent), obj); +#if GC_DEBUG_VERBOSE + printf("mark gray parent = %p (%ld) obj = %p\n", parent, type_of(parent), obj); +#endif } } @@ -1096,9 +1096,9 @@ void gc_collector() { int old_clear, old_mark; size_t freed = 0, max_freed = 0, total_size; -//#if GC_DEBUG_CONCISE_PRINTFS +#if GC_DEBUG_TRACE time_t sweep_start = time(NULL); -//#endif +#endif // TODO: what kind of sync is required here? //clear : @@ -1108,7 +1108,9 @@ void gc_collector() old_mark = ATOMIC_GET(&gc_color_mark); while(!ATOMIC_SET_IF_EQ(&gc_color_clear, old_clear, old_mark)){} while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} -printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); +#if GC_DEBUG_TRACE + printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); +#endif gc_handshake(STATUS_SYNC1); //printf("DEBUG - after handshake sync 1\n"); //mark : @@ -1122,17 +1124,19 @@ printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); //printf("DEBUG - after wait_handshake aync\n"); //trace : gc_collector_trace(); -printf("DEBUG - after trace\n"); -//debug_dump_globals(); +#if GC_DEBUG_TRACE + printf("DEBUG - after trace\n"); + //debug_dump_globals(); +#endif gc_stage = STAGE_SWEEPING; // //sweep : max_freed = gc_sweep(gc_get_heap(), &freed); // TODO: grow heap if it is mostly full after collection?? -//#if GC_DEBUG_CONCISE_PRINTFS - printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", - freed, max_freed, time(NULL) - sweep_start); -//#endif +#if GC_DEBUG_TRACE + printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", + freed, max_freed, time(NULL) - sweep_start); +#endif gc_stage = STAGE_RESTING; } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 02ee8f02..ed205e8c 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -180,9 +180,13 @@ gc_heap *gc_get_heap(); //void gc_collector() /* GC debugging flags */ -//#define DEBUG_GC 0 -#define GC_DEBUG_PRINTFS 0 -#define GC_DEBUG_CONCISE_PRINTFS 0 +#define GC_DEBUG_TRACE 0 +#define GC_DEBUG_VERBOSE 0 + +/* Additional runtime checking of the GC system. + This is here because these checks should not be + necessary if GC is working correctly. */ +#define GC_SAFETY_CHECKS 1 /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 diff --git a/runtime.c b/runtime.c index 69b9904d..dad42bbf 100644 --- a/runtime.c +++ b/runtime.c @@ -2408,40 +2408,15 @@ void Cyc_start_thread(gc_thread_data *thd) exit(0); } -//// Collect garbage using mark&sweep algorithm -//// Note non-global roots should be marked prior to calling this function. -//size_t gc_collect(gc_heap *h, size_t *sum_freed) -//{ -//#if GC_DEBUG_CONCISE_PRINTFS -// printf("(heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); -//#endif -// // Mark global variables -// gc_mark(h, Cyc_global_variables); // Internal global used by the runtime -// // Marking it ensures all glos are marked -// { -// list l = global_table; -// for(; !nullp(l); l = cdr(l)){ -// cvar_type *c = (cvar_type *)car(l); -// gc_mark(h, *(c->pvar)); // Mark actual object the global points to -// } -// } -// // TODO: what else to mark? gc_mark( -// // conservative mark? -// // weak refs? -// // finalize? -// return gc_sweep(h, sum_freed); -// // debug print free stats? -//} - // Mark globals as part of the tracing collector // This is called by the collector thread void gc_mark_globals() { -#if GC_DEBUG_CONCISE_PRINTFS +#if GC_DEBUG_TRACE printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + printf("Cyc_global_variables %p\n", Cyc_global_variables); #endif // Mark global variables -printf("Cyc_global_variables %p\n", Cyc_global_variables); gc_mark_black(Cyc_global_variables); // Internal global used by the runtime // Marking it ensures all glos are marked { @@ -2450,7 +2425,9 @@ printf("Cyc_global_variables %p\n", Cyc_global_variables); cvar_type *c = (cvar_type *)car(l); object glo = *(c->pvar); if (!nullp(glo)) { -printf("global pvar %p\n", glo); +#if GC_DEBUG_TRACE + printf("global pvar %p\n", glo); +#endif gc_mark_black(glo); // Mark actual object the global points to } } @@ -2717,34 +2694,12 @@ void GC(void *data, closure cont, object *args, int num_args) scani++; } -//fprintf(stdout, "DEBUG done minor GC, alloci = %d\n", alloci); - -// // Check if we need to do a major GC -// if (heap_grown) { -// size_t freed = 0, max_freed = 0; -//#if GC_DEBUG_CONCISE_PRINTFS -// time_t majorStart = time(NULL); -// fprintf(stdout, "DEBUG, starting major mark/sweep GC\n"); // JAE DEBUG -//#endif -// gc_mark(Cyc_heap, cont); -// for (i = 0; i < num_args; i++){ -// gc_mark(Cyc_heap, args[i]); -// } -// max_freed = gc_collect(Cyc_heap, &freed); -//#if GC_DEBUG_CONCISE_PRINTFS -// printf("done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - majorStart); -// //JAE_DEBUG++; -// //if (JAE_DEBUG == 2) exit(1); // JAE DEBUG -// for (i = 0; i < 20; i++){ -// printf("gcMoveCountsDEBUG[%d] = %d\n", i, gcMoveCountsDEBUG[i]); -// } -//#endif -// } - // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data); -printf("done with minor GC\n"); +#ifdef GC_DEBUG_TRACE + printf("done with minor GC\n"); +#endif // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } From 8452c35fae26293c4a6784c4a89188f228967c19 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 30 Nov 2015 21:41:48 -0500 Subject: [PATCH 185/339] Use #if instead of #ifdef --- runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index dad42bbf..150e38d2 100644 --- a/runtime.c +++ b/runtime.c @@ -2697,7 +2697,7 @@ void GC(void *data, closure cont, object *args, int num_args) // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data); -#ifdef GC_DEBUG_TRACE +#if GC_DEBUG_TRACE printf("done with minor GC\n"); #endif // Let it all go, Neo... From 524e922ee076d56d406c2d564b2df855bf4605d0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 30 Nov 2015 22:22:13 -0500 Subject: [PATCH 186/339] Added temporary SIGINT --- runtime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime.c b/runtime.c index 150e38d2..0d4ce7a6 100644 --- a/runtime.c +++ b/runtime.c @@ -8,6 +8,7 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" +#include // TODO: only used for debugging! //int JAE_DEBUG = 0; //int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; @@ -287,6 +288,7 @@ object Cyc_default_exception_handler(void *data, int argc, closure _, object err fprintf(stderr, "\nCall history:\n"); Cyc_st_print(stderr); fprintf(stderr, "\n"); +raise(SIGINT); // break into debugger, unix only exit(1); return nil; } From c70a69c20242811c3f7956173762e7f4a8cbae1c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 1 Dec 2015 22:41:11 -0500 Subject: [PATCH 187/339] WIP --- gc.c | 42 +++++++++++++++++++++++------------------ include/cyclone/types.h | 2 +- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/gc.c b/gc.c index 4a1ad76c..75e6a952 100644 --- a/gc.c +++ b/gc.c @@ -697,14 +697,14 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): // Scan the given object and its refs, marking all heap objects. The issue // here is that the heap's write barrier can be invoked at any time and // we need to ensure any heap objects affected are traced -void gc_stack_mark_gray(gc_thread_data *thd, object obj) +void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) { char tmp; object low_limit = &tmp; object high_limit = ((gc_thread_data *)thd)->stack_start; int color; - if (is_object_type(obj)) { + if (is_object_type(obj) && depth < 100) { color = mark(obj); #if GC_SAFETY_CHECKS if (check_overflow(low_limit, obj) && @@ -718,12 +718,18 @@ void gc_stack_mark_gray(gc_thread_data *thd, object obj) #endif if (color == gc_color_clear) { gc_mark_gray(thd, obj); + printf("marked heap obj from stack barrier %p %d\n", obj, color); } else if (color == gc_color_red) { - gc_stack_mark_refs_gray(thd, obj); + gc_stack_mark_refs_gray(thd, obj, depth + 1); } } } +void gc_stack_mark_gray(gc_thread_data *thd, object obj) +{ + gc_stack_mark_gray3(thd, obj, 0); +} + // Should only be called from above function as a helper // // TODO: this will probably hang procssing circular @@ -733,41 +739,41 @@ void gc_stack_mark_gray(gc_thread_data *thd, object obj) // been visited. trick is that, unlike in other places, the // nodes may be visited multiple times so cannot destructively // alter them. -void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj) +void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth) { switch(type_of(obj)) { case cons_tag: { - gc_stack_mark_gray(thd, car(obj)); - gc_stack_mark_gray(thd, cdr(obj)); + gc_stack_mark_gray3(thd, car(obj), depth); + gc_stack_mark_gray3(thd, cdr(obj), depth); break; } case closure1_tag: - gc_stack_mark_gray(thd, ((closure1) obj)->elt1); + gc_stack_mark_gray3(thd, ((closure1) obj)->elt1, depth); break; case closure2_tag: - gc_stack_mark_gray(thd, ((closure2) obj)->elt1); - gc_stack_mark_gray(thd, ((closure2) obj)->elt2); + gc_stack_mark_gray3(thd, ((closure2) obj)->elt1, depth); + gc_stack_mark_gray3(thd, ((closure2) obj)->elt2, depth); case closure3_tag: - gc_stack_mark_gray(thd, ((closure3) obj)->elt1); - gc_stack_mark_gray(thd, ((closure3) obj)->elt2); - gc_stack_mark_gray(thd, ((closure3) obj)->elt3); + gc_stack_mark_gray3(thd, ((closure3) obj)->elt1, depth); + gc_stack_mark_gray3(thd, ((closure3) obj)->elt2, depth); + gc_stack_mark_gray3(thd, ((closure3) obj)->elt3, depth); case closure4_tag: - gc_stack_mark_gray(thd, ((closure4) obj)->elt1); - gc_stack_mark_gray(thd, ((closure4) obj)->elt2); - gc_stack_mark_gray(thd, ((closure4) obj)->elt3); - gc_stack_mark_gray(thd, ((closure4) obj)->elt4); + gc_stack_mark_gray3(thd, ((closure4) obj)->elt1, depth); + gc_stack_mark_gray3(thd, ((closure4) obj)->elt2, depth); + gc_stack_mark_gray3(thd, ((closure4) obj)->elt3, depth); + gc_stack_mark_gray3(thd, ((closure4) obj)->elt4, depth); break; case closureN_tag: { int i, n = ((closureN) obj)->num_elt; for (i = 0; i < n; i++) { - gc_stack_mark_gray(thd, ((closureN) obj)->elts[i]); + gc_stack_mark_gray3(thd, ((closureN) obj)->elts[i], depth); } break; } case vector_tag: { int i, n = ((vector) obj)->num_elt; for (i = 0; i < n; i++) { - gc_stack_mark_gray(thd, ((vector) obj)->elts[i]); + gc_stack_mark_gray3(thd, ((vector) obj)->elts[i], depth); } break; } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index ed205e8c..43c58166 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -160,7 +160,7 @@ void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mut_update(gc_thread_data *thd, object old_obj, object value); void gc_mut_cooperate(gc_thread_data *thd); -void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj); +void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_collector_trace(); From ab5d12b8968fc98f5eaf2863b0ab86abae343a5a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 2 Dec 2015 01:01:26 -0500 Subject: [PATCH 188/339] Link with pthread libs --- cyclone.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyclone.scm b/cyclone.scm index ee110c76..e44a283e 100644 --- a/cyclone.scm +++ b/cyclone.scm @@ -286,7 +286,7 @@ (comp-prog-cmd (string-append "gcc " src-file " -g -c -o " exec-file ".o")) (comp-objs-cmd - (string-append "gcc " exec-file ".o " objs-str " -lcyclone -lm -g -o " exec-file))) + (string-append "gcc " exec-file ".o " objs-str " -pthread -lcyclone -lm -g -o " exec-file))) ;(write `(DEBUG all imports ,lib-deps objs ,objs-str)) ;(write `(DEBUG ,(lib:get-all-import-deps (cdar in-prog)))) (cond From f6e14ef3a87cd976deceb439eb513d0b2dd05cd8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 1 Dec 2015 22:34:39 -0500 Subject: [PATCH 189/339] Added debugging --- gc.c | 26 ++++++++++++++++---------- include/cyclone/types.h | 4 ++-- runtime.c | 4 ++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/gc.c b/gc.c index 75e6a952..8fb7e689 100644 --- a/gc.c +++ b/gc.c @@ -345,7 +345,7 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea } } #if GC_DEBUG_TRACE - fprintf(stdout, "alloc %p size = %d, obj=%p, tag=%ld\n", result, size, obj, type_of(obj)); + fprintf(stdout, "alloc %p size = %d, obj=%p, tag=%ld, mark=%d\n", result, size, obj, type_of(obj), mark(((object)result))); //// TODO: Debug check, remove (ifdef it) once GC is stabilized //if (is_value_type(result)) { // printf("Invalid allocated address - is a value type %p\n", result); @@ -704,7 +704,7 @@ void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) object high_limit = ((gc_thread_data *)thd)->stack_start; int color; - if (is_object_type(obj) && depth < 100) { + if (is_object_type(obj) && depth < 15) { color = mark(obj); #if GC_SAFETY_CHECKS if (check_overflow(low_limit, obj) && @@ -718,7 +718,7 @@ void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) #endif if (color == gc_color_clear) { gc_mark_gray(thd, obj); - printf("marked heap obj from stack barrier %p %d\n", obj, color); + //printf("marked heap obj from stack barrier %p %d\n", obj, color); } else if (color == gc_color_red) { gc_stack_mark_refs_gray(thd, obj, depth + 1); } @@ -801,7 +801,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //printf("\n"); gc_mark_gray(thd, old_obj); // TODO: need this too??? - //gc_stack_mark_gray(thd, value); + gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { //printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stdout); @@ -1105,8 +1105,6 @@ void gc_collector() #if GC_DEBUG_TRACE time_t sweep_start = time(NULL); #endif - // TODO: what kind of sync is required here? - //clear : gc_stage = STAGE_CLEAR_OR_MARKING; // exchange values of markColor and clearColor @@ -1118,16 +1116,24 @@ void gc_collector() printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); #endif gc_handshake(STATUS_SYNC1); -//printf("DEBUG - after handshake sync 1\n"); +#if GC_DEBUG_TRACE +printf("DEBUG - after handshake sync 1\n"); +#endif //mark : gc_handshake(STATUS_SYNC2); -//printf("DEBUG - after handshake sync 2\n"); +#if GC_DEBUG_TRACE +printf("DEBUG - after handshake sync 2\n"); +#endif gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); -//printf("DEBUG - after post_handshake aync\n"); +#if GC_DEBUG_TRACE +printf("DEBUG - after post_handshake aync\n"); +#endif gc_mark_globals(); gc_wait_handshake(); -//printf("DEBUG - after wait_handshake aync\n"); +#if GC_DEBUG_TRACE +printf("DEBUG - after wait_handshake aync\n"); +#endif //trace : gc_collector_trace(); #if GC_DEBUG_TRACE diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 43c58166..ea28aadd 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -180,8 +180,8 @@ gc_heap *gc_get_heap(); //void gc_collector() /* GC debugging flags */ -#define GC_DEBUG_TRACE 0 -#define GC_DEBUG_VERBOSE 0 +#define GC_DEBUG_TRACE 1 +#define GC_DEBUG_VERBOSE 1 /* Additional runtime checking of the GC system. This is here because these checks should not be diff --git a/runtime.c b/runtime.c index 0d4ce7a6..efb71564 100644 --- a/runtime.c +++ b/runtime.c @@ -47,7 +47,7 @@ const char *tag_names[21] = { \ void Cyc_invalid_type_error(void *data, int tag, object found) { char buf[256]; - snprintf(buf, 255, "Invalid type: expected %s, found", tag_names[tag]); + snprintf(buf, 255, "Invalid type: expected %s, found (%p) ", tag_names[tag], found); Cyc_rt_raise2(data, buf, found); } @@ -2415,7 +2415,7 @@ void Cyc_start_thread(gc_thread_data *thd) void gc_mark_globals() { #if GC_DEBUG_TRACE - printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + //printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); printf("Cyc_global_variables %p\n", Cyc_global_variables); #endif // Mark global variables From ea6167b90b299329bae013843b93a02c9ed55c27 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 02:51:58 -0500 Subject: [PATCH 190/339] Fixed debug statements --- gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index 8fb7e689..bb54d74b 100644 --- a/gc.c +++ b/gc.c @@ -808,7 +808,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //printf("\n"); gc_mark_gray(thd, old_obj); #if GC_DEBUG_VERBOSE - if (is_object_type(old_obj)) { + if (is_object_type(old_obj) && mark(old_obj) == gc_color_clear) { printf("added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); Cyc_display(old_obj, stdout); printf("\n"); @@ -1127,12 +1127,12 @@ printf("DEBUG - after handshake sync 2\n"); gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); #if GC_DEBUG_TRACE -printf("DEBUG - after post_handshake aync\n"); +printf("DEBUG - after post_handshake async\n"); #endif gc_mark_globals(); gc_wait_handshake(); #if GC_DEBUG_TRACE -printf("DEBUG - after wait_handshake aync\n"); +printf("DEBUG - after wait_handshake async\n"); #endif //trace : gc_collector_trace(); From f4a19959579d9150dbeb9e9c8a869202205b465c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 02:56:20 -0500 Subject: [PATCH 191/339] Added TODO's --- gc-notes.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 4009b2fb..c34408d0 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -4,6 +4,8 @@ Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naiv Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. - TODO: -- add_mutation will need to be brought into thread local data +- need to fix memory corruption bugs +- need to cooperate when a mutator is blocked +- add_mutation will need to be brought into thread local data. +- probably exceptions too. anything else? From d0a5451cf92cad540d8783c7c913a2b971bcf388 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 02:57:15 -0500 Subject: [PATCH 192/339] more notes --- gc-notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index c34408d0..cb92a2cb 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -7,5 +7,7 @@ Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC TODO: - need to fix memory corruption bugs - need to cooperate when a mutator is blocked +- need an intelligent scheduling of GC, instead of just constantly running it - add_mutation will need to be brought into thread local data. - probably exceptions too. anything else? +- multiple mutators, and threading functions/types. probably want this on a new branch, when ready From 51b84301a6c1de4b3d141146c60b27ae7b514ddc Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 2 Dec 2015 23:02:27 -0500 Subject: [PATCH 193/339] Trying to isolate memory corruption issue. May also have an issue with long lists --- test.scm | 1542 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1516 insertions(+), 26 deletions(-) diff --git a/test.scm b/test.scm index ac4233e8..12360999 100644 --- a/test.scm +++ b/test.scm @@ -1,28 +1,1518 @@ -(import (scheme base) - (scheme write) - (scheme read)) +;; A temporary file to attempt to repro crashing / data corruption +(import (scheme base) (scheme write)) -(write `(read ,(+ 1 2 3))) -(write `(read ,(list 1 2 3))) -(write `(read ,@(list 1 2 3))) -;;`(read , -(write (make-vector 4 #t)) -(write (string->list "abc")) -(write (apply append '((1) (2) (3)))) -(write #(a)) -(write #(1 2 3)) -(write #((1) (2) (3))) -(write (eq? #(1) #(1))) -(write (equal? #(1 1 1) (make-vector 3 1))) -(write '#(1)) -(write '#()) +(define lambdas + '( + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) + (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) + (9 ("test")) + )) -(define a (vector 1 2 3 4 5)) -(define b (vector 10 20 30 40 50)) -(vector-copy! b 1 a 0 2) -(write (equal? b #(10 1 2 40 50))) -(call-with-values - (lambda () (values 1 1)) - (lambda (a) (write a))) - -(write (Cyc-stdout)) + (for-each + (lambda (l) + (write (list + "static void __lambda_" + (number->string (car l)) "(void *data, int argc, " + (cdadr l) + ") ;"))) + lambdas) From ef0571b45ef68636bb30d7cf01c9b3d359d40c56 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 23:14:18 -0500 Subject: [PATCH 194/339] Move verbose output to stderr to make runtime logging easier --- gc.c | 76 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/gc.c b/gc.c index bb54d74b..8ca03868 100644 --- a/gc.c +++ b/gc.c @@ -275,7 +275,7 @@ int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size) h_last->next = h_new; pthread_mutex_unlock(&heap_lock); #if GC_DEBUG_TRACE - printf("DEBUG - grew heap\n"); + fprintf(stderr, "DEBUG - grew heap\n"); #endif return (h_new != NULL); } @@ -345,7 +345,7 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea } } #if GC_DEBUG_TRACE - fprintf(stdout, "alloc %p size = %d, obj=%p, tag=%ld, mark=%d\n", result, size, obj, type_of(obj), mark(((object)result))); + fprintf(stderr, "alloc %p size = %d, obj=%p, tag=%ld, mark=%d\n", result, size, obj, type_of(obj), mark(((object)result))); //// TODO: Debug check, remove (ifdef it) once GC is stabilized //if (is_value_type(result)) { // printf("Invalid allocated address - is a value type %p\n", result); @@ -359,7 +359,7 @@ size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r) tag_type t; #if GC_SAFETY_CHECKS if (is_value_type(obj)) { - fprintf(stdout, + fprintf(stderr, "gc_allocated_bytes - passed value type %p q=[%p, %d] r=[%p, %d]\n", obj, q, q->size, r, r->size); exit(1); @@ -417,7 +417,7 @@ size_t gc_heap_total_size(gc_heap *h) // return; // //#if GC_DEBUG_PRINTFS -//// fprintf(stdout, "gc_mark %p\n", obj); +//// fprintf(stderr, "gc_mark %p\n", obj); //#endif // ((list)obj)->hdr.mark = 1; // // TODO: mark heap saves (??) @@ -471,7 +471,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) pthread_mutex_lock(&heap_lock); for (; h; h = h->next) { // All heaps #if GC_DEBUG_TRACE - fprintf(stdout, "sweep heap %p, size = %d\n", h, h->size); + fprintf(stderr, "sweep heap %p, size = %d\n", h, h->size); #endif p = gc_heap_first_block(h); q = h->free_list; @@ -483,7 +483,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if ((char *)r == (char *)p) { // this is a free block, skip it p = (object) (((char *)p) + r->size); #if GC_DEBUG_TRACE - fprintf(stdout, "skip free block %p size = %d\n", p, r->size); + fprintf(stderr, "skip free block %p size = %d\n", p, r->size); #endif continue; } @@ -506,7 +506,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) if (mark(p) == gc_color_clear) { #if GC_DEBUG_VERBOSE - fprintf(stdout, "sweep is freeing unmarked obj: %p with tag %ld\n", p, type_of(p)); + fprintf(stderr, "sweep is freeing unmarked obj: %p with tag %ld\n", p, type_of(p)); #endif mark(p) = gc_color_blue; // Needed? // free p @@ -543,7 +543,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) max_freed = freed; } else { //#if GC_DEBUG_VERBOSE -// fprintf(stdout, "sweep: object is marked %p\n", p); +// fprintf(stderr, "sweep: object is marked %p\n", p); //#endif p = (object)(((char *)p) + size); } @@ -567,7 +567,7 @@ void gc_thr_grow_move_buffer(gc_thread_data *d) d->moveBuf = realloc(d->moveBuf, d->moveBufLen * sizeof(void *)); #if GC_DEBUG_TRACE - printf("grew moveBuffer, len = %d\n", d->moveBufLen); + fprintf(stderr, "grew moveBuffer, len = %d\n", d->moveBufLen); #endif } @@ -710,15 +710,15 @@ void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) if (check_overflow(low_limit, obj) && check_overflow(obj, high_limit) && color != gc_color_red){ - printf("stack object has wrong color %d!\n", color); - Cyc_display(obj, stdout); - printf("\n"); + fprintf(stderr, "stack object has wrong color %d!\n", color); + Cyc_display(obj, stderr); + fprintf(stderr, "\n"); exit(1); } #endif if (color == gc_color_clear) { gc_mark_gray(thd, obj); - //printf("marked heap obj from stack barrier %p %d\n", obj, color); + //fprintf(stderr, "marked heap obj from stack barrier %p %d\n", obj, color); } else if (color == gc_color_red) { gc_stack_mark_refs_gray(thd, obj, depth + 1); } @@ -793,25 +793,25 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) int status = ATOMIC_GET(&gc_status_col), stage = ATOMIC_GET(&gc_stage); if (thd->gc_status != STATUS_ASYNC) { -//printf("DEBUG - GC sync marking heap obj %p ", old_obj); -//Cyc_display(old_obj, stdout); -//printf(" and new value %p ", value); -//Cyc_display(value, stdout); -////printf(" for heap object "); -//printf("\n"); +//fprintf(stderr, "DEBUG - GC sync marking heap obj %p ", old_obj); +//Cyc_display(old_obj, stderr); +//fprintf(stderr, " and new value %p ", value); +//Cyc_display(value, stderr); +////fprintf(stderr, " for heap object "); +//fprintf(stderr, "\n"); gc_mark_gray(thd, old_obj); // TODO: need this too??? gc_stack_mark_gray(thd, value); } else if (stage == STAGE_TRACING) { -//printf("DEBUG - GC async tracing marking heap obj %p ", old_obj); -//Cyc_display(old_obj, stdout); -//printf("\n"); +//fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); +//Cyc_display(old_obj, stderr); +//fprintf(stderr, "\n"); gc_mark_gray(thd, old_obj); #if GC_DEBUG_VERBOSE if (is_object_type(old_obj) && mark(old_obj) == gc_color_clear) { - printf("added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); - Cyc_display(old_obj, stdout); - printf("\n"); + fprintf(stderr, "added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); + Cyc_display(old_obj, stderr); + fprintf(stderr, "\n"); } #endif } @@ -860,12 +860,12 @@ void gc_mut_cooperate(gc_thread_data *thd) else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" #if GC_DEBUG_VERBOSE -printf("gc_cont %p\n", thd->gc_cont); +fprintf(stderr, "gc_cont %p\n", thd->gc_cont); #endif gc_mark_gray(thd, thd->gc_cont); for (i = 0; i < thd->gc_num_args; i++) { #if GC_DEBUG_VERBOSE -printf("gc_args[%d] %p\n", i, thd->gc_args[i]); +fprintf(stderr, "gc_args[%d] %p\n", i, thd->gc_args[i]); #endif gc_mark_gray(thd, thd->gc_args[i]); } @@ -937,7 +937,7 @@ void gc_collector_trace() while (m->last_read < m->last_write) { clean = 0; #if GC_DEBUG_VERBOSE - printf("gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", + fprintf(stderr, "gc_mark_black mark buffer %p, last_read = %d last_write = %d\n", (m->mark_buffer)[m->last_read], m->last_read, m->last_write); #endif @@ -1017,9 +1017,9 @@ void gc_mark_black(object obj) } #if GC_DEBUG_VERBOSE if (mark(obj) != gc_color_red) { - printf("marked %p %d\n", obj, markColor); + fprintf(stderr, "marked %p %d\n", obj, markColor); } else { - printf("not marking stack obj %p %d\n", obj, markColor); + fprintf(stderr, "not marking stack obj %p %d\n", obj, markColor); } #endif } @@ -1035,7 +1035,7 @@ void gc_collector_mark_gray(object parent, object obj) if (is_object_type(obj) && mark(obj) == gc_color_clear) { mark_stack = vpbuffer_add(mark_stack, &mark_stack_len, mark_stack_i++, obj); #if GC_DEBUG_VERBOSE - printf("mark gray parent = %p (%ld) obj = %p\n", parent, type_of(parent), obj); + fprintf(stderr, "mark gray parent = %p (%ld) obj = %p\n", parent, type_of(parent), obj); #endif } } @@ -1113,31 +1113,31 @@ void gc_collector() while(!ATOMIC_SET_IF_EQ(&gc_color_clear, old_clear, old_mark)){} while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} #if GC_DEBUG_TRACE - printf("DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); + fprintf(stderr, "DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); #endif gc_handshake(STATUS_SYNC1); #if GC_DEBUG_TRACE -printf("DEBUG - after handshake sync 1\n"); +fprintf(stderr, "DEBUG - after handshake sync 1\n"); #endif //mark : gc_handshake(STATUS_SYNC2); #if GC_DEBUG_TRACE -printf("DEBUG - after handshake sync 2\n"); +fprintf(stderr, "DEBUG - after handshake sync 2\n"); #endif gc_stage = STAGE_TRACING; gc_post_handshake(STATUS_ASYNC); #if GC_DEBUG_TRACE -printf("DEBUG - after post_handshake async\n"); +fprintf(stderr, "DEBUG - after post_handshake async\n"); #endif gc_mark_globals(); gc_wait_handshake(); #if GC_DEBUG_TRACE -printf("DEBUG - after wait_handshake async\n"); +fprintf(stderr, "DEBUG - after wait_handshake async\n"); #endif //trace : gc_collector_trace(); #if GC_DEBUG_TRACE - printf("DEBUG - after trace\n"); + fprintf(stderr, "DEBUG - after trace\n"); //debug_dump_globals(); #endif gc_stage = STAGE_SWEEPING; @@ -1146,7 +1146,7 @@ printf("DEBUG - after wait_handshake async\n"); max_freed = gc_sweep(gc_get_heap(), &freed); // TODO: grow heap if it is mostly full after collection?? #if GC_DEBUG_TRACE - printf("sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", + fprintf(stderr, "sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", freed, max_freed, time(NULL) - sweep_start); #endif gc_stage = STAGE_RESTING; From 4f0ff11f332192666ea5f961ed55d568de6fb63f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 23:14:42 -0500 Subject: [PATCH 195/339] Attempting to create standalone test case --- test.scm | 3033 +++++++++++++++++++++++++++--------------------------- 1 file changed, 1526 insertions(+), 1507 deletions(-) diff --git a/test.scm b/test.scm index 12360999..d668b741 100644 --- a/test.scm +++ b/test.scm @@ -1,1513 +1,18 @@ ;; A temporary file to attempt to repro crashing / data corruption (import (scheme base) (scheme write)) -(define lambdas - '( - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) - (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) -; (9 ("test")) - (9 ("test")) - )) +(define lambdas (list)) +;; TODO: fill lambdas list + +(letrec + ((init (lambda (n) + (cond + ((equal? n 0) #f) + (else + (set! lambdas (cons '(9 ("test")) lambdas)) + (init (- n 1)))))) + (main (lambda () (for-each (lambda (l) (write (list @@ -1515,4 +20,1518 @@ (number->string (car l)) "(void *data, int argc, " (cdadr l) ") ;"))) - lambdas) + lambdas))) + (loop (lambda () + (main) + (loop))) + ) + (init 1000) + (loop) +) +; TODO: a long list like this seems to cause trouble. but revisit later, after GC is stabilized +;(define lambdas +; '( +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; (9 ("test")) +; )) From 22275832b541cee112927ebd699bab1061ff474f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 3 Dec 2015 23:20:16 -0500 Subject: [PATCH 196/339] Redirect GC to stderr --- runtime.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime.c b/runtime.c index efb71564..e3826ab5 100644 --- a/runtime.c +++ b/runtime.c @@ -2415,8 +2415,8 @@ void Cyc_start_thread(gc_thread_data *thd) void gc_mark_globals() { #if GC_DEBUG_TRACE - //printf("(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); - printf("Cyc_global_variables %p\n", Cyc_global_variables); + //fprintf(stderr, "(gc_mark_globals heap: %p size: %d)\n", h, (unsigned int)gc_heap_total_size(h)); + fprintf(stderr, "Cyc_global_variables %p\n", Cyc_global_variables); #endif // Mark global variables gc_mark_black(Cyc_global_variables); // Internal global used by the runtime @@ -2428,7 +2428,7 @@ void gc_mark_globals() object glo = *(c->pvar); if (!nullp(glo)) { #if GC_DEBUG_TRACE - printf("global pvar %p\n", glo); + fprintf(stderr, "global pvar %p\n", glo); #endif gc_mark_black(glo); // Mark actual object the global points to } @@ -2700,7 +2700,7 @@ void GC(void *data, closure cont, object *args, int num_args) gc_mut_cooperate((gc_thread_data *)data); #if GC_DEBUG_TRACE - printf("done with minor GC\n"); + fprintf(stderr, "done with minor GC\n"); #endif // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); From 09f4a638cf11191143d77b025f6119dfc3f2cf1f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 5 Dec 2015 02:55:28 -0500 Subject: [PATCH 197/339] Added notes --- gc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gc.c b/gc.c index 8ca03868..3ab7a025 100644 --- a/gc.c +++ b/gc.c @@ -704,6 +704,10 @@ void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) object high_limit = ((gc_thread_data *)thd)->stack_start; int color; +// TODO: is it just a coincidence that a corrupted lambda list element +// was at 15? this approach may not work for deep lists, and may not +// work at all. may need to replace with another method that is complete +// but also handles circular references... if (is_object_type(obj) && depth < 15) { color = mark(obj); #if GC_SAFETY_CHECKS From 17fbd853c7fbaf18a6c70d4372cf200d65baf63c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 4 Dec 2015 22:31:31 -0500 Subject: [PATCH 198/339] Added note --- gc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gc.c b/gc.c index 3ab7a025..852effb0 100644 --- a/gc.c +++ b/gc.c @@ -863,6 +863,8 @@ void gc_mut_cooperate(gc_thread_data *thd) } else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" + // TODO: below is efficient, but is there a chance we are missing anything by + // doing this instead of marking the objects in moveBuf?? #if GC_DEBUG_VERBOSE fprintf(stderr, "gc_cont %p\n", thd->gc_cont); #endif From 11864e558ffbf2d406eab046852c197c5eb5130b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 4 Dec 2015 23:23:15 -0500 Subject: [PATCH 199/339] Added more notes --- gc-notes.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index cb92a2cb..38a57c70 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -4,6 +4,15 @@ Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naiv Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. +memory corruption + - noticed that an object may be allocated with the old mark color, and then freed before it + can be marked, even though it is part of a global list. + what might be happening is that the new heap obj is part of the global list, but the minor + GC only marks gc-cont/gc-args, which this is not part of. and the globals are already marked + at that point by the collector thread, so no one is around to mark this object. + wait a minute - but how does the obj even get on the heap? see this - if above was true there would be no ref to move this to the heap, right? so what is going on?? -> +alloc 0xb78400e0 size = 32, obj=0xbffcd648, tag=0, mark=1 + TODO: - need to fix memory corruption bugs - need to cooperate when a mutator is blocked From 0946d56aaa3ed13d4ef5e52c1f83706b17b088b9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 4 Dec 2015 23:38:09 -0500 Subject: [PATCH 200/339] More notes --- gc-notes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 38a57c70..13e814e6 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -12,6 +12,9 @@ memory corruption at that point by the collector thread, so no one is around to mark this object. wait a minute - but how does the obj even get on the heap? see this - if above was true there would be no ref to move this to the heap, right? so what is going on?? -> alloc 0xb78400e0 size = 32, obj=0xbffcd648, tag=0, mark=1 +well, we also move globals, which would explain it since the next lambda becomes the head of the global list. so I think that explains it. the most expedient change is to just use moveBuf to mark the thread's roots. + +but again, this did not fix all crashes, so there are either other issues with the GC (not surprising, although disappointing) or this is not the issue. but I think this has to be a problem given the error output observed today. TODO: - need to fix memory corruption bugs From 3d0d966e6dfbac768b06d432253857bf9a8b3354 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 5 Dec 2015 22:44:06 -0500 Subject: [PATCH 201/339] Changed GC cooperation Mark all objects moved to the heap, instead of just the typical roots. --- gc.c | 25 +++++++++++++++---------- include/cyclone/types.h | 2 +- runtime.c | 4 ++-- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/gc.c b/gc.c index 852effb0..793ab4a8 100644 --- a/gc.c +++ b/gc.c @@ -850,7 +850,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) } // TODO: still need to handle case where a mutator is blocked -void gc_mut_cooperate(gc_thread_data *thd) +void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { int i, status = ATOMIC_GET(&gc_status_col); if (thd->gc_status != status) { @@ -863,18 +863,23 @@ void gc_mut_cooperate(gc_thread_data *thd) } else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" - // TODO: below is efficient, but is there a chance we are missing anything by - // doing this instead of marking the objects in moveBuf?? + // In this case, mark everything the collector moved to the heap + for (i = 0; i < buf_len; i++) { + gc_mark_gray(thd, thd->moveBuf[i]); #if GC_DEBUG_VERBOSE -fprintf(stderr, "gc_cont %p\n", thd->gc_cont); + fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); #endif - gc_mark_gray(thd, thd->gc_cont); - for (i = 0; i < thd->gc_num_args; i++) { -#if GC_DEBUG_VERBOSE -fprintf(stderr, "gc_args[%d] %p\n", i, thd->gc_args[i]); -#endif - gc_mark_gray(thd, thd->gc_args[i]); } +//#if GC_DEBUG_VERBOSE +//fprintf(stderr, "gc_cont %p\n", thd->gc_cont); +//#endif +// gc_mark_gray(thd, thd->gc_cont); +// for (i = 0; i < thd->gc_num_args; i++) { +//#if GC_DEBUG_VERBOSE +//fprintf(stderr, "gc_args[%d] %p\n", i, thd->gc_args[i]); +//#endif +// gc_mark_gray(thd, thd->gc_args[i]); +// } thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } thd->gc_status = status; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index ea28aadd..7b74f290 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -159,7 +159,7 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: void gc_mut_update(gc_thread_data *thd, object old_obj, object value); -void gc_mut_cooperate(gc_thread_data *thd); +void gc_mut_cooperate(gc_thread_data *thd, int buf_len); void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); diff --git a/runtime.c b/runtime.c index e3826ab5..11ad7906 100644 --- a/runtime.c +++ b/runtime.c @@ -2582,7 +2582,7 @@ void GC(void *data, closure cont, object *args, int num_args) object low_limit = &tmp; // This is one end of the stack... object high_limit = ((gc_thread_data *)data)->stack_start; int i; - int scani = 0, alloci = 0; // TODO: not quite sure how to do this yet, want to user pointers but realloc can move them... need to think about how this will work + int scani = 0, alloci = 0; int heap_grown = 0; //fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG @@ -2697,7 +2697,7 @@ void GC(void *data, closure cont, object *args, int num_args) } // Cooperate with the collector thread - gc_mut_cooperate((gc_thread_data *)data); + gc_mut_cooperate((gc_thread_data *)data, alloci); #if GC_DEBUG_TRACE fprintf(stderr, "done with minor GC\n"); From 9ded782a0600be2755a97b8e7ee6a6f9a31e3bcb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 6 Dec 2015 22:37:08 -0500 Subject: [PATCH 202/339] New approach to stack graying from write barrier --- gc.c | 23 +++++++++++++++++++++-- include/cyclone/types.h | 5 +++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/gc.c b/gc.c index 793ab4a8..28192de2 100644 --- a/gc.c +++ b/gc.c @@ -786,6 +786,18 @@ void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth) } } +/** + * Determine if object lives on the thread's stack + */ +int gc_is_stack_obj(gc_thread_data *thd, object obj) +{ + char tmp; + object low_limit = &tmp; + object high_limit = thd->stack_start; + return (check_overflow(low_limit, obj) && + check_overflow(obj, high_limit)); +} + /** Write barrier for updates to heap-allocated objects Plans: @@ -804,8 +816,15 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) ////fprintf(stderr, " for heap object "); //fprintf(stderr, "\n"); gc_mark_gray(thd, old_obj); - // TODO: need this too??? - gc_stack_mark_gray(thd, value); +// TODO: check if value is on the heap, +// if so, mark gray right now +// otherwise set it to be marked after moved to heap during next GC + //gc_stack_mark_gray(thd, value); + if (gc_is_stack_obj(thd, value)) { + grayed(value) = 1; + } else { + gc_mark_gray(thd, value); + } } else if (stage == STAGE_TRACING) { //fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 7b74f290..3b6c85b6 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -95,11 +95,11 @@ struct gc_heap_t { typedef struct gc_header_type_t gc_header_type; struct gc_header_type_t { - //unsigned char mark; // mark bits (only need 2) unsigned int mark; // mark bits (only need 2) - // TODO: forwarding address (probably not needed for mark/sweep), anything else??? + unsigned char grayed; // stack object to be grayed when moved to heap }; #define mark(x) (((list) x)->hdr.mark) +#define grayed(x) (((list) x)->hdr.grayed) /* HEAP definitions */ // experimenting with a heap based off of the one in Chibi scheme @@ -158,6 +158,7 @@ void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); void gc_thread_data_free(gc_thread_data *thd); // Prototypes for mutator/collector: +int gc_is_stack_obj(gc_thread_data *thd, object obj); void gc_mut_update(gc_thread_data *thd, object old_obj, object value); void gc_mut_cooperate(gc_thread_data *thd, int buf_len); void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); From c75c86f0282894697a43e5443bbdd6bc744dd74d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 6 Dec 2015 22:56:19 -0500 Subject: [PATCH 203/339] WIP - "grayed" flag to indicate grayed stack object --- include/cyclone/runtime.h | 1 + include/cyclone/types.h | 30 +++++++++++++++--------------- runtime.c | 16 ++++++++++++++++ scheme/cyclone/cgen.sld | 1 + 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 240abbaf..51392fc2 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -73,6 +73,7 @@ object Cyc_global_set(void *thd, object *glo, object value); tmp = arg_var; \ } \ var[i].hdr.mark = gc_color_red; \ + var[i].hdr.grayed = 0; \ var[i].tag = cons_tag; \ var[i].cons_car = tmp; \ var[i].cons_cdr = (i == (count-1)) ? nil : &var[i + 1]; \ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 3b6c85b6..9ca3af8b 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -260,7 +260,7 @@ typedef void (*function_type_va)(int, object, object, object, ...); /* Define C-variable integration type */ typedef struct {gc_header_type hdr; tag_type tag; object *pvar;} cvar_type; typedef cvar_type *cvar; -#define make_cvar(n,v) cvar_type n; n.hdr.mark = gc_color_red; n.tag = cvar_tag; n.pvar = v; +#define make_cvar(n,v) cvar_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = cvar_tag; n.pvar = v; /* Define boolean type. */ typedef struct {gc_header_type hdr; const tag_type tag; const char *pname;} boolean_type; @@ -281,9 +281,9 @@ static object quote_##name = nil; /* Define numeric types */ typedef struct {gc_header_type hdr; tag_type tag; int value;} integer_type; -#define make_int(n,v) integer_type n; n.hdr.mark = gc_color_red; n.tag = integer_tag; n.value = v; +#define make_int(n,v) integer_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = integer_tag; n.value = v; typedef struct {gc_header_type hdr; tag_type tag; double value;} double_type; -#define make_double(n,v) double_type n; n.hdr.mark = gc_color_red; n.tag = double_tag; n.value = v; +#define make_double(n,v) double_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = double_tag; n.value = v; #define integer_value(x) (((integer_type *) x)->value) #define double_value(x) (((double_type *) x)->value) @@ -294,16 +294,16 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty //// all functions that allocate strings, the GC, cgen, and maybe more. //// Because these strings are (at least for now) allocaed on the stack. #define make_string(cs, s) string_type cs; \ -{ int len = strlen(s); cs.tag = string_tag; cs.len = len; cs.hdr.mark = gc_color_red; \ +{ int len = strlen(s); cs.tag = string_tag; cs.len = len; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len + 1);} -#define make_string_with_len(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; \ +#define make_string_with_len(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ { int len = length; \ cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len); \ cs.str[len] = '\0';} -#define make_string_noalloc(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; \ +#define make_string_noalloc(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } @@ -317,14 +317,14 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty // TODO: a simple wrapper around FILE may not be good enough long-term // TODO: how exactly mode will be used. need to know r/w, bin/txt typedef struct {gc_header_type hdr; tag_type tag; FILE *fp; int mode;} port_type; -#define make_port(p,f,m) port_type p; p.hdr.mark = gc_color_red; p.tag = port_tag; p.fp = f; p.mode = m; +#define make_port(p,f,m) port_type p; p.hdr.mark = gc_color_red; n.hdr.grayed = 0; p.tag = port_tag; p.fp = f; p.mode = m; /* Vector type */ typedef struct {gc_header_type hdr; tag_type tag; int num_elt; object *elts;} vector_type; typedef vector_type *vector; -#define make_empty_vector(v) vector_type v; v.hdr.mark = gc_color_red; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; +#define make_empty_vector(v) vector_type v; v.hdr.mark = gc_color_red; n.hdr.grayed = 0; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; /* Define cons type. */ @@ -363,7 +363,7 @@ typedef cons_type *list; #define cddddr(x) (cdr(cdr(cdr(cdr(x))))) #define make_cons(n,a,d) \ -cons_type n; n.hdr.mark = gc_color_red; n.tag = cons_tag; n.cons_car = a; n.cons_cdr = d; +cons_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = cons_tag; n.cons_car = a; n.cons_cdr = d; /* Closure types */ @@ -384,15 +384,15 @@ typedef closureN_type *closureN; typedef closure0_type *closure; typedef closure0_type *macro; -#define mmacro(c,f) macro_type c; c.hdr.mark = gc_color_red; c.tag = macro_tag; c.fn = f; c.num_args = -1; -#define mclosure0(c,f) closure0_type c; c.hdr.mark = gc_color_red; c.tag = closure0_tag; c.fn = f; c.num_args = -1; -#define mclosure1(c,f,a) closure1_type c; c.hdr.mark = gc_color_red; c.tag = closure1_tag; \ +#define mmacro(c,f) macro_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = macro_tag; c.fn = f; c.num_args = -1; +#define mclosure0(c,f) closure0_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure0_tag; c.fn = f; c.num_args = -1; +#define mclosure1(c,f,a) closure1_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure1_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a; -#define mclosure2(c,f,a1,a2) closure2_type c; c.hdr.mark = gc_color_red; c.tag = closure2_tag; \ +#define mclosure2(c,f,a1,a2) closure2_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure2_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; -#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.hdr.mark = gc_color_red; c.tag = closure3_tag; \ +#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure3_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; -#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.hdr.mark = gc_color_red; c.tag = closure4_tag; \ +#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure4_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; c.elt4 = a4; #define mlist1(e1) (mcons(e1,nil)) diff --git a/runtime.c b/runtime.c index 11ad7906..d1a60d20 100644 --- a/runtime.c +++ b/runtime.c @@ -942,11 +942,13 @@ common_type Cyc_string2number(void *data, object str){ if (ceilf(n) == n) { result.integer_t.hdr.mark = gc_color_red; + result.integer_t.hdr.grayed = 0; result.integer_t.tag = integer_tag; result.integer_t.value = (int)n; } else { result.double_t.hdr.mark = gc_color_red; + result.double_t.hdr.grayed = 0; result.double_t.tag = double_tag; result.double_t.value = n; } @@ -1129,6 +1131,7 @@ object Cyc_command_line_arguments(void *data, object cont) { make_string(s, _cyc_argv[i - 1]); memcpy(ps, &s, sizeof(string_type)); ((list)pl)->hdr.mark = gc_color_red; + ((list)pl)->hdr.grayed = 0; ((list)pl)->tag = cons_tag; ((list)pl)->cons_car = ps; ((list)pl)->cons_cdr = lis; @@ -1143,6 +1146,7 @@ object Cyc_make_vector(void *data, object cont, object len, object fill) { Cyc_check_int(data, len); v = alloca(sizeof(vector_type)); ((vector)v)->hdr.mark = gc_color_red; + ((vector)v)->hdr.grayed = 0; ((vector)v)->tag = vector_tag; ((vector)v)->num_elt = ((integer_type *)len)->value; ((vector)v)->elts = @@ -1165,6 +1169,7 @@ object Cyc_list2vector(void *data, object cont, object l) { len = Cyc_length(data, l); v = alloca(sizeof(vector_type)); ((vector)v)->hdr.mark = gc_color_red; + ((vector)v)->hdr.grayed = 0; ((vector)v)->tag = vector_tag; ((vector)v)->num_elt = len.value; ((vector)v)->elts = @@ -1223,6 +1228,7 @@ common_type FUNC_OP(void *data, object x, object y) { \ common_type s; \ int tx = type_of(x), ty = type_of(y); \ s.double_t.hdr.mark = gc_color_red; \ + s.double_t.hdr.grayed = 0; \ s.double_t.tag = double_tag; \ if (DIV && \ ((ty == integer_tag && integer_value(y) == 0) || \ @@ -1231,6 +1237,7 @@ common_type FUNC_OP(void *data, object x, object y) { \ } \ if (tx == integer_tag && ty == integer_tag) { \ s.integer_t.hdr.mark = gc_color_red; \ + s.integer_t.hdr.grayed = 0; \ s.integer_t.tag = integer_tag; \ s.integer_t.value = ((integer_type *)x)->value OP ((integer_type *)y)->value; \ } else if (tx == double_tag && ty == integer_tag) { \ @@ -1274,6 +1281,7 @@ common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(void *, int i; if (argc == 0) { sum.integer_t.hdr.mark = gc_color_red; + sum.integer_t.hdr.grayed = 0; sum.integer_t.tag = integer_tag; sum.integer_t.value = 0; return sum; @@ -1281,10 +1289,12 @@ common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(void *, if (type_of(n) == integer_tag) { sum.integer_t.hdr.mark = gc_color_red; + sum.integer_t.hdr.grayed = 0; sum.integer_t.tag = integer_tag; sum.integer_t.value = ((integer_type *)n)->value; } else if (type_of(n) == double_tag) { sum.double_t.hdr.mark = gc_color_red; + sum.double_t.hdr.grayed = 0; sum.double_t.tag = double_tag; sum.double_t.value = ((double_type *)n)->value; } else { @@ -1298,10 +1308,12 @@ common_type Cyc_num_op_va_list(void *data, int argc, common_type (fn_op(void *, common_type result = fn_op(data, &sum, va_arg(ns, object)); if (type_of(&result) == integer_tag) { sum.integer_t.hdr.mark = gc_color_red; + sum.integer_t.hdr.grayed = 0; sum.integer_t.tag = integer_tag; sum.integer_t.value = ((integer_type *) &result)->value; } else if (type_of(&result) == double_tag) { sum.double_t.hdr.mark = gc_color_red; + sum.double_t.hdr.grayed = 0; sum.double_t.tag = double_tag; sum.double_t.value = ((double_type *) &result)->value; } else { @@ -1454,12 +1466,14 @@ object Cyc_io_peek_char(void *data, object port) { list mcons(a,d) object a,d; {register cons_type *c = malloc(sizeof(cons_type)); c->hdr.mark = gc_color_red; + c->hdr.grayed = 0; c->tag = cons_tag; c->cons_car = a; c->cons_cdr = d; return c;} cvar_type *mcvar(object *var) { cvar_type *c = malloc(sizeof(cvar_type)); c->hdr.mark = gc_color_red; + c->hdr.grayed = 0; c->tag = cvar_tag; c->pvar = var; return c;} @@ -1955,6 +1969,7 @@ void Cyc_apply(void *data, int argc, closure cont, object prim, ...){ for (i = 0; i < argc; i++) { tmp = va_arg(ap, object); args[i].hdr.mark = gc_color_red; + args[i].hdr.grayed = 0; args[i].tag = cons_tag; args[i].cons_car = tmp; args[i].cons_cdr = (i == (argc-1)) ? nil : &args[i + 1]; @@ -1984,6 +1999,7 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { for (i = 1; i < argc; i++) { args[i - 1].hdr.mark = gc_color_red; + args[i - 1].hdr.grayed = 0; args[i - 1].tag = cons_tag; args[i - 1].cons_car = buf[i]; args[i - 1].cons_cdr = (i == (argc-1)) ? nil : &args[i]; diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 2c218a1d..50ca02ae 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -1087,6 +1087,7 @@ (string-append "closureN_type " cv-name ";\n" cv-name ".hdr.mark = gc_color_red;\n " + cv-name ".hdr.grayed = 0;\n" cv-name ".tag = closureN_tag;\n " cv-name ".fn = (function_type)__lambda_" (number->string lid) ";\n" cv-name ".num_args = " (number->string (compute-num-args lam)) ";\n" From e994d4aa76fe09d11e449b7d84596f08e55dc42e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 22:02:38 -0500 Subject: [PATCH 204/339] Do thread locking outside of gc_mark_gray Changed the locking to attempt to avoid race conditions where not all of the heap objects have been moved prior to the collector staring to process them. --- gc.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index 28192de2..4ebe3d56 100644 --- a/gc.c +++ b/gc.c @@ -721,7 +721,9 @@ void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) } #endif if (color == gc_color_clear) { + pthread_mutex_lock(&(thd->lock)); gc_mark_gray(thd, obj); + pthread_mutex_unlock(&(thd->lock)); //fprintf(stderr, "marked heap obj from stack barrier %p %d\n", obj, color); } else if (color == gc_color_red) { gc_stack_mark_refs_gray(thd, obj, depth + 1); @@ -815,21 +817,23 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) //Cyc_display(value, stderr); ////fprintf(stderr, " for heap object "); //fprintf(stderr, "\n"); + pthread_mutex_lock(&(thd->lock)); gc_mark_gray(thd, old_obj); -// TODO: check if value is on the heap, -// if so, mark gray right now -// otherwise set it to be marked after moved to heap during next GC - //gc_stack_mark_gray(thd, value); + // Check if value is on the heap. If so, mark gray right now, + // otherwise set it to be marked after moved to heap by next GC if (gc_is_stack_obj(thd, value)) { grayed(value) = 1; } else { gc_mark_gray(thd, value); } + pthread_mutex_unlock(&(thd->lock)); } else if (stage == STAGE_TRACING) { //fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); //fprintf(stderr, "\n"); + pthread_mutex_lock(&(thd->lock)); gc_mark_gray(thd, old_obj); + pthread_mutex_unlock(&(thd->lock)); #if GC_DEBUG_VERBOSE if (is_object_type(old_obj) && mark(old_obj) == gc_color_clear) { fprintf(stderr, "added to mark buffer (trace) from write barrier %p:mark %d:", old_obj, mark(old_obj)); @@ -883,12 +887,14 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) else if (thd->gc_status == STATUS_SYNC2) { // Mark thread "roots" // In this case, mark everything the collector moved to the heap + pthread_mutex_lock(&(thd->lock)); for (i = 0; i < buf_len; i++) { gc_mark_gray(thd, thd->moveBuf[i]); #if GC_DEBUG_VERBOSE fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); #endif } + pthread_mutex_unlock(&(thd->lock)); //#if GC_DEBUG_VERBOSE //fprintf(stderr, "gc_cont %p\n", thd->gc_cont); //#endif @@ -908,6 +914,13 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) ///////////////////////////////////////////// // Collector functions +/** + * Mark the given object gray if it is on the heap. + * Note marking is done implicitly by placing it in a buffer, + * to avoid repeated re-scanning. + * + * This function must be executed once the thread lock has been acquired. + */ void gc_mark_gray(gc_thread_data *thd, object obj) { // From what I can tell, no other thread would be modifying @@ -919,13 +932,11 @@ void gc_mark_gray(gc_thread_data *thd, object obj) // Note that ideally this should be a lock-free data structure to make the // algorithm more efficient. So this code (and the corresponding collector // trace code) should be converted at some point. - pthread_mutex_lock(&(thd->lock)); thd->mark_buffer = vpbuffer_add(thd->mark_buffer, &(thd->mark_buffer_len), thd->last_write, obj); (thd->last_write)++; // Already locked, just do it... - pthread_mutex_unlock(&(thd->lock)); } } From 372a0a3fed5289a81c88ef46f29ac5e7e571da0d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 22:11:58 -0500 Subject: [PATCH 205/339] Fixed compilation errors --- include/cyclone/types.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 9ca3af8b..423aae83 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -294,16 +294,16 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty //// all functions that allocate strings, the GC, cgen, and maybe more. //// Because these strings are (at least for now) allocaed on the stack. #define make_string(cs, s) string_type cs; \ -{ int len = strlen(s); cs.tag = string_tag; cs.len = len; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ +{ int len = strlen(s); cs.tag = string_tag; cs.len = len; cs.hdr.mark = gc_color_red; cs.hdr.grayed = 0; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len + 1);} -#define make_string_with_len(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ +#define make_string_with_len(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; cs.hdr.grayed = 0; \ { int len = length; \ cs.tag = string_tag; cs.len = len; \ cs.str = alloca(sizeof(char) * (len + 1)); \ memcpy(cs.str, s, len); \ cs.str[len] = '\0';} -#define make_string_noalloc(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; n.hdr.grayed = 0; \ +#define make_string_noalloc(cs, s, length) string_type cs; cs.hdr.mark = gc_color_red; cs.hdr.grayed = 0; \ { cs.tag = string_tag; cs.len = length; \ cs.str = s; } @@ -317,14 +317,14 @@ typedef struct {gc_header_type hdr; tag_type tag; int len; char *str;} string_ty // TODO: a simple wrapper around FILE may not be good enough long-term // TODO: how exactly mode will be used. need to know r/w, bin/txt typedef struct {gc_header_type hdr; tag_type tag; FILE *fp; int mode;} port_type; -#define make_port(p,f,m) port_type p; p.hdr.mark = gc_color_red; n.hdr.grayed = 0; p.tag = port_tag; p.fp = f; p.mode = m; +#define make_port(p,f,m) port_type p; p.hdr.mark = gc_color_red; p.hdr.grayed = 0; p.tag = port_tag; p.fp = f; p.mode = m; /* Vector type */ typedef struct {gc_header_type hdr; tag_type tag; int num_elt; object *elts;} vector_type; typedef vector_type *vector; -#define make_empty_vector(v) vector_type v; v.hdr.mark = gc_color_red; n.hdr.grayed = 0; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; +#define make_empty_vector(v) vector_type v; v.hdr.mark = gc_color_red; v.hdr.grayed = 0; v.tag = vector_tag; v.num_elt = 0; v.elts = NULL; /* Define cons type. */ @@ -384,15 +384,15 @@ typedef closureN_type *closureN; typedef closure0_type *closure; typedef closure0_type *macro; -#define mmacro(c,f) macro_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = macro_tag; c.fn = f; c.num_args = -1; -#define mclosure0(c,f) closure0_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure0_tag; c.fn = f; c.num_args = -1; -#define mclosure1(c,f,a) closure1_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure1_tag; \ +#define mmacro(c,f) macro_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = macro_tag; c.fn = f; c.num_args = -1; +#define mclosure0(c,f) closure0_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = closure0_tag; c.fn = f; c.num_args = -1; +#define mclosure1(c,f,a) closure1_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = closure1_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a; -#define mclosure2(c,f,a1,a2) closure2_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure2_tag; \ +#define mclosure2(c,f,a1,a2) closure2_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = closure2_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; -#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure3_tag; \ +#define mclosure3(c,f,a1,a2,a3) closure3_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = closure3_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; -#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.hdr.mark = gc_color_red; n.hdr.grayed = 0; c.tag = closure4_tag; \ +#define mclosure4(c,f,a1,a2,a3,a4) closure4_type c; c.hdr.mark = gc_color_red; c.hdr.grayed = 0; c.tag = closure4_tag; \ c.fn = f; c.num_args = -1; c.elt1 = a1; c.elt2 = a2; c.elt3 = a3; c.elt4 = a4; #define mlist1(e1) (mcons(e1,nil)) From 3adf4d8d324f42c186fd2d47b18bc05fee6ee619 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 22:54:47 -0500 Subject: [PATCH 206/339] Refactoring --- runtime.c | 94 +++++++++++++++---------------------------------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/runtime.c b/runtime.c index d1a60d20..2de6496a 100644 --- a/runtime.c +++ b/runtime.c @@ -2452,123 +2452,81 @@ void gc_mark_globals() } } +char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, object hp) +{ + // hp ==> new heap object, point to it from old stack object + forward(obj) = hp; + type_of(obj) = forward_tag; + // keep track of each allocation so we can scan/move + // the whole live object 'tree' + gc_thr_add_to_move_buffer(thd, alloci, hp); + return (char *)hp; +} + char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; - - -// !!! -// TODO: clean up code below and consolidate with gc_copy_obj in gc.c: -// !!! - - -//gcMoveCountsDEBUG[type_of(obj)]++; -//printf("DEBUG gc_move type = %ld\n", type_of(obj)); // JAE DEBUG switch(type_of(obj)){ case cons_tag: { - list hp = gc_alloc(Cyc_heap, sizeof(cons_type), obj, thd, heap_grown); // hp ==> new heap object - forward(obj) = hp; - type_of(obj) = forward_tag; - // keep track of each allocation so we can scan/move - // the whole live object 'tree' - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + list hp = gc_alloc(Cyc_heap, sizeof(cons_type), obj, thd, heap_grown); + return gc_fixup_moved_obj(thd, alloci, hp); } case macro_tag: { macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closure0_tag: { closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closure1_tag: { closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closure2_tag: { closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closure3_tag: { closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closure4_tag: { closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case closureN_tag: { closureN_type *hp = gc_alloc(Cyc_heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case vector_tag: { vector_type *hp = gc_alloc(Cyc_heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case string_tag: { string_type *hp = gc_alloc(Cyc_heap, sizeof(string_type) + ((string_len(obj) + 1)), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case integer_tag: { integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case double_tag: { double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case port_tag: { port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case cvar_tag: { cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown); - forward(obj) = hp; - type_of(obj) = forward_tag; - gc_thr_add_to_move_buffer(thd, alloci, hp); - return (char *)hp; + return gc_fixup_moved_obj(thd, alloci, hp); } case forward_tag: return (char *)forward(obj); From 5818ffc0ebbb2308c5f354fca5a68c098e83539c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 22:54:54 -0500 Subject: [PATCH 207/339] Temporarily reverting gc_stack change --- gc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 4ebe3d56..aa618ce4 100644 --- a/gc.c +++ b/gc.c @@ -821,12 +821,13 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) gc_mark_gray(thd, old_obj); // Check if value is on the heap. If so, mark gray right now, // otherwise set it to be marked after moved to heap by next GC - if (gc_is_stack_obj(thd, value)) { - grayed(value) = 1; - } else { - gc_mark_gray(thd, value); - } +// if (gc_is_stack_obj(thd, value)) { +// grayed(value) = 1; +// } else { +// gc_mark_gray(thd, value); +// } pthread_mutex_unlock(&(thd->lock)); +gc_stack_mark_gray(thd, value); // TODO: this line will be replace with above block } else if (stage == STAGE_TRACING) { //fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); From fa26b18b0112ef2ae21f2668dfd8f4259af5c409 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 23:04:04 -0500 Subject: [PATCH 208/339] Fixed compile error --- runtime.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/runtime.c b/runtime.c index 2de6496a..04bf0e71 100644 --- a/runtime.c +++ b/runtime.c @@ -2452,7 +2452,7 @@ void gc_mark_globals() } } -char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, object hp) +char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) { // hp ==> new heap object, point to it from old stack object forward(obj) = hp; @@ -2468,65 +2468,65 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { switch(type_of(obj)){ case cons_tag: { list hp = gc_alloc(Cyc_heap, sizeof(cons_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case macro_tag: { macro_type *hp = gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure0_tag: { closure0_type *hp = gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure1_tag: { closure1_type *hp = gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure2_tag: { closure2_type *hp = gc_alloc(Cyc_heap, sizeof(closure2_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure3_tag: { closure3_type *hp = gc_alloc(Cyc_heap, sizeof(closure3_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure4_tag: { closure4_type *hp = gc_alloc(Cyc_heap, sizeof(closure4_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closureN_tag: { closureN_type *hp = gc_alloc(Cyc_heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elt), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case vector_tag: { vector_type *hp = gc_alloc(Cyc_heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elt), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case string_tag: { string_type *hp = gc_alloc(Cyc_heap, sizeof(string_type) + ((string_len(obj) + 1)), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case integer_tag: { integer_type *hp = gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case double_tag: { double_type *hp = gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case port_tag: { port_type *hp = gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case cvar_tag: { cvar_type *hp = gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown); - return gc_fixup_moved_obj(thd, alloci, hp); + return gc_fixup_moved_obj(thd, alloci, obj, hp); } case forward_tag: return (char *)forward(obj); From 2dda21e43ab1ec6916d8a6e920142abc061fc4ea Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 23:10:42 -0500 Subject: [PATCH 209/339] Added TODO --- runtime.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/runtime.c b/runtime.c index 04bf0e71..2dc68dec 100644 --- a/runtime.c +++ b/runtime.c @@ -2460,6 +2460,14 @@ char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) // keep track of each allocation so we can scan/move // the whole live object 'tree' gc_thr_add_to_move_buffer(thd, alloci, hp); + +// TODO: if grayed(obj) then - do a deferred gc_mark_gray on hp +// you know, one possibility would be to add it to the thread mark buffer +// but now increment the read (write?) variable. instead increment another +// one and wait until the end of minor GC to set read (write?) to the +// appropriate value. just need to make sure we have the lock before +// updating it. +// that should avoid race conditions and the need for an additional buffer return (char *)hp; } From c4554c5af6ca0b0314dfa5d76dceeee225582bac Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 23:29:51 -0500 Subject: [PATCH 210/339] Added notes --- gc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gc.c b/gc.c index aa618ce4..5b479560 100644 --- a/gc.c +++ b/gc.c @@ -975,6 +975,14 @@ void gc_collector_trace() m = Cyc_mutators[i]; // TODO: ideally, want to use a lock-free data structure to prevent // having to use a mutex here. see corresponding code in gc_mark_gray + +TODO: I think this locking is too coarse. observing immediate failures with the recent change to g_mark_gray locking and +wonder if the problem is that this locking will prevent a batch of changes from being seen. +you know, do we really need locking here? the last read/write can be made atomic, and any reads/writes to mark buffer can +be made atomic as well. I think we may need a dirty flag to let the collector know something is happening when the mark buffer +needs to be resized, but other than that it this good enough? +on the other hand, a central issue with this collector is when can we be sure that we are existing tracing at the right time, and +not too early? because an early exit here will surely mean that objects are incorrectly freed pthread_mutex_lock(&(m->lock)); while (m->last_read < m->last_write) { clean = 0; From 598c981ecbc9bf5157dc24cb8dc76f2f04d03d4c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 03:02:30 -0500 Subject: [PATCH 211/339] Adding an experimental safety check --- gc.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index 5b479560..a15b0f51 100644 --- a/gc.c +++ b/gc.c @@ -976,13 +976,13 @@ void gc_collector_trace() // TODO: ideally, want to use a lock-free data structure to prevent // having to use a mutex here. see corresponding code in gc_mark_gray -TODO: I think this locking is too coarse. observing immediate failures with the recent change to g_mark_gray locking and -wonder if the problem is that this locking will prevent a batch of changes from being seen. -you know, do we really need locking here? the last read/write can be made atomic, and any reads/writes to mark buffer can -be made atomic as well. I think we may need a dirty flag to let the collector know something is happening when the mark buffer -needs to be resized, but other than that it this good enough? -on the other hand, a central issue with this collector is when can we be sure that we are existing tracing at the right time, and -not too early? because an early exit here will surely mean that objects are incorrectly freed +//TODO: I think this locking is too coarse. observing immediate failures with the recent change to g_mark_gray locking and +//wonder if the problem is that this locking will prevent a batch of changes from being seen. +//you know, do we really need locking here? the last read/write can be made atomic, and any reads/writes to mark buffer can +//be made atomic as well. I think we may need a dirty flag to let the collector know something is happening when the mark buffer +//needs to be resized, but other than that it this good enough? +//on the other hand, a central issue with this collector is when can we be sure that we are existing tracing at the right time, and +//not too early? because an early exit here will surely mean that objects are incorrectly freed pthread_mutex_lock(&(m->lock)); while (m->last_read < m->last_write) { clean = 0; @@ -996,6 +996,18 @@ not too early? because an early exit here will surely mean that objects are inco (m->last_read)++; // Inc here to prevent off-by-one error } pthread_mutex_unlock(&(m->lock)); + + // Try checking the condition once more after giving the + // mutator a chance to respond, to prevent exiting early. + // This is experimental, not sure if it is necessary + if (clean) { + pthread_mutex_lock(&(m->lock)); + if (m->last_read < m->last_write) { + printf("JAE DEBUG - might have exited trace early\n"); + clean = 0; + } + pthread_mutex_unlock(&(m->lock)); + } } } } From c8878e749aa5ed132f2d55445f105dbb460e458d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 03:14:00 -0500 Subject: [PATCH 212/339] WIP - deferred gray --- runtime.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/runtime.c b/runtime.c index 2dc68dec..93cff642 100644 --- a/runtime.c +++ b/runtime.c @@ -2452,7 +2452,7 @@ void gc_mark_globals() } } -char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) +char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, int *num_grayed, char *obj, object hp) { // hp ==> new heap object, point to it from old stack object forward(obj) = hp; @@ -2468,10 +2468,19 @@ char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) // appropriate value. just need to make sure we have the lock before // updating it. // that should avoid race conditions and the need for an additional buffer + + if (TODO){ + lock + gc_mark_gray - but WITHOUT incrementing write (read?) + unlock + (*num_grayed)++; +} + + return (char *)hp; } -char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { +char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown, int *num_grayed) { if (!is_object_type(obj)) return obj; switch(type_of(obj)){ case cons_tag: { @@ -2553,7 +2562,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown); \ + (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown, &num_grayed); \ } \ } @@ -2566,6 +2575,7 @@ void GC(void *data, closure cont, object *args, int num_args) int i; int scani = 0, alloci = 0; int heap_grown = 0; + int num_grayed = 0; //fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer From 33447ebc57cf7344a8377b938480756785dfdec5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 7 Dec 2015 22:34:29 -0500 Subject: [PATCH 213/339] New write barrier implementation --- gc.c | 35 ++++++++++++++++++++++++++++------- include/cyclone/types.h | 2 ++ runtime.c | 30 +++++++++--------------------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/gc.c b/gc.c index a15b0f51..8be59a00 100644 --- a/gc.c +++ b/gc.c @@ -821,13 +821,12 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) gc_mark_gray(thd, old_obj); // Check if value is on the heap. If so, mark gray right now, // otherwise set it to be marked after moved to heap by next GC -// if (gc_is_stack_obj(thd, value)) { -// grayed(value) = 1; -// } else { -// gc_mark_gray(thd, value); -// } + if (gc_is_stack_obj(thd, value)) { + grayed(value) = 1; + } else { + gc_mark_gray(thd, value); + } pthread_mutex_unlock(&(thd->lock)); -gc_stack_mark_gray(thd, value); // TODO: this line will be replace with above block } else if (stage == STAGE_TRACING) { //fprintf(stderr, "DEBUG - GC async tracing marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); @@ -877,12 +876,20 @@ gc_stack_mark_gray(thd, value); // TODO: this line will be replace with above bl void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { int i, status = ATOMIC_GET(&gc_status_col); + + // Handle any pending marks from write barrier + pthread_mutex_lock(&(thd->lock)); + thd->last_write += thd->pending_writes; + thd->pending_writes = 0; + pthread_mutex_unlock(&(thd->lock)); + if (thd->gc_status != status) { if (thd->gc_status == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); thd->last_write = 0; thd->last_read = 0; + thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); } else if (thd->gc_status == STATUS_SYNC2) { @@ -941,6 +948,17 @@ void gc_mark_gray(gc_thread_data *thd, object obj) } } +void gc_mark_gray2(gc_thread_data *thd, object obj) +{ + if (is_object_type(obj) && mark(obj) == gc_color_clear) { + thd->mark_buffer = vpbuffer_add(thd->mark_buffer, + &(thd->mark_buffer_len), + (thd->last_write + thd->pending_writes), + obj); + thd->pending_writes++; + } +} + // TODO: before doing this, may want to debug a bit and see what is // being passed to gc_mut_update. see if those objects tend to have // any heap refs. may need to add debug code to do that... @@ -1003,7 +1021,10 @@ void gc_collector_trace() if (clean) { pthread_mutex_lock(&(m->lock)); if (m->last_read < m->last_write) { - printf("JAE DEBUG - might have exited trace early\n"); + fprintf(stderr, "JAE DEBUG - might have exited trace early\n"); + clean = 0; + } + else if (m->pending_writes) { clean = 0; } pthread_mutex_unlock(&(m->lock)); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 423aae83..ab73bed9 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -56,6 +56,7 @@ struct gc_thread_data_t { int gc_status; int last_write; int last_read; + int pending_writes; void **mark_buffer; int mark_buffer_len; pthread_mutex_t lock; @@ -164,6 +165,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len); void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); +void gc_mark_gray2(gc_thread_data *thd, object obj); void gc_collector_trace(); void gc_mark_black(object obj); void gc_collector_mark_gray(object parent, object obj); diff --git a/runtime.c b/runtime.c index 93cff642..616eb527 100644 --- a/runtime.c +++ b/runtime.c @@ -2452,35 +2452,24 @@ void gc_mark_globals() } } -char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, int *num_grayed, char *obj, object hp) +char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) { + if (grayed(obj)) { + pthread_mutex_lock(&(thd->lock)); + gc_mark_gray2(thd, hp); + pthread_mutex_unlock(&(thd->lock)); + } + // hp ==> new heap object, point to it from old stack object forward(obj) = hp; type_of(obj) = forward_tag; // keep track of each allocation so we can scan/move // the whole live object 'tree' gc_thr_add_to_move_buffer(thd, alloci, hp); - -// TODO: if grayed(obj) then - do a deferred gc_mark_gray on hp -// you know, one possibility would be to add it to the thread mark buffer -// but now increment the read (write?) variable. instead increment another -// one and wait until the end of minor GC to set read (write?) to the -// appropriate value. just need to make sure we have the lock before -// updating it. -// that should avoid race conditions and the need for an additional buffer - - if (TODO){ - lock - gc_mark_gray - but WITHOUT incrementing write (read?) - unlock - (*num_grayed)++; -} - - return (char *)hp; } -char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown, int *num_grayed) { +char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { if (!is_object_type(obj)) return obj; switch(type_of(obj)){ case cons_tag: { @@ -2562,7 +2551,7 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown, int temp = obj; \ if (check_overflow(low_limit, temp) && \ check_overflow(temp, high_limit)){ \ - (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown, &num_grayed); \ + (obj) = (object) gc_move(temp, (gc_thread_data *)data, &alloci, &heap_grown); \ } \ } @@ -2575,7 +2564,6 @@ void GC(void *data, closure cont, object *args, int num_args) int i; int scani = 0, alloci = 0; int heap_grown = 0; - int num_grayed = 0; //fprintf(stdout, "DEBUG, started minor GC\n"); // JAE DEBUG // Prevent overrunning buffer From 6ad9e6098f7de07052a82ad55d495d47fae9ef0e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 21:37:01 -0500 Subject: [PATCH 214/339] Removed hacky gc_stack functions --- gc.c | 94 ----------------------------------------- include/cyclone/types.h | 2 - 2 files changed, 96 deletions(-) diff --git a/gc.c b/gc.c index 8be59a00..2d04fa83 100644 --- a/gc.c +++ b/gc.c @@ -694,100 +694,6 @@ PHASE 2 - multi-threaded mutator (IE, more than one stack thread): ///////////////////////////////////////////// // GC functions called by the Mutator threads -// Scan the given object and its refs, marking all heap objects. The issue -// here is that the heap's write barrier can be invoked at any time and -// we need to ensure any heap objects affected are traced -void gc_stack_mark_gray3(gc_thread_data *thd, object obj, int depth) -{ - char tmp; - object low_limit = &tmp; - object high_limit = ((gc_thread_data *)thd)->stack_start; - int color; - -// TODO: is it just a coincidence that a corrupted lambda list element -// was at 15? this approach may not work for deep lists, and may not -// work at all. may need to replace with another method that is complete -// but also handles circular references... - if (is_object_type(obj) && depth < 15) { - color = mark(obj); -#if GC_SAFETY_CHECKS - if (check_overflow(low_limit, obj) && - check_overflow(obj, high_limit) && - color != gc_color_red){ - fprintf(stderr, "stack object has wrong color %d!\n", color); - Cyc_display(obj, stderr); - fprintf(stderr, "\n"); - exit(1); - } -#endif - if (color == gc_color_clear) { - pthread_mutex_lock(&(thd->lock)); - gc_mark_gray(thd, obj); - pthread_mutex_unlock(&(thd->lock)); - //fprintf(stderr, "marked heap obj from stack barrier %p %d\n", obj, color); - } else if (color == gc_color_red) { - gc_stack_mark_refs_gray(thd, obj, depth + 1); - } - } -} - -void gc_stack_mark_gray(gc_thread_data *thd, object obj) -{ - gc_stack_mark_gray3(thd, obj, 0); -} - -// Should only be called from above function as a helper -// -// TODO: this will probably hang procssing circular -// references!!!! need to extend this once the concept is proven -// -// ideally would need some way of recording which nodes have -// been visited. trick is that, unlike in other places, the -// nodes may be visited multiple times so cannot destructively -// alter them. -void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth) -{ - switch(type_of(obj)) { - case cons_tag: { - gc_stack_mark_gray3(thd, car(obj), depth); - gc_stack_mark_gray3(thd, cdr(obj), depth); - break; - } - case closure1_tag: - gc_stack_mark_gray3(thd, ((closure1) obj)->elt1, depth); - break; - case closure2_tag: - gc_stack_mark_gray3(thd, ((closure2) obj)->elt1, depth); - gc_stack_mark_gray3(thd, ((closure2) obj)->elt2, depth); - case closure3_tag: - gc_stack_mark_gray3(thd, ((closure3) obj)->elt1, depth); - gc_stack_mark_gray3(thd, ((closure3) obj)->elt2, depth); - gc_stack_mark_gray3(thd, ((closure3) obj)->elt3, depth); - case closure4_tag: - gc_stack_mark_gray3(thd, ((closure4) obj)->elt1, depth); - gc_stack_mark_gray3(thd, ((closure4) obj)->elt2, depth); - gc_stack_mark_gray3(thd, ((closure4) obj)->elt3, depth); - gc_stack_mark_gray3(thd, ((closure4) obj)->elt4, depth); - break; - case closureN_tag: { - int i, n = ((closureN) obj)->num_elt; - for (i = 0; i < n; i++) { - gc_stack_mark_gray3(thd, ((closureN) obj)->elts[i], depth); - } - break; - } - case vector_tag: { - int i, n = ((vector) obj)->num_elt; - for (i = 0; i < n; i++) { - gc_stack_mark_gray3(thd, ((vector) obj)->elts[i], depth); - } - break; - } - default: - break; - } -} - /** * Determine if object lives on the thread's stack */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index ab73bed9..e7f9c809 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -162,8 +162,6 @@ void gc_thread_data_free(gc_thread_data *thd); int gc_is_stack_obj(gc_thread_data *thd, object obj); void gc_mut_update(gc_thread_data *thd, object old_obj, object value); void gc_mut_cooperate(gc_thread_data *thd, int buf_len); -void gc_stack_mark_refs_gray(gc_thread_data *thd, object obj, int depth); -void gc_stack_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray(gc_thread_data *thd, object obj); void gc_mark_gray2(gc_thread_data *thd, object obj); void gc_collector_trace(); From 9199bf512ac9f2b3e4c01b0054641886a4f62918 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 21:42:18 -0500 Subject: [PATCH 215/339] Separate debug printing in gc_mut_cooperate --- gc.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/gc.c b/gc.c index 2d04fa83..0bb61507 100644 --- a/gc.c +++ b/gc.c @@ -782,6 +782,9 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { int i, status = ATOMIC_GET(&gc_status_col); +#if GC_DEBUG_VERBOSE + int debug_print = 0; +#endif // Handle any pending marks from write barrier pthread_mutex_lock(&(thd->lock)); @@ -805,24 +808,22 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) for (i = 0; i < buf_len; i++) { gc_mark_gray(thd, thd->moveBuf[i]); #if GC_DEBUG_VERBOSE - fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); + debug_print = 1; #endif } pthread_mutex_unlock(&(thd->lock)); -//#if GC_DEBUG_VERBOSE -//fprintf(stderr, "gc_cont %p\n", thd->gc_cont); -//#endif -// gc_mark_gray(thd, thd->gc_cont); -// for (i = 0; i < thd->gc_num_args; i++) { -//#if GC_DEBUG_VERBOSE -//fprintf(stderr, "gc_args[%d] %p\n", i, thd->gc_args[i]); -//#endif -// gc_mark_gray(thd, thd->gc_args[i]); -// } thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } thd->gc_status = status; } +#if GC_DEBUG_VERBOSE + if (debug_print) { + for (i = 0; i < buf_len; i++) { + gc_mark_gray(thd, thd->moveBuf[i]); + fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); + } + } +#endif } ///////////////////////////////////////////// From e5bf6e0e4ecc16a3e597d85c490253f632e1def4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 23:13:22 -0500 Subject: [PATCH 216/339] Fixed race condition on startup --- include/cyclone/runtime-main.h | 1 - scheme/cyclone/cgen.sld | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 9e7a26f4..c99cee8b 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -28,7 +28,6 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif gc_init_heap(heap_size); - gc_initialize(); gc_start_collector(); } diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 50ca02ae..9ebbf111 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -81,13 +81,14 @@ mclosure0(entry_pt,&c_entry_pt); // First function to execute _cyc_argc = argc; _cyc_argv = argv; - Cyc_heap_init(heap_size); + gc_initialize(); thd = malloc(sizeof(gc_thread_data)); gc_thread_data_init(thd, 0, (char *) &stack_size, stack_size); thd->gc_cont = &entry_pt; thd->gc_args[0] = &clos_halt; thd->gc_num_args = 1; gc_add_mutator(thd); + Cyc_heap_init(heap_size); Cyc_start_thread(thd); return 0;}") From a5dcb6c6a203754a3cf56134cd828e28439698ff Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 9 Dec 2015 02:59:25 -0500 Subject: [PATCH 217/339] Potential debug tracing --- gc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gc.c b/gc.c index 0bb61507..36f9d7b0 100644 --- a/gc.c +++ b/gc.c @@ -1035,6 +1035,10 @@ void gc_empty_collector_stack() // Mark stack is only used by the collector thread, so no sync needed while (mark_stack_i > 0) { // not empty mark_stack_i--; +//#if GC_DEBUG_VERBOSE +// fprintf(stderr, "gc_mark_black mark stack %p \n", +// mark_stack[mark_stack_i]); +//#endif gc_mark_black(mark_stack[mark_stack_i]); } } From ce500fff3edc6cbaf8d29bc1e9de2e476d3d552e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 8 Dec 2015 22:49:20 -0500 Subject: [PATCH 218/339] Removed dead code and errant gc_mark_gray --- gc.c | 50 +++----------------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/gc.c b/gc.c index 36f9d7b0..317d056c 100644 --- a/gc.c +++ b/gc.c @@ -411,49 +411,6 @@ size_t gc_heap_total_size(gc_heap *h) return total_size; } -//void gc_mark(gc_heap *h, object obj) -//{ -// if (nullp(obj) || is_value_type(obj) || mark(obj)) -// return; -// -//#if GC_DEBUG_PRINTFS -//// fprintf(stderr, "gc_mark %p\n", obj); -//#endif -// ((list)obj)->hdr.mark = 1; -// // TODO: mark heap saves (??) -// // could this be a write barrier? -// -// // Mark objects this one references -// if (type_of(obj) == cons_tag) { -// gc_mark(h, car(obj)); -// gc_mark(h, cdr(obj)); -// } else if (type_of(obj) == closure1_tag) { -// gc_mark(h, ((closure1) obj)->elt1); -// } else if (type_of(obj) == closure2_tag) { -// gc_mark(h, ((closure2) obj)->elt1); -// gc_mark(h, ((closure2) obj)->elt2); -// } else if (type_of(obj) == closure3_tag) { -// gc_mark(h, ((closure3) obj)->elt1); -// gc_mark(h, ((closure3) obj)->elt2); -// gc_mark(h, ((closure3) obj)->elt3); -// } else if (type_of(obj) == closure4_tag) { -// gc_mark(h, ((closure4) obj)->elt1); -// gc_mark(h, ((closure4) obj)->elt2); -// gc_mark(h, ((closure4) obj)->elt3); -// gc_mark(h, ((closure4) obj)->elt4); -// } else if (type_of(obj) == closureN_tag) { -// int i, n = ((closureN) obj)->num_elt; -// for (i = 0; i < n; i++) { -// gc_mark(h, ((closureN) obj)->elts[i]); -// } -// } else if (type_of(obj) == vector_tag) { -// int i, n = ((vector) obj)->num_elt; -// for (i = 0; i < n; i++) { -// gc_mark(h, ((vector) obj)->elts[i]); -// } -// } -//} - size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) { size_t freed, max_freed=0, sum_freed=0, size; @@ -807,10 +764,10 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) pthread_mutex_lock(&(thd->lock)); for (i = 0; i < buf_len; i++) { gc_mark_gray(thd, thd->moveBuf[i]); -#if GC_DEBUG_VERBOSE - debug_print = 1; -#endif } +#if GC_DEBUG_VERBOSE + debug_print = 1; +#endif pthread_mutex_unlock(&(thd->lock)); thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } @@ -819,7 +776,6 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) #if GC_DEBUG_VERBOSE if (debug_print) { for (i = 0; i < buf_len; i++) { - gc_mark_gray(thd, thd->moveBuf[i]); fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); } } From 15ac239d2f5695f5eb28a597f2227048dad6d3fb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 9 Dec 2015 23:38:15 -0500 Subject: [PATCH 219/339] Mark current continuation during GC coop Mark both current cont (gc_cont + args) as well as all moved objects during cooperation. Trying to prevent cases of valid objects being collected when they should have been part of the continuation chain (IE, parens in read:parse). --- gc.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index 317d056c..4858b577 100644 --- a/gc.c +++ b/gc.c @@ -759,15 +759,21 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) pthread_mutex_unlock(&(thd->lock)); } else if (thd->gc_status == STATUS_SYNC2) { - // Mark thread "roots" - // In this case, mark everything the collector moved to the heap - pthread_mutex_lock(&(thd->lock)); - for (i = 0; i < buf_len; i++) { - gc_mark_gray(thd, thd->moveBuf[i]); - } #if GC_DEBUG_VERBOSE debug_print = 1; #endif + // Mark thread "roots": + // Begin my marking current continuation, which may have already + // been on the heap prior to latest minor GC + pthread_mutex_lock(&(thd->lock)); + gc_mark_gray(thd, thd->gc_cont); + for (i = 0; i < thd->gc_num_args; i++) { + gc_mark_gray(thd, thd->gc_args[i]); + } + // Also, mark everything the collector moved to the heap + for (i = 0; i < buf_len; i++) { + gc_mark_gray(thd, thd->moveBuf[i]); + } pthread_mutex_unlock(&(thd->lock)); thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } @@ -775,8 +781,12 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) } #if GC_DEBUG_VERBOSE if (debug_print) { + fprintf(stderr, "coop mark gc_cont %p\n", thd->gc_cont); + for (i = 0; i < thd->gc_num_args; i++) { + fprintf(stderr, "coop mark gc_args[%d] %p\n", i, thd->gc_args[i]); + } for (i = 0; i < buf_len; i++) { - fprintf(stderr, "mark from move buf %i %p\n", i, thd->moveBuf[i]); + fprintf(stderr, "coop mark from move buf %i %p\n", i, thd->moveBuf[i]); } } #endif From e7d0dbc87fae359b20f0a3fb60b15fb32a52ee90 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 01:42:29 -0500 Subject: [PATCH 220/339] Turning off debug traces --- include/cyclone/types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index e7f9c809..7f05354b 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -181,8 +181,8 @@ gc_heap *gc_get_heap(); //void gc_collector() /* GC debugging flags */ -#define GC_DEBUG_TRACE 1 -#define GC_DEBUG_VERBOSE 1 +#define GC_DEBUG_TRACE 0 +#define GC_DEBUG_VERBOSE 0 /* Additional runtime checking of the GC system. This is here because these checks should not be From d89b90f4b36ce43d628c935bb74719c4be15173f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 02:00:32 -0500 Subject: [PATCH 221/339] Added reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 68dedf28..29950b84 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ References - [CHICKEN Scheme](http://www.call-cc.org/) - [Chibi Scheme](https://github.com/ashinn/chibi-scheme) - [Compiling Scheme to C with closure conversion](http://matt.might.net/articles/compiling-scheme-to-c/), by Matt Might +- [Implementing an on-the-fly garbage collector for Java], by Domani et al - [Lisp in Small Pieces](http://pagesperso-systeme.lip6.fr/Christian.Queinnec/WWW/LiSP.html), by Christian Queinnec - [R5RS Scheme Specification](http://www.schemers.org/Documents/Standards/R5RS/HTML/) - [R7RS Scheme Specification](http://trac.sacrideo.us/wg/wiki) From c76241630d84eef9b21a4319da126a1d92d6ebe6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 02:02:17 -0500 Subject: [PATCH 222/339] Updated with latest progress --- gc-notes.txt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 13e814e6..360e3fbb 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -4,22 +4,9 @@ Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naiv Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. -memory corruption - - noticed that an object may be allocated with the old mark color, and then freed before it - can be marked, even though it is part of a global list. - what might be happening is that the new heap obj is part of the global list, but the minor - GC only marks gc-cont/gc-args, which this is not part of. and the globals are already marked - at that point by the collector thread, so no one is around to mark this object. - wait a minute - but how does the obj even get on the heap? see this - if above was true there would be no ref to move this to the heap, right? so what is going on?? -> -alloc 0xb78400e0 size = 32, obj=0xbffcd648, tag=0, mark=1 -well, we also move globals, which would explain it since the next lambda becomes the head of the global list. so I think that explains it. the most expedient change is to just use moveBuf to mark the thread's roots. - -but again, this did not fix all crashes, so there are either other issues with the GC (not surprising, although disappointing) or this is not the issue. but I think this has to be a problem given the error output observed today. - TODO: -- need to fix memory corruption bugs -- need to cooperate when a mutator is blocked - need an intelligent scheduling of GC, instead of just constantly running it +- need to cooperate when a mutator is blocked - add_mutation will need to be brought into thread local data. - probably exceptions too. anything else? - multiple mutators, and threading functions/types. probably want this on a new branch, when ready From b97db40110e45ea916665375a6e7c1b73aec7408 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 02:04:59 -0500 Subject: [PATCH 223/339] Fixed markdown --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29950b84..16eda6fe 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ References - [CHICKEN Scheme](http://www.call-cc.org/) - [Chibi Scheme](https://github.com/ashinn/chibi-scheme) - [Compiling Scheme to C with closure conversion](http://matt.might.net/articles/compiling-scheme-to-c/), by Matt Might -- [Implementing an on-the-fly garbage collector for Java], by Domani et al +- Implementing an on-the-fly garbage collector for Java, by Domani et al - [Lisp in Small Pieces](http://pagesperso-systeme.lip6.fr/Christian.Queinnec/WWW/LiSP.html), by Christian Queinnec - [R5RS Scheme Specification](http://www.schemers.org/Documents/Standards/R5RS/HTML/) - [R7RS Scheme Specification](http://trac.sacrideo.us/wg/wiki) From 26c586ed2621127340137f10c9a9122859407758 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 02:10:21 -0500 Subject: [PATCH 224/339] Added second GC paper --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 16eda6fe..681b1c2e 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ References - [Compiling Scheme to C with closure conversion](http://matt.might.net/articles/compiling-scheme-to-c/), by Matt Might - Implementing an on-the-fly garbage collector for Java, by Domani et al - [Lisp in Small Pieces](http://pagesperso-systeme.lip6.fr/Christian.Queinnec/WWW/LiSP.html), by Christian Queinnec +- Portable, Unobtrusive Garbage Collection for Multiprocessor Systems, by Damien Doligez and Georges Gonthier - [R5RS Scheme Specification](http://www.schemers.org/Documents/Standards/R5RS/HTML/) - [R7RS Scheme Specification](http://trac.sacrideo.us/wg/wiki) - [Structure and Interpretation of Computer Programs](https://mitpress.mit.edu/sicp/full-text/book/book.html), by Harold Abelson and Gerald Jay Sussman From de0c19e1cd46faca665ee04429dd524c97adab8d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 9 Dec 2015 22:46:00 -0500 Subject: [PATCH 225/339] Keep track of the amount of free space in the heap --- gc.c | 30 +++++++++++++++++++++++++----- include/cyclone/types.h | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 4858b577..d9068bdd 100644 --- a/gc.c +++ b/gc.c @@ -86,6 +86,7 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) h = malloc(gc_heap_pad_size(size)); if (!h) return NULL; h->size = size; + h->free_size = size; h->chunk_size = chunk_size; h->max_size = max_size; h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); @@ -300,6 +301,7 @@ void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd) } // Copy object into heap now to avoid any uninitialized memory issues gc_copy_obj(f2, obj, thd); + h->free_size -= gc_allocated_bytes(obj, NULL, NULL); pthread_mutex_unlock(&heap_lock); return f2; } @@ -411,9 +413,21 @@ size_t gc_heap_total_size(gc_heap *h) return total_size; } +size_t gc_heap_total_free(gc_heap *h) +{ + size_t total_size = 0; + pthread_mutex_lock(&heap_lock); + while(h) { + total_size += h->free_size; + h = h->next; + } + pthread_mutex_unlock(&heap_lock); + return total_size; +} + size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) { - size_t freed, max_freed=0, sum_freed=0, size; + size_t freed, max_freed=0, heap_freed = 0, sum_freed=0, size; object p, end; gc_free_list *q, *r, *s; @@ -467,7 +481,7 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) #endif mark(p) = gc_color_blue; // Needed? // free p - sum_freed += size; + heap_freed += size; if (((((char *)q) + q->size) == (char *)p) && (q != h->free_list)) { /* merge q with p */ if (r && r->size && ((((char *)p)+size) == (char *)r)) { @@ -505,6 +519,9 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) p = (object)(((char *)p) + size); } } + h->free_size += heap_freed; + sum_freed += heap_freed; + heap_freed = 0; } pthread_mutex_unlock(&heap_lock); if (sum_freed_ptr) *sum_freed_ptr = sum_freed; @@ -1061,7 +1078,7 @@ void debug_dump_globals(); void gc_collector() { int old_clear, old_mark; - size_t freed = 0, max_freed = 0, total_size; + size_t freed = 0, max_freed = 0, total_size, total_free; #if GC_DEBUG_TRACE time_t sweep_start = time(NULL); #endif @@ -1104,9 +1121,12 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); // //sweep : max_freed = gc_sweep(gc_get_heap(), &freed); - // TODO: grow heap if it is mostly full after collection?? + total_size = gc_heap_total_size(gc_get_heap()); + total_free = gc_heap_total_free(gc_get_heap()); + #if GC_DEBUG_TRACE - fprintf(stderr, "sweep done, freed = %d, max_freed = %d, elapsed = %ld\n", + fprintf(stderr, "sweep done, total_size = %d, total_free = %d, freed = %d, max_freed = %d, elapsed = %ld\n", + total_size, total_free, freed, max_freed, time(NULL) - sweep_start); #endif gc_stage = STAGE_RESTING; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 7f05354b..0b342d8d 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -89,6 +89,7 @@ struct gc_heap_t { unsigned int size; unsigned int chunk_size; // 0 for any size, other and heap will only alloc chunks of that size unsigned int max_size; + unsigned int free_size; gc_free_list *free_list; // TBD gc_heap *next; // TBD, linked list is not very efficient, but easy to work with as a start char *data; @@ -150,6 +151,7 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); +size_t gc_heap_total_free(gc_heap *h); //size_t gc_collect(gc_heap *h, size_t *sum_freed); //void gc_mark(gc_heap *h, object obj); void gc_mark_globals(void); From 5fa6f19418278c901224be3758584cf2dcad46bc Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 9 Dec 2015 22:55:46 -0500 Subject: [PATCH 226/339] Adding stubs for collector scheduling --- gc.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/gc.c b/gc.c index d9068bdd..b310a5e8 100644 --- a/gc.c +++ b/gc.c @@ -303,6 +303,14 @@ void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd) gc_copy_obj(f2, obj, thd); h->free_size -= gc_allocated_bytes(obj, NULL, NULL); pthread_mutex_unlock(&heap_lock); + +// TODO: initiate collection cycle if free space is too low +// TODO: cache total size (??), probably need to do that because we +// want to look at sizes across all heaps, not just this one. and +// don't want to waste a lot of time scanning heaps to just to find +// these sizes +// if (gc_stage != STAGE_RESTING) { +// } return f2; } } @@ -1134,20 +1142,15 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); void *collector_main(void *arg) { + struct timespec tim; + tim.tv_sec = 0; + tim.tv_nsec = 100; while (1) { - gc_collector(); - // TODO: how to schedule this thread? - // this is inefficient but it should be good enough to - // at least stand up this collector. then we'll have to - // come back and improve it -// -// some ideas: -// - maybe check amount of free space in heap, and collect if less than a certain amount/percentage. -// otherwise just sleep for awhile and check again. -// once that works, might consider a way to let a mutator alert the collector that it should kick off -// - after collection, maybe grow heap if usage is above a certain percentage -// -// sleep(1); + // TODO: setup scheduling such that we transition away from resting at some point + //if (gc_stage != STAGE_RESTING) { + gc_collector(); + //} + nanosleep(&tim, NULL); } } From ded3f76cc8a7080ba9f317adc3291176d191b24a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 23:11:22 -0500 Subject: [PATCH 227/339] Scheduling of GC --- gc.c | 100 ++++++++++++++++++++++++---------------- include/cyclone/types.h | 4 +- 2 files changed, 63 insertions(+), 41 deletions(-) diff --git a/gc.c b/gc.c index b310a5e8..b2de5b01 100644 --- a/gc.c +++ b/gc.c @@ -15,6 +15,8 @@ //////////////////// // Global variables +static const int NANOSECONDS_PER_MILLISECOND = 1000000; + // Note: will need to use atomics and/or locking to access any // variables shared between threads static int gc_color_mark = 1; // Black, is swapped during GC @@ -23,7 +25,7 @@ static int gc_color_clear = 3; // White, is swapped during GC // unfortunately this had to be split up; const colors are located in types.h static int gc_status_col = STATUS_SYNC1; -static int gc_stage = STAGE_CLEAR_OR_MARKING; +static int gc_stage = STAGE_RESTING; // Does not need sync, only used by collector thread static void **mark_stack = NULL; @@ -33,6 +35,12 @@ static int mark_stack_i = 0; // Lock to protect the heap from concurrent modifications static pthread_mutex_t heap_lock; +// Cached heap statistics +// Note this assumes a single overall heap "chain". Code would need to +// be modified to support multiple independent heaps +static int cached_heap_free_size = 0; +static int cached_heap_total_size = 0; + // Data for each individual mutator thread static gc_thread_data **Cyc_mutators; static int Cyc_num_mutators; @@ -86,7 +94,9 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) h = malloc(gc_heap_pad_size(size)); if (!h) return NULL; h->size = size; - h->free_size = size; + //h->free_size = size; + cached_heap_total_size += size; + cached_heap_free_size += size; h->chunk_size = chunk_size; h->max_size = max_size; h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); @@ -301,16 +311,9 @@ void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd) } // Copy object into heap now to avoid any uninitialized memory issues gc_copy_obj(f2, obj, thd); - h->free_size -= gc_allocated_bytes(obj, NULL, NULL); + //h->free_size -= gc_allocated_bytes(obj, NULL, NULL); + cached_heap_free_size -= gc_allocated_bytes(obj, NULL, NULL); pthread_mutex_unlock(&heap_lock); - -// TODO: initiate collection cycle if free space is too low -// TODO: cache total size (??), probably need to do that because we -// want to look at sizes across all heaps, not just this one. and -// don't want to waste a lot of time scanning heaps to just to find -// these sizes -// if (gc_stage != STAGE_RESTING) { -// } return f2; } } @@ -421,17 +424,17 @@ size_t gc_heap_total_size(gc_heap *h) return total_size; } -size_t gc_heap_total_free(gc_heap *h) -{ - size_t total_size = 0; - pthread_mutex_lock(&heap_lock); - while(h) { - total_size += h->free_size; - h = h->next; - } - pthread_mutex_unlock(&heap_lock); - return total_size; -} +//size_t gc_heap_total_free_size(gc_heap *h) +//{ +// size_t total_size = 0; +// pthread_mutex_lock(&heap_lock); +// while(h) { +// total_size += h->free_size; +// h = h->next; +// } +// pthread_mutex_unlock(&heap_lock); +// return total_size; +//} size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) { @@ -527,7 +530,8 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) p = (object)(((char *)p) + size); } } - h->free_size += heap_freed; + //h->free_size += heap_freed; + cached_heap_free_size += heap_freed; sum_freed += heap_freed; heap_freed = 0; } @@ -763,7 +767,8 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) // TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { - int i, status = ATOMIC_GET(&gc_status_col); + int i, status = ATOMIC_GET(&gc_status_col), + stage = ATOMIC_GET(&gc_stage); #if GC_DEBUG_VERBOSE int debug_print = 0; #endif @@ -815,6 +820,16 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) } } #endif + + // Initiate collection cycle if free space is too low + if (stage == STAGE_RESTING && + (cached_heap_free_size < (cached_heap_total_size * 0.10))){ + fprintf(stdout, "Less than 10%% of the heap is free, initiating collector\n"); // Temporary debug line + ATOMIC_SET_IF_EQ(&gc_stage, + STAGE_RESTING, + STAGE_CLEAR_OR_MARKING); + + } } ///////////////////////////////////////////// @@ -1051,7 +1066,7 @@ void gc_wait_handshake() int i, statusm, statusc; struct timespec tim; tim.tv_sec = 0; - tim.tv_nsec = 1; + tim.tv_nsec = 1000000; // 1 millisecond // TODO: same as in other places, need to either sync access to // mutator vars, or ensure only the collector uses them @@ -1087,11 +1102,11 @@ void gc_collector() { int old_clear, old_mark; size_t freed = 0, max_freed = 0, total_size, total_free; -#if GC_DEBUG_TRACE +//#if GC_DEBUG_TRACE time_t sweep_start = time(NULL); -#endif +//#endif //clear : - gc_stage = STAGE_CLEAR_OR_MARKING; + ATOMIC_SET_IF_EQ(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); // exchange values of markColor and clearColor old_clear = ATOMIC_GET(&gc_color_clear); old_mark = ATOMIC_GET(&gc_color_mark); @@ -1109,7 +1124,7 @@ fprintf(stderr, "DEBUG - after handshake sync 1\n"); #if GC_DEBUG_TRACE fprintf(stderr, "DEBUG - after handshake sync 2\n"); #endif - gc_stage = STAGE_TRACING; + ATOMIC_SET_IF_EQ(&gc_stage, STAGE_CLEAR_OR_MARKING, STAGE_TRACING); gc_post_handshake(STATUS_ASYNC); #if GC_DEBUG_TRACE fprintf(stderr, "DEBUG - after post_handshake async\n"); @@ -1125,31 +1140,38 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); fprintf(stderr, "DEBUG - after trace\n"); //debug_dump_globals(); #endif - gc_stage = STAGE_SWEEPING; + ATOMIC_SET_IF_EQ(&gc_stage, STAGE_TRACING, STAGE_SWEEPING); // //sweep : max_freed = gc_sweep(gc_get_heap(), &freed); - total_size = gc_heap_total_size(gc_get_heap()); - total_free = gc_heap_total_free(gc_get_heap()); + total_size = cached_heap_total_size; //gc_heap_total_size(gc_get_heap()); + total_free = cached_heap_free_size; //gc_heap_total_free_size(gc_get_heap()); -#if GC_DEBUG_TRACE + if (total_free < (total_size * 0.10)) { +fprintf(stdout, "JAE TODO: may need to rethink this growth strategy\n"); + fprintf(stdout, "Less than 10%% of the heap is free, growing it\n", + total_free, total_size); + gc_grow_heap(gc_get_heap(), 0, 0); + } +//#if GC_DEBUG_TRACE fprintf(stderr, "sweep done, total_size = %d, total_free = %d, freed = %d, max_freed = %d, elapsed = %ld\n", total_size, total_free, freed, max_freed, time(NULL) - sweep_start); -#endif - gc_stage = STAGE_RESTING; +//#endif + ATOMIC_SET_IF_EQ(&gc_stage, STAGE_SWEEPING, STAGE_RESTING); } void *collector_main(void *arg) { + int stage; struct timespec tim; tim.tv_sec = 0; - tim.tv_nsec = 100; + tim.tv_nsec = 100 * NANOSECONDS_PER_MILLISECOND; while (1) { - // TODO: setup scheduling such that we transition away from resting at some point - //if (gc_stage != STAGE_RESTING) { + stage = ATOMIC_GET(&gc_stage); + if (stage != STAGE_RESTING) { gc_collector(); - //} + } nanosleep(&tim, NULL); } } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 0b342d8d..1b51e7b7 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -89,7 +89,7 @@ struct gc_heap_t { unsigned int size; unsigned int chunk_size; // 0 for any size, other and heap will only alloc chunks of that size unsigned int max_size; - unsigned int free_size; + //unsigned int free_size; gc_free_list *free_list; // TBD gc_heap *next; // TBD, linked list is not very efficient, but easy to work with as a start char *data; @@ -151,7 +151,7 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r); gc_heap *gc_heap_last(gc_heap *h); size_t gc_heap_total_size(gc_heap *h); -size_t gc_heap_total_free(gc_heap *h); +//size_t gc_heap_total_free_size(gc_heap *h); //size_t gc_collect(gc_heap *h, size_t *sum_freed); //void gc_mark(gc_heap *h, object obj); void gc_mark_globals(void); From be9a07551e05e254e2b642471d6115d90f80fa04 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 23:13:40 -0500 Subject: [PATCH 228/339] Added notes --- gc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gc.c b/gc.c index b2de5b01..4095fb25 100644 --- a/gc.c +++ b/gc.c @@ -1166,6 +1166,9 @@ void *collector_main(void *arg) int stage; struct timespec tim; tim.tv_sec = 0; +JAE TODO: this is still not good enough, seems memory grows still grows fast with this. +alternatively, may want to consider shrinking the heap if possible after a collection, if it is +sparse enough (would be difficult to do without relocations, though tim.tv_nsec = 100 * NANOSECONDS_PER_MILLISECOND; while (1) { stage = ATOMIC_GET(&gc_stage); From 29e6cb38e98de105e16080d5f088f0ee86bb19b7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 21:48:19 -0500 Subject: [PATCH 229/339] Tweaked GC thresholds --- gc.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/gc.c b/gc.c index 4095fb25..35b25f8e 100644 --- a/gc.c +++ b/gc.c @@ -821,13 +821,15 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) } #endif - // Initiate collection cycle if free space is too low + // Initiate collection cycle if free space is too low. + // Threshold is intentially low because we have to go through an + // entire handshake/trace/sweep cycle, ideally without growing heap. if (stage == STAGE_RESTING && - (cached_heap_free_size < (cached_heap_total_size * 0.10))){ - fprintf(stdout, "Less than 10%% of the heap is free, initiating collector\n"); // Temporary debug line - ATOMIC_SET_IF_EQ(&gc_stage, - STAGE_RESTING, - STAGE_CLEAR_OR_MARKING); + (cached_heap_free_size < (cached_heap_total_size * 0.50))){ +#if GC_DEBUG_TRACE + fprintf(stdout, "Less than 50%% of the heap is free, initiating collector\n"); +#endif + ATOMIC_SET_IF_EQ(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); } } @@ -1102,9 +1104,9 @@ void gc_collector() { int old_clear, old_mark; size_t freed = 0, max_freed = 0, total_size, total_free; -//#if GC_DEBUG_TRACE +#if GC_DEBUG_TRACE time_t sweep_start = time(NULL); -//#endif +#endif //clear : ATOMIC_SET_IF_EQ(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); // exchange values of markColor and clearColor @@ -1148,16 +1150,17 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); total_free = cached_heap_free_size; //gc_heap_total_free_size(gc_get_heap()); if (total_free < (total_size * 0.10)) { -fprintf(stdout, "JAE TODO: may need to rethink this growth strategy\n"); - fprintf(stdout, "Less than 10%% of the heap is free, growing it\n", +#if GC_DEBUG_TRACE + fprintf(stdout, "Less than 10%% of the heap is free, growing it\n", total_free, total_size); +#endif gc_grow_heap(gc_get_heap(), 0, 0); } -//#if GC_DEBUG_TRACE +#if GC_DEBUG_TRACE fprintf(stderr, "sweep done, total_size = %d, total_free = %d, freed = %d, max_freed = %d, elapsed = %ld\n", total_size, total_free, freed, max_freed, time(NULL) - sweep_start); -//#endif +#endif ATOMIC_SET_IF_EQ(&gc_stage, STAGE_SWEEPING, STAGE_RESTING); } @@ -1166,9 +1169,9 @@ void *collector_main(void *arg) int stage; struct timespec tim; tim.tv_sec = 0; -JAE TODO: this is still not good enough, seems memory grows still grows fast with this. -alternatively, may want to consider shrinking the heap if possible after a collection, if it is -sparse enough (would be difficult to do without relocations, though +//JAE TODO: this is still not good enough, seems memory grows still grows fast with this. +//alternatively, may want to consider shrinking the heap if possible after a collection, if it is +//sparse enough (would be difficult to do without relocations, though tim.tv_nsec = 100 * NANOSECONDS_PER_MILLISECOND; while (1) { stage = ATOMIC_GET(&gc_stage); From 578972de58fe698f48a8cae559d0c08d8e275b67 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 10 Dec 2015 22:53:21 -0500 Subject: [PATCH 230/339] Added notes --- gc-notes.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index 360e3fbb..3180fe71 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -5,7 +5,10 @@ Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. TODO: -- need an intelligent scheduling of GC, instead of just constantly running it +- profiling and performance improvements + let's trying using hash tables for symbol table. maybe give concurrency kit a try, + since it could be used for atomic operations. also want data structures that will be + concurrency-friendly, especially hash tables - need to cooperate when a mutator is blocked - add_mutation will need to be brought into thread local data. - probably exceptions too. anything else? From ac7f94fa8aaa596e8cfb08057541816d284d9592 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 12 Dec 2015 02:55:14 -0500 Subject: [PATCH 231/339] Added temporary integration file --- test.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 test.c diff --git a/test.c b/test.c new file mode 100644 index 00000000..f16391fb --- /dev/null +++ b/test.c @@ -0,0 +1,178 @@ +/* +compile with ck in above directory, and using: +gcc test.c -g -lck && ./a.out +*/ +#include +#include "../ck/src/ck_ht_hash.h" +#include "include/cyclone/types.h" + +static ck_hs_t hs_symbol_table; + +static void *hs_malloc(size_t r) +{ + return malloc(r); +} + +static void +hs_free(void *p, size_t b, bool r) +{ + (void)b; + (void)r; + free(p); + return; +} + +static struct ck_malloc my_allocator = { + .malloc = hs_malloc, + .free = hs_free +}; + +static unsigned long +hs_hash(const void *object, unsigned long seed) +{ + const char *c = object; + unsigned long h; + + h = (unsigned long)MurmurHash64A(c, strlen(c), seed); + return h; +} + +static bool +hs_compare(const void *previous, const void *compare) +{ + + return strcmp(previous, compare) == 0; +} +static void * +set_get(ck_hs_t *hs, const char *value) +{ + unsigned long h; + void *v; + + h = CK_HS_HASH(hs, hs_hash, value); + v = ck_hs_get(hs, h, value); + return v; +} + +static bool +set_insert(ck_hs_t *hs, const char *value) +{ + unsigned long h; + + h = CK_HS_HASH(hs, hs_hash, value); + return ck_hs_put(hs, h, value); +} +//static void *table_get(ck_ht_t *ht, const char *value) +//{ +// ck_ht_entry_t entry; +// ck_ht_hash_t h; +// size_t l = strlen(value); +// void *v = NULL; +// +// ck_ht_hash(&h, ht, value, l); +// ck_ht_entry_key_set(&entry, value, l); +// +// if (ck_ht_get_spmc(ht, h, &entry) == true) { +// v = ck_ht_entry_value(&entry); +// } +// return v; +//} +// +//static int table_insert(ck_ht_t *ht, const char *key, const void *value) +//{ +// ck_ht_entry_t entry; +// ck_ht_hash_t h; +// size_t l = strlen(key); +// +// ck_ht_hash(&h, ht, key, l); +// ck_ht_entry_set(&entry, h, key, l, "VALUE"); //value); +// return ck_ht_put_spmc(ht, h, &entry); +//} +//// END CK section +// + +char *_strdup (const char *s) { + char *d = malloc (strlen (s) + 1); + if (d) { strcpy (d,s); } + return d; +} + +//object find_symbol_by_name(const char *name) { +// //list l = symbol_table; +// //for (; !nullp(l); l = cdr(l)) { +// // const char *str = symbol_pname(car(l)); +// // if (strcmp(str, name) == 0) return car(l); +// //} +// //return nil; +// object result = set_get(&hs_symbol_table, name); +// if (result) { +// printf("found symbol %s\n", symbol_pname(result)); +// } +// return result; +//} +// +//object add_symbol(symbol_type *psym) { +// //symbol_table = mcons(psym, symbol_table); +// printf("Adding symbol %s\n", symbol_pname(psym)); +// set_insert(&hs_symbol_table, symbol_pname(psym), psym); +// return psym; +//} +// +//object add_symbol_by_name(const char *name) { +// symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; +// symbol_type *psym = malloc(sizeof(symbol_type)); +// memcpy(psym, &sym, sizeof(symbol_type)); +// return add_symbol(psym); +//} +// +//object find_or_add_symbol(const char *name){ +// object sym = find_symbol_by_name(name); +// if (sym){ +// return sym; +// } else { +// return add_symbol_by_name(name); +// } +//} +// +void main() +{ + char a[] = "a"; + char b[] = "b"; + char c[] = "c"; + + if (!ck_hs_init(&hs_symbol_table, + CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, + hs_hash, hs_compare, + &my_allocator, + 2, 43423)){ + fprintf(stderr, "Unable to initialize symbol table\n"); + exit(1); + } + + + set_insert(&hs_symbol_table, a); + printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + printf("has \"a\" = %p\n", set_get(&hs_symbol_table, "a")); + printf("has \"b\" = %p\n", set_get(&hs_symbol_table, "b")); + + set_insert(&hs_symbol_table, b); + printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + printf("has \"a\" = %p\n", set_get(&hs_symbol_table, "a")); + printf("has \"b\" = %p\n", set_get(&hs_symbol_table, "b")); +// object a = find_or_add_symbol("a"); +// printf("%p\n", a); +// +// object b = find_or_add_symbol("b"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object c = find_or_add_symbol("c"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object d = find_or_add_symbol("d"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object aa = find_or_add_symbol("a"); +// printf("%p\n", aa); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + return; +} From 166f67c7d3cdb06483766bc7edb65a29ee844749 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 12 Dec 2015 03:11:13 -0500 Subject: [PATCH 232/339] Use symbol_type as key instead of (char *) --- test.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/test.c b/test.c index f16391fb..7d23f8f7 100644 --- a/test.c +++ b/test.c @@ -30,10 +30,15 @@ static struct ck_malloc my_allocator = { static unsigned long hs_hash(const void *object, unsigned long seed) { - const char *c = object; +// const char *c = object; +// unsigned long h; +// +// h = (unsigned long)MurmurHash64A(c, strlen(c), seed); +// return h; + const symbol_type *c = object; unsigned long h; - h = (unsigned long)MurmurHash64A(c, strlen(c), seed); + h = (unsigned long)MurmurHash64A(c->pname, strlen(c->pname), seed); return h; } @@ -41,10 +46,11 @@ static bool hs_compare(const void *previous, const void *compare) { - return strcmp(previous, compare) == 0; + return strcmp((previous), (compare)) == 0; + //return strcmp(symbol_pname(previous), symbol_pname(compare)) == 0; } static void * -set_get(ck_hs_t *hs, const char *value) +set_get(ck_hs_t *hs, const void *value) { unsigned long h; void *v; @@ -55,7 +61,7 @@ set_get(ck_hs_t *hs, const char *value) } static bool -set_insert(ck_hs_t *hs, const char *value) +set_insert(ck_hs_t *hs, const void *value) { unsigned long h; @@ -136,9 +142,13 @@ char *_strdup (const char *s) { // void main() { - char a[] = "a"; - char b[] = "b"; - char c[] = "c"; + char astr[] = "a"; + char bstr[] = "b"; + char cstr[] = "c"; + symbol_type a = {{0}, symbol_tag, astr, nil}; + symbol_type aa = {{0}, symbol_tag, astr, nil}; + symbol_type b = {{0}, symbol_tag, bstr, nil}; + symbol_type c = {{0}, symbol_tag, cstr, nil}; if (!ck_hs_init(&hs_symbol_table, CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, @@ -150,15 +160,17 @@ void main() } - set_insert(&hs_symbol_table, a); + set_insert(&hs_symbol_table, &a); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - printf("has \"a\" = %p\n", set_get(&hs_symbol_table, "a")); - printf("has \"b\" = %p\n", set_get(&hs_symbol_table, "b")); + printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); + printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); + printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); - set_insert(&hs_symbol_table, b); + set_insert(&hs_symbol_table, &b); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - printf("has \"a\" = %p\n", set_get(&hs_symbol_table, "a")); - printf("has \"b\" = %p\n", set_get(&hs_symbol_table, "b")); + printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); + printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); + printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); // object a = find_or_add_symbol("a"); // printf("%p\n", a); // From d8a96d17b78ee7842cbff30808c905b8aa4f0149 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 21:16:17 -0500 Subject: [PATCH 233/339] Added header comment --- gc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gc.c b/gc.c index 35b25f8e..66556041 100644 --- a/gc.c +++ b/gc.c @@ -1,13 +1,13 @@ -/* A basic mark-sweep GC - As of now, the GC code is based off the implementation from chibi scheme - - Goals of this project: - - write algorithms - - add test cases - - integrate with types - - integrate with cyclone - - extend to tri-color marking an on-the-fly collection - - etc... +/** + * Cyclone Scheme + * Copyright (c) 2015, Justin Ethier + * All rights reserved. + * + * Primary garbage collector used by the Cyclone runtime. + * Based on the tracing GC algorithm from: + * "Implementing an on-the-fly garbage collector for Java", by Domani et al. + * + * The heap implementation (alloc / sweep, etc) is based on code from Chibi Scheme. */ #include "cyclone/types.h" From 35e9ec76d51459aa207fb64ba317f401df9dd722 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 21:24:24 -0500 Subject: [PATCH 234/339] Modified to work with existing runtime api --- test.c | 145 ++++++++++++++++++++++----------------------------------- 1 file changed, 56 insertions(+), 89 deletions(-) diff --git a/test.c b/test.c index 7d23f8f7..854d0e21 100644 --- a/test.c +++ b/test.c @@ -68,34 +68,6 @@ set_insert(ck_hs_t *hs, const void *value) h = CK_HS_HASH(hs, hs_hash, value); return ck_hs_put(hs, h, value); } -//static void *table_get(ck_ht_t *ht, const char *value) -//{ -// ck_ht_entry_t entry; -// ck_ht_hash_t h; -// size_t l = strlen(value); -// void *v = NULL; -// -// ck_ht_hash(&h, ht, value, l); -// ck_ht_entry_key_set(&entry, value, l); -// -// if (ck_ht_get_spmc(ht, h, &entry) == true) { -// v = ck_ht_entry_value(&entry); -// } -// return v; -//} -// -//static int table_insert(ck_ht_t *ht, const char *key, const void *value) -//{ -// ck_ht_entry_t entry; -// ck_ht_hash_t h; -// size_t l = strlen(key); -// -// ck_ht_hash(&h, ht, key, l); -// ck_ht_entry_set(&entry, h, key, l, "VALUE"); //value); -// return ck_ht_put_spmc(ht, h, &entry); -//} -//// END CK section -// char *_strdup (const char *s) { char *d = malloc (strlen (s) + 1); @@ -103,43 +75,37 @@ char *_strdup (const char *s) { return d; } -//object find_symbol_by_name(const char *name) { -// //list l = symbol_table; -// //for (; !nullp(l); l = cdr(l)) { -// // const char *str = symbol_pname(car(l)); -// // if (strcmp(str, name) == 0) return car(l); -// //} -// //return nil; -// object result = set_get(&hs_symbol_table, name); -// if (result) { -// printf("found symbol %s\n", symbol_pname(result)); -// } -// return result; -//} -// -//object add_symbol(symbol_type *psym) { -// //symbol_table = mcons(psym, symbol_table); -// printf("Adding symbol %s\n", symbol_pname(psym)); -// set_insert(&hs_symbol_table, symbol_pname(psym), psym); -// return psym; -//} -// -//object add_symbol_by_name(const char *name) { -// symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; -// symbol_type *psym = malloc(sizeof(symbol_type)); -// memcpy(psym, &sym, sizeof(symbol_type)); -// return add_symbol(psym); -//} -// -//object find_or_add_symbol(const char *name){ -// object sym = find_symbol_by_name(name); -// if (sym){ -// return sym; -// } else { -// return add_symbol_by_name(name); -// } -//} -// +object find_symbol_by_name(const char *name) { + symbol_type tmp = {{0}, symbol_tag, name, nil}; + object result = set_get(&hs_symbol_table, &tmp); + if (result) { + printf("found symbol %s\n", symbol_pname(result)); + } + return result; +} + +object add_symbol(symbol_type *psym) { + printf("Adding symbol %s\n", symbol_pname(psym)); + set_insert(&hs_symbol_table, psym); + return psym; +} + +object add_symbol_by_name(const char *name) { + symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; + symbol_type *psym = malloc(sizeof(symbol_type)); + memcpy(psym, &sym, sizeof(symbol_type)); + return add_symbol(psym); +} + +object find_or_add_symbol(const char *name){ + object sym = find_symbol_by_name(name); + if (sym){ + return sym; + } else { + return add_symbol_by_name(name); + } +} + void main() { char astr[] = "a"; @@ -160,31 +126,32 @@ void main() } - set_insert(&hs_symbol_table, &a); - printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); - printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); - printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); +// set_insert(&hs_symbol_table, &a); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); +// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); +// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); +// +// set_insert(&hs_symbol_table, &b); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); +// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); +// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); - set_insert(&hs_symbol_table, &b); + object asym = find_or_add_symbol("a"); + printf("%p\n", asym); + + object bsym = find_or_add_symbol("b"); + printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + + object csym = find_or_add_symbol("c"); + printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + + object dsym = find_or_add_symbol("d"); + printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); + + object aasym = find_or_add_symbol("a"); + printf("%p\n", aasym); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); - printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); - printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); -// object a = find_or_add_symbol("a"); -// printf("%p\n", a); -// -// object b = find_or_add_symbol("b"); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); -// -// object c = find_or_add_symbol("c"); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); -// -// object d = find_or_add_symbol("d"); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); -// -// object aa = find_or_add_symbol("a"); -// printf("%p\n", aa); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); return; } From dbab8ba26b7f25bdfef368d653fc169a66208ce9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 21:38:17 -0500 Subject: [PATCH 235/339] Initial file --- include/cyclone/ck_ht_hash.h | 269 +++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 include/cyclone/ck_ht_hash.h diff --git a/include/cyclone/ck_ht_hash.h b/include/cyclone/ck_ht_hash.h new file mode 100644 index 00000000..cd3d7a53 --- /dev/null +++ b/include/cyclone/ck_ht_hash.h @@ -0,0 +1,269 @@ +/* + * Copyright 2012-2015 Samy Al Bahra + * Copyright 2011-2014 AppNexus, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_HT_HASH_H +#define CK_HT_HASH_H + +/* + * This is the Murmur hash written by Austin Appleby. + */ + +#include +#include + +//----------------------------------------------------------------------------- +// MurmurHash3 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - The x86 and x64 versions do _not_ produce the same results, as the +// algorithms are optimized for their respective platforms. You can still +// compile and run any of them on any platform, but your performance with the +// non-native version will be less than optimal. + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define FORCE_INLINE __forceinline + +#include + +#define ROTL32(x,y) _rotl(x,y) +#define ROTL64(x,y) _rotl64(x,y) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define FORCE_INLINE inline __attribute__((always_inline)) + +static inline uint32_t rotl32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +static inline uint64_t rotl64 ( uint64_t x, int8_t r ) +{ + return (x << r) | (x >> (64 - r)); +} + +#define ROTL32(x,y) rotl32(x,y) +#define ROTL64(x,y) rotl64(x,y) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +FORCE_INLINE static uint32_t getblock ( const uint32_t * p, int i ) +{ + return p[i]; +} + +//----------------------------------------------------------------------------- +// Finalization mix - force all bits of a hash block to avalanche + +FORCE_INLINE static uint32_t fmix ( uint32_t h ) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +//----------------------------------------------------------------------------- + +static inline void MurmurHash3_x86_32 ( const void * key, int len, + uint32_t seed, uint32_t * out ) +{ + const uint8_t * data = (const uint8_t*)key; + const int nblocks = len / 4; + int i; + + uint32_t h1 = seed; + + uint32_t c1 = 0xcc9e2d51; + uint32_t c2 = 0x1b873593; + + //---------- + // body + + const uint32_t * blocks = (const uint32_t *)(const void *)(data + nblocks*4); + + for(i = -nblocks; i; i++) + { + uint32_t k1 = getblock(blocks,i); + + k1 *= c1; + k1 = ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1,13); + h1 = h1*5+0xe6546b64; + } + + //---------- + // tail + + const uint8_t * tail = (const uint8_t*)(data + nblocks*4); + + uint32_t k1 = 0; + + switch(len & 3) + { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h1 = fmix(h1); + + *(uint32_t *)out = h1; +} + +static inline uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed ) +{ + const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995); + const int r = 47; + + uint64_t h = seed ^ (len * m); + + const uint64_t * data = (const uint64_t *)key; + const uint64_t * end = data + (len/8); + + while(data != end) + { + uint64_t k; + + if (!((uintptr_t)data & 0x7)) + k = *data++; + else { + memcpy(&k, data, sizeof(k)); + data++; + } + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + const unsigned char * data2 = (const unsigned char*)data; + + switch(len & 7) + { + case 7: h ^= (uint64_t)(data2[6]) << 48; + case 6: h ^= (uint64_t)(data2[5]) << 40; + case 5: h ^= (uint64_t)(data2[4]) << 32; + case 4: h ^= (uint64_t)(data2[3]) << 24; + case 3: h ^= (uint64_t)(data2[2]) << 16; + case 2: h ^= (uint64_t)(data2[1]) << 8; + case 1: h ^= (uint64_t)(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return h; +} + + +// 64-bit hash for 32-bit platforms + +static inline uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed ) +{ + const uint32_t m = 0x5bd1e995; + const int r = 24; + + uint32_t h1 = (uint32_t)(seed) ^ len; + uint32_t h2 = (uint32_t)(seed >> 32); + + const uint32_t * data = (const uint32_t *)key; + + while(len >= 8) + { + uint32_t k1 = *data++; + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + + uint32_t k2 = *data++; + k2 *= m; k2 ^= k2 >> r; k2 *= m; + h2 *= m; h2 ^= k2; + len -= 4; + } + + if(len >= 4) + { + uint32_t k1 = *data++; + k1 *= m; k1 ^= k1 >> r; k1 *= m; + h1 *= m; h1 ^= k1; + len -= 4; + } + + switch(len) + { + case 3: h2 ^= ((const unsigned char*)data)[2] << 16; + case 2: h2 ^= ((const unsigned char*)data)[1] << 8; + case 1: h2 ^= ((const unsigned char*)data)[0]; + h2 *= m; + }; + + h1 ^= h2 >> 18; h1 *= m; + h2 ^= h1 >> 22; h2 *= m; + h1 ^= h2 >> 17; h1 *= m; + h2 ^= h1 >> 19; h2 *= m; + + uint64_t h = h1; + + h = (h << 32) | h2; + + return h; +} + +#endif /* CK_HT_HASH_H */ From c5f46e66f4fdcbc505852108ff572bf53af14b8e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 21:39:24 -0500 Subject: [PATCH 236/339] Removed unneeded export --- include/cyclone/runtime.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 51392fc2..919101db 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -198,7 +198,6 @@ object add_symbol(symbol_type *psym); object add_symbol_by_name(const char *name); object find_symbol_by_name(const char *name); object find_or_add_symbol(const char *name); -extern list symbol_table; extern list global_table; void add_global(object *glo); From 6956396fea634458598c7b45cbd91bbacc7f6e3c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 21:39:35 -0500 Subject: [PATCH 237/339] Copy new header --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 79e28006..00403ef5 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ bootstrap: icyc cp include/cyclone/types.h $(BOOTSTRAP_DIR)/include/cyclone cp include/cyclone/runtime-main.h $(BOOTSTRAP_DIR)/include/cyclone cp include/cyclone/runtime.h $(BOOTSTRAP_DIR)/include/cyclone + cp include/cyclone/ck_ht_hash.h $(BOOTSTRAP_DIR)/include/cyclone cp scheme/*.sld $(BOOTSTRAP_DIR)/scheme cp scheme/cyclone/*.sld $(BOOTSTRAP_DIR)/scheme/cyclone cp runtime.c $(BOOTSTRAP_DIR) From 84d74409cbdc54eabc7be1f85fa7e92277fe9aad Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 22:27:21 -0500 Subject: [PATCH 238/339] Use ck hashset to speed up our symbol table --- cyclone.scm | 2 +- runtime.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++------ test.c | 14 ++++----- 3 files changed, 88 insertions(+), 18 deletions(-) diff --git a/cyclone.scm b/cyclone.scm index e44a283e..b43e72f9 100644 --- a/cyclone.scm +++ b/cyclone.scm @@ -286,7 +286,7 @@ (comp-prog-cmd (string-append "gcc " src-file " -g -c -o " exec-file ".o")) (comp-objs-cmd - (string-append "gcc " exec-file ".o " objs-str " -pthread -lcyclone -lm -g -o " exec-file))) + (string-append "gcc " exec-file ".o " objs-str " -pthread -lcyclone -lck -lm -g -o " exec-file))) ;(write `(DEBUG all imports ,lib-deps objs ,objs-str)) ;(write `(DEBUG ,(lib:get-all-import-deps (cdar in-prog)))) (cond diff --git a/runtime.c b/runtime.c index 616eb527..76f20af9 100644 --- a/runtime.c +++ b/runtime.c @@ -6,8 +6,10 @@ * This file contains the C runtime used by compiled programs. */ +#include #include "cyclone/types.h" #include "cyclone/runtime.h" +#include "cyclone/ck_ht_hash.h" #include // TODO: only used for debugging! //int JAE_DEBUG = 0; @@ -97,10 +99,74 @@ char **_cyc_argv = NULL; static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of custom type const object Cyc_EOF = &__EOF; +static ck_hs_t symbol_table; +static int symbol_table_size = 65536; + +// Functions to support concurrency kit hashset +// These are specifically for a table of symbols +static void *hs_malloc(size_t r) +{ + return malloc(r); +} + +static void hs_free(void *p, size_t b, bool r) +{ +// (void)b; +// (void)r; + free(p); +// return; +} + +static struct ck_malloc my_allocator = { + .malloc = hs_malloc, + .free = hs_free +}; + +static unsigned long hs_hash(const void *object, unsigned long seed) +{ + const symbol_type *c = object; + unsigned long h; + + h = (unsigned long)MurmurHash64A(c->pname, strlen(c->pname), seed); + return h; +} + +static bool hs_compare(const void *previous, const void *compare) +{ + return strcmp(symbol_pname(previous), symbol_pname(compare)) == 0; +} + +static void *set_get(ck_hs_t *hs, const void *value) +{ + unsigned long h; + void *v; + + h = CK_HS_HASH(hs, hs_hash, value); + v = ck_hs_get(hs, h, value); + return v; +} + +static bool set_insert(ck_hs_t *hs, const void *value) +{ + unsigned long h; + + h = CK_HS_HASH(hs, hs_hash, value); + return ck_hs_put(hs, h, value); +} +// End supporting functions void gc_init_heap(long heap_size) { Cyc_heap = gc_heap_create(heap_size, 0, 0); + if (!ck_hs_init(&symbol_table, + CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, + hs_hash, hs_compare, + &my_allocator, + symbol_table_size, + 43423)){ + fprintf(stderr, "Unable to initialize symbol table\n"); + exit(1); + } } gc_heap *gc_get_heap() @@ -166,8 +232,6 @@ void Cyc_st_print(FILE *out) { For now, GC of symbols is missing. long-term it probably would be desirable */ -list symbol_table = nil; - char *_strdup (const char *s) { char *d = malloc (strlen (s) + 1); if (d) { strcpy (d,s); } @@ -175,16 +239,23 @@ char *_strdup (const char *s) { } object find_symbol_by_name(const char *name) { - list l = symbol_table; - for (; !nullp(l); l = cdr(l)) { - const char *str = symbol_pname(car(l)); - if (strcmp(str, name) == 0) return car(l); - } - return nil; + symbol_type tmp = {{0}, symbol_tag, name, nil}; + object result = set_get(&symbol_table, &tmp); + //if (result) { + // printf("found symbol %s\n", symbol_pname(result)); + //} + return result; } object add_symbol(symbol_type *psym) { - symbol_table = mcons(psym, symbol_table); + //printf("Adding symbol %s, table size = %ld\n", symbol_pname(psym), ck_hs_count(&symbol_table)); + // TODO: lock table here, only allow one writer at a time + // TODO: grow table if it is not big enough + if (ck_hs_count(&symbol_table) == symbol_table_size) { + fprintf(stderr, "Ran out of symbol table entries\n"); + exit(1); + } + set_insert(&symbol_table, psym); return psym; } @@ -203,6 +274,7 @@ object find_or_add_symbol(const char *name){ return add_symbol_by_name(name); } } + /* END symbol table */ /* Global table */ diff --git a/test.c b/test.c index 854d0e21..01e8a8fe 100644 --- a/test.c +++ b/test.c @@ -13,8 +13,7 @@ static void *hs_malloc(size_t r) return malloc(r); } -static void -hs_free(void *p, size_t b, bool r) +static void hs_free(void *p, size_t b, bool r) { (void)b; (void)r; @@ -27,8 +26,7 @@ static struct ck_malloc my_allocator = { .free = hs_free }; -static unsigned long -hs_hash(const void *object, unsigned long seed) +static unsigned long hs_hash(const void *object, unsigned long seed) { // const char *c = object; // unsigned long h; @@ -120,7 +118,7 @@ void main() CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, hs_hash, hs_compare, &my_allocator, - 2, 43423)){ + 1024, 43423)){ fprintf(stderr, "Unable to initialize symbol table\n"); exit(1); } @@ -138,19 +136,19 @@ void main() // printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); // printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); - object asym = find_or_add_symbol("a"); + object asym = find_or_add_symbol("producer"); printf("%p\n", asym); object bsym = find_or_add_symbol("b"); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - object csym = find_or_add_symbol("c"); + object csym = find_or_add_symbol("lambda"); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); object dsym = find_or_add_symbol("d"); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - object aasym = find_or_add_symbol("a"); + object aasym = find_or_add_symbol("producer"); printf("%p\n", aasym); printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); return; From dcf9396be2736f21512e0d1bd7f47716fc909fa7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 22:36:31 -0500 Subject: [PATCH 239/339] Added a note about global table --- runtime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 76f20af9..04636296 100644 --- a/runtime.c +++ b/runtime.c @@ -277,7 +277,9 @@ object find_or_add_symbol(const char *name){ /* END symbol table */ -/* Global table */ +/* Global table + A list is appropriate for this table because the only time + we use it is to iterate over all the globals... */ list global_table = nil; void add_global(object *glo) { From 4b3949ccb474dceb05be92c65c2af26f74c551a3 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 11 Dec 2015 23:09:54 -0500 Subject: [PATCH 240/339] Speed up call history and remove debug code --- runtime.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/runtime.c b/runtime.c index 04636296..1a1cbcce 100644 --- a/runtime.c +++ b/runtime.c @@ -10,7 +10,7 @@ #include "cyclone/types.h" #include "cyclone/runtime.h" #include "cyclone/ck_ht_hash.h" -#include // TODO: only used for debugging! +//#include // TODO: only used for debugging! //int JAE_DEBUG = 0; //int gcMoveCountsDEBUG[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; @@ -49,7 +49,8 @@ const char *tag_names[21] = { \ void Cyc_invalid_type_error(void *data, int tag, object found) { char buf[256]; - snprintf(buf, 255, "Invalid type: expected %s, found (%p) ", tag_names[tag], found); + snprintf(buf, 255, "Invalid type: expected %s, found ", tag_names[tag]); + //snprintf(buf, 255, "Invalid type: expected %s, found (%p) ", tag_names[tag], found); Cyc_rt_raise2(data, buf, found); } @@ -190,6 +191,7 @@ const object quote_void = &Cyc_void_symbol; static const int MAX_STACK_TRACES = 10; static char **Cyc_Stack_Traces; static int Cyc_Stack_Trace_Idx = 0; +static char *Cyc_Stack_Prev_Frame = NULL; void Cyc_st_init() { Cyc_Stack_Traces = calloc(MAX_STACK_TRACES, sizeof(char *)); @@ -197,7 +199,8 @@ void Cyc_st_init() { void Cyc_st_add(char *frame) { // Do not allow recursion to remove older frames - if (frame != Cyc_Stack_Traces[(Cyc_Stack_Trace_Idx - 1) % MAX_STACK_TRACES]) { + if (frame != Cyc_Stack_Prev_Frame) { + Cyc_Stack_Prev_Frame = frame; Cyc_Stack_Traces[Cyc_Stack_Trace_Idx] = frame; Cyc_Stack_Trace_Idx = (Cyc_Stack_Trace_Idx + 1) % MAX_STACK_TRACES; } @@ -277,9 +280,7 @@ object find_or_add_symbol(const char *name){ /* END symbol table */ -/* Global table - A list is appropriate for this table because the only time - we use it is to iterate over all the globals... */ +/* Global table */ list global_table = nil; void add_global(object *glo) { @@ -362,7 +363,7 @@ object Cyc_default_exception_handler(void *data, int argc, closure _, object err fprintf(stderr, "\nCall history:\n"); Cyc_st_print(stderr); fprintf(stderr, "\n"); -raise(SIGINT); // break into debugger, unix only + //raise(SIGINT); // break into debugger, unix only exit(1); return nil; } From add7c572c8f06e2b1bef7d015b0725853780e326 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 12 Dec 2015 23:01:30 -0500 Subject: [PATCH 241/339] Added notes about next phase of development --- gc-notes.txt | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 3180fe71..76e0c19e 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -3,13 +3,46 @@ Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and b Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. +Phase 6 (TBD) - Multiple mutators (application threads) TODO: -- profiling and performance improvements - let's trying using hash tables for symbol table. maybe give concurrency kit a try, - since it could be used for atomic operations. also want data structures that will be - concurrency-friendly, especially hash tables -- need to cooperate when a mutator is blocked - add_mutation will need to be brought into thread local data. - probably exceptions too. anything else? - multiple mutators, and threading functions/types. probably want this on a new branch, when ready +- need to cooperate when a mutator is blocked + might be able to stop a thread and do a minor GC on it, but no longjmp until after major GC. + would need to figure out how to repack gc_cont and args + optionally, some primitives can accept a cont, how to handle? I guess we would have to + call the primitive with a wrapper instead of the real cont. + worse, how to handle args to a possibly blocking cont? maybe use some kind of proxy + objects? do these primitives need to use a read barrier?? ideally want low overhead... + + at the end of the day, obviously need to use a wrapper function to call the primitive, + instead of calling it directly. + + how to stop a thread? suppose mutator would set a member in thread data (need to mutex/atomic + that, and be careful about doing that for any shared members), and mutator would need to + lock somehow if that is set upon return. + + bottom line, only have to worry about this when calling potentially-blocking primitives. + and if one is blocked when collector is active, then need the collector to cooperate + instead of the blocked mutator. overally this seems do-able, though there are many details + to consider. + +- how to share variables between threads? + obviously need to use mutexes (on the application side) to handle access. + but how to handle the case where an object from one thread is added to + a list that belongs to another (IE, queueing an object)? because the + other thread's object might be added as a stack object. + + keep in mind referenced obj may be a list or such that contains many other + refs to stack objects on another thread + + how can a variable be shared? - cons, vector, set!, define (?), set-car, set-cdr + can we detect if there will be a problem? + * adding var to something in this thread - can tell that obj is red and not on this stack + * modifying list on another thread - if list is on heap, how do we know the 'owning' thread is + not this one? we would have no idea + + very concerned about how to make this work + From 606591ebe54d19d4fe538bf805f3fe78389dbd68 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 13 Dec 2015 00:19:58 -0500 Subject: [PATCH 242/339] Added more notes --- gc-notes.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 76e0c19e..66f97ae8 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -4,11 +4,15 @@ Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naiv Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. Phase 6 (TBD) - Multiple mutators (application threads) +Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) TODO: - add_mutation will need to be brought into thread local data. - probably exceptions too. anything else? + do this before branching??? + - multiple mutators, and threading functions/types. probably want this on a new branch, when ready + part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc - need to cooperate when a mutator is blocked might be able to stop a thread and do a minor GC on it, but no longjmp until after major GC. would need to figure out how to repack gc_cont and args @@ -46,3 +50,11 @@ TODO: very concerned about how to make this work + since we only need a minor GC to put the var in the heap, might be able to add a function to trigger a minor GC. could call this function, then it would be safe to move a var to another thread (I think). + + might also need to expose a function that would determine whether any given object lives on the stack, and which thread it is on (or at least, if it belongs to the current one). + + neither is ideal, but might make the whole thing workable. ideally application code would not need to know about stack vs heap + + this feature might end up being gc-dev7 (possibly the final phase) + From ead5bcb1008357c058171a305c18137b2edac73a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 22:55:57 -0500 Subject: [PATCH 243/339] Keep track of call history using thread data --- include/cyclone/runtime-main.h | 4 ---- include/cyclone/runtime.h | 4 ++-- include/cyclone/types.h | 4 ++++ runtime.c | 39 ++++++++++++++++++---------------- scheme/cyclone/cgen.sld | 2 +- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index c99cee8b..3d1890e8 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -19,10 +19,6 @@ static void Cyc_heap_init(long heap_size); static void Cyc_heap_init(long heap_size) { - /* Initialize stack trace table - TODO: will eventually be relocated to a per-thread operation */ - Cyc_st_init(); - /* Allocate heap area for second generation. */ #if DEBUG_SHOW_DIAG printf("main: Allocating and initializing heap...\n"); diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 919101db..b1888bcb 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -189,9 +189,9 @@ object memqp(void *,object,list); void Cyc_start_thread(gc_thread_data *thd); void GC(void *,closure,object*,int); -void Cyc_st_init(); void Cyc_st_add(char *frame); -void Cyc_st_print(FILE *out); +void Cyc_st_add2(void *data, char *frame); +void Cyc_st_print(void *data, FILE *out); char *_strdup (const char *s); object add_symbol(symbol_type *psym); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 1b51e7b7..3d423096 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -60,6 +60,10 @@ struct gc_thread_data_t { void **mark_buffer; int mark_buffer_len; pthread_mutex_t lock; + // Data needed for call history + char **stack_traces; + int stack_trace_idx; + char *stack_prev_frame; }; /* GC data structures */ diff --git a/runtime.c b/runtime.c index 1a1cbcce..e5b1aea9 100644 --- a/runtime.c +++ b/runtime.c @@ -189,24 +189,19 @@ const object quote_void = &Cyc_void_symbol; /* Stack Traces */ static const int MAX_STACK_TRACES = 10; -static char **Cyc_Stack_Traces; -static int Cyc_Stack_Trace_Idx = 0; -static char *Cyc_Stack_Prev_Frame = NULL; -void Cyc_st_init() { - Cyc_Stack_Traces = calloc(MAX_STACK_TRACES, sizeof(char *)); -} - -void Cyc_st_add(char *frame) { +void Cyc_st_add(char *frame) { } // TODO: a temporary function, merge with below +void Cyc_st_add2(void *data, char *frame) { + gc_thread_data *thd = (gc_thread_data *)data; // Do not allow recursion to remove older frames - if (frame != Cyc_Stack_Prev_Frame) { - Cyc_Stack_Prev_Frame = frame; - Cyc_Stack_Traces[Cyc_Stack_Trace_Idx] = frame; - Cyc_Stack_Trace_Idx = (Cyc_Stack_Trace_Idx + 1) % MAX_STACK_TRACES; + if (frame != thd->stack_prev_frame) { + thd->stack_prev_frame = frame; + thd->stack_traces[thd->stack_trace_idx] = frame; + thd->stack_trace_idx = (thd->stack_trace_idx + 1) % MAX_STACK_TRACES; } } -void Cyc_st_print(FILE *out) { +void Cyc_st_print(void *data, FILE *out) { /* print to stream, note it is possible that some traces could be on the stack after a GC. not sure what to do about it, may need to @@ -214,10 +209,11 @@ void Cyc_st_print(FILE *out) { or, with the tbl being so small, maybe it will not be an issue in practice? a bit risky to ignore though */ - int i = (Cyc_Stack_Trace_Idx + 1) % MAX_STACK_TRACES; - while (i != Cyc_Stack_Trace_Idx) { - if (Cyc_Stack_Traces[i]) { - fprintf(out, "%s\n", Cyc_Stack_Traces[i]); + gc_thread_data *thd = (gc_thread_data *)data; + int i = (thd->stack_trace_idx + 1) % MAX_STACK_TRACES; + while (i != thd->stack_trace_idx) { + if (thd->stack_traces[i]) { + fprintf(out, "%s\n", thd->stack_traces[i]); } i = (i + 1) % MAX_STACK_TRACES; } @@ -361,7 +357,7 @@ object Cyc_default_exception_handler(void *data, int argc, closure _, object err } fprintf(stderr, "\nCall history:\n"); - Cyc_st_print(stderr); + Cyc_st_print(data, stderr); fprintf(stderr, "\n"); //raise(SIGINT); // break into debugger, unix only exit(1); @@ -2484,6 +2480,13 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { void Cyc_start_thread(gc_thread_data *thd) { + thd->stack_trace_idx = 0; + thd->stack_prev_frame = NULL; + // TODO: may need to relocate the calloc to another function that + // initializes thread objects, rather than here that just calls them. + // at a minimum, should initialize it to NULL so we can test for that here. + thd->stack_traces = calloc(MAX_STACK_TRACES, sizeof(char *)); + /* Tank, load the jump program... */ setjmp(*(thd->jmp_start)); diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 9ebbf111..76c4d567 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -183,7 +183,7 @@ (null? (cdr trace))) "" (string-append - "Cyc_st_add(\"" + "Cyc_st_add2(data, \"" (car trace) ":" ;; TODO: escape backslashes From ddf54ec5c75ae399800983d0a7c3bb3af237ca41 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 23:16:28 -0500 Subject: [PATCH 244/339] Phasing-out Cyc_st_add2 --- include/cyclone/runtime.h | 2 +- runtime.c | 4 ++-- scheme/cyclone/cgen.sld | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index b1888bcb..9972c7b3 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -189,7 +189,7 @@ object memqp(void *,object,list); void Cyc_start_thread(gc_thread_data *thd); void GC(void *,closure,object*,int); -void Cyc_st_add(char *frame); +void Cyc_st_add(void *data, char *frame); void Cyc_st_add2(void *data, char *frame); void Cyc_st_print(void *data, FILE *out); diff --git a/runtime.c b/runtime.c index e5b1aea9..4b6c0e2f 100644 --- a/runtime.c +++ b/runtime.c @@ -190,8 +190,8 @@ const object quote_void = &Cyc_void_symbol; /* Stack Traces */ static const int MAX_STACK_TRACES = 10; -void Cyc_st_add(char *frame) { } // TODO: a temporary function, merge with below -void Cyc_st_add2(void *data, char *frame) { +void Cyc_st_add2(void *data, char *frame) { } // TODO: a temporary function, merge with below +void Cyc_st_add(void *data, char *frame) { gc_thread_data *thd = (gc_thread_data *)data; // Do not allow recursion to remove older frames if (frame != thd->stack_prev_frame) { diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 76c4d567..b6bd7f43 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -183,7 +183,7 @@ (null? (cdr trace))) "" (string-append - "Cyc_st_add2(data, \"" + "Cyc_st_add(data, \"" (car trace) ":" ;; TODO: escape backslashes From c61fcd69d71906d54fcd8911dba107f4f48f74b5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 23:17:14 -0500 Subject: [PATCH 245/339] Removing obsolete function --- include/cyclone/runtime.h | 1 - runtime.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 9972c7b3..4db8d288 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -190,7 +190,6 @@ void Cyc_start_thread(gc_thread_data *thd); void GC(void *,closure,object*,int); void Cyc_st_add(void *data, char *frame); -void Cyc_st_add2(void *data, char *frame); void Cyc_st_print(void *data, FILE *out); char *_strdup (const char *s); diff --git a/runtime.c b/runtime.c index 4b6c0e2f..401e96a6 100644 --- a/runtime.c +++ b/runtime.c @@ -190,7 +190,6 @@ const object quote_void = &Cyc_void_symbol; /* Stack Traces */ static const int MAX_STACK_TRACES = 10; -void Cyc_st_add2(void *data, char *frame) { } // TODO: a temporary function, merge with below void Cyc_st_add(void *data, char *frame) { gc_thread_data *thd = (gc_thread_data *)data; // Do not allow recursion to remove older frames From a0c6309a3b7722518dc855ff1d7e15bf0e56d0a0 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 23:28:36 -0500 Subject: [PATCH 246/339] Added notes --- gc-notes.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 66f97ae8..c36bbd08 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -3,13 +3,12 @@ Phase 2 (gc-dev2) - Change how strings are allocated, to clean up the code and b Phase 3 (gc-dev3) - Change from using a Cheney-style copying collector to a naive mark&sweep algorithm. Phase 4 (gc-dev4) - Integrating new tracing GC algorithm, added new thread data argument to runtime. Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC algorithm. -Phase 6 (TBD) - Multiple mutators (application threads) +Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) TODO: -- add_mutation will need to be brought into thread local data. -- probably exceptions too. anything else? - do this before branching??? +- bring exceptions into local thread data? anything else? + also, will probably need to lock shared resources such as I/O... - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc From ff18c50aac31356ac0c7ca49714afad36e85fe97 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 21:30:51 -0500 Subject: [PATCH 247/339] Cleanup all thread data members --- gc.c | 11 +++++++++++ include/cyclone/types.h | 22 +++++++++++++--------- runtime.c | 9 --------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/gc.c b/gc.c index 66556041..e1137c01 100644 --- a/gc.c +++ b/gc.c @@ -1215,6 +1215,9 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon (1 - STACK_GROWS_DOWNWARD)); exit(1); } + thd->stack_traces = calloc(MAX_STACK_TRACES, sizeof(char *)); + thd->stack_trace_idx = 0; + thd->stack_prev_frame = NULL; //thd->mutator_num = mut_num; thd->jmp_start = malloc(sizeof(jmp_buf)); thd->gc_args = malloc(sizeof(object) * NUM_GC_ANS); @@ -1236,10 +1239,18 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon void gc_thread_data_free(gc_thread_data *thd) { if (thd) { + if (pthread_mutex_destroy(&thd->lock) != 0) { + // TODO: can only destroy the lock if it is unlocked. need to make sure we + // can guarantee that is the case prior to making this call + // On the other hand, can we just use sleep and a loop to retry?? + fprintf(stderr, "Thread mutex is locked, unable to free\n"); + exit(1); + } if (thd->jmp_start) free(thd->jmp_start); if (thd->gc_args) free(thd->gc_args); if (thd->moveBuf) free(thd->moveBuf); if (thd->mark_buffer) free(thd->mark_buffer); + if (thd->stack_traces) free(thd->stack_traces); free(thd); } } diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 3d423096..1c375c81 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -31,6 +31,19 @@ // Size of a "page" on the heap (the second generation), in bytes. #define HEAP_SIZE 6000000 +// Number of functions to save for printing call history +#define MAX_STACK_TRACES 10 + +// GC debugging flags +#define GC_DEBUG_TRACE 0 +#define GC_DEBUG_VERBOSE 0 + +/* Additional runtime checking of the GC system. + This is here because these checks should not be + necessary if GC is working correctly. */ +#define GC_SAFETY_CHECKS 1 + + /* Define general object type. */ typedef void *object; @@ -186,15 +199,6 @@ gc_heap *gc_get_heap(); // TODO: //void gc_collector() -/* GC debugging flags */ -#define GC_DEBUG_TRACE 0 -#define GC_DEBUG_VERBOSE 0 - -/* Additional runtime checking of the GC system. - This is here because these checks should not be - necessary if GC is working correctly. */ -#define GC_SAFETY_CHECKS 1 - /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 diff --git a/runtime.c b/runtime.c index 401e96a6..32b4caf4 100644 --- a/runtime.c +++ b/runtime.c @@ -188,8 +188,6 @@ static symbol_type Cyc_void_symbol = {{0}, symbol_tag, "", nil}; const object quote_void = &Cyc_void_symbol; /* Stack Traces */ -static const int MAX_STACK_TRACES = 10; - void Cyc_st_add(void *data, char *frame) { gc_thread_data *thd = (gc_thread_data *)data; // Do not allow recursion to remove older frames @@ -2479,13 +2477,6 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { void Cyc_start_thread(gc_thread_data *thd) { - thd->stack_trace_idx = 0; - thd->stack_prev_frame = NULL; - // TODO: may need to relocate the calloc to another function that - // initializes thread objects, rather than here that just calls them. - // at a minimum, should initialize it to NULL so we can test for that here. - thd->stack_traces = calloc(MAX_STACK_TRACES, sizeof(char *)); - /* Tank, load the jump program... */ setjmp(*(thd->jmp_start)); From 74b818ec2fac84709aeaa41460ddaae37d40acaf Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 14 Dec 2015 21:58:41 -0500 Subject: [PATCH 248/339] Added an 'end thread' stub --- runtime.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime.c b/runtime.c index 32b4caf4..14bea76e 100644 --- a/runtime.c +++ b/runtime.c @@ -2494,6 +2494,12 @@ void Cyc_start_thread(gc_thread_data *thd) exit(0); } +void Cyc_end_thread(gc_thread_data *thd) { + // TODO: call pthread_exit? + // alternatively could call longjmp with a null continuation, but that seems + // more complicated than necessary +} + // Mark globals as part of the tracing collector // This is called by the collector thread void gc_mark_globals() From dfed77639ae434c50eb1b5823bdf7a6751faf576 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 15 Dec 2015 22:58:15 -0500 Subject: [PATCH 249/339] Adding thread application stubs --- gc.c | 5 +++-- include/cyclone/types.h | 2 +- scheme/base.sld | 10 ++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index e1137c01..82fa9971 100644 --- a/gc.c +++ b/gc.c @@ -70,7 +70,7 @@ void gc_initialize() } // Add data for a new mutator -void gc_add_mutator(gc_thread_data *thd) +int gc_add_mutator(gc_thread_data *thd) { // TODO: need to sync access to these static variables. both here and // elsewhere in the module!! @@ -78,12 +78,13 @@ void gc_add_mutator(gc_thread_data *thd) for (i = 0; i < Cyc_num_mutators; i++) { if (!Cyc_mutators[i]) { Cyc_mutators[i] = thd; - return; + return i; } } // TODO: unable to create any more mutators. what to do??? fprintf(stderr, "Unable to create a new thread, exiting\n"); exit(1); + return -1; } gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 1c375c81..9ba3b8da 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -159,7 +159,7 @@ void vpbuffer_free(void **buf); /* GC prototypes */ void gc_initialize(); -void gc_add_mutator(gc_thread_data *thd); +int gc_add_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); diff --git a/scheme/base.sld b/scheme/base.sld index 2f5d1b6f..a86286f1 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -1,5 +1,8 @@ (define-library (scheme base) (export + ;; Thread functions. these are not standard, and may be relocated + make-thread + ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete ;delete-duplicates @@ -95,6 +98,13 @@ quasiquote ) (begin + ;; Threading + (define (make-thread thunk . name) + (let ((name-str (if (pair? name) + (car name) + ""))) + (list 'cyc-thread-obj thunk name-str))) + ;; Features implemented by this Scheme (define (features) '(cyclone r7rs exact-closed)) From 0e8129f5e6e5fd1821337085ef0423ab1b5ffe35 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 16 Dec 2015 22:54:34 -0500 Subject: [PATCH 250/339] Added thread stubs --- scheme/base.sld | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/scheme/base.sld b/scheme/base.sld index a86286f1..85c7857a 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -1,7 +1,12 @@ (define-library (scheme base) (export ;; Thread functions. these are not standard, and may be relocated + thread? make-thread + thread-name + thread-specific + thread-specific-set! + ;thread-start! ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete @@ -99,11 +104,34 @@ ) (begin ;; Threading + (define (thread? obj) + (and (vector? obj) + (> (vector-length obj) 0) + (equal? 'cyc-thread-obj (vector-ref obj 0)))) + (define (make-thread thunk . name) - (let ((name-str (if (pair? name) - (car name) - ""))) - (list 'cyc-thread-obj thunk name-str))) +; (let ((name-str (if (pair? name) +; (car name) +; ""))) + ;; Fields supported so far: + ;; - type marker (implementation-specific) + ;; - thunk + ;; - internal thread id (implementation-specific) + ;; - name + ;; - specific + (vector 'cyc-thread-obj thunk #f name #f)) +; (vector 'cyc-thread-obj thunk #f 'name-str #f))) + + (define (thread-name t) (vector-ref t 3)) + (define (thread-specific t) (vector-ref t 4)) + (define (thread-specific-set! t obj) (vector-set! t 4 obj)) + +; TODO: +; current-thread - not sure how to look this up yet... may need a global list of running threads +; (define (thread-start! t) +; (let* ((thunk (vector-ref t 1)) +; (mutator-id (Cyc-thread-start! thunk))) +; (vector-set! t 2 mutator-id))) ;; Features implemented by this Scheme (define (features) '(cyclone r7rs exact-closed)) From 7c795f1534450ef9ee7f0295d1b0d71ed61e039a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 16 Dec 2015 23:07:14 -0500 Subject: [PATCH 251/339] Noted TODO --- scheme/base.sld | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scheme/base.sld b/scheme/base.sld index 85c7857a..27af254c 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -109,17 +109,19 @@ (> (vector-length obj) 0) (equal? 'cyc-thread-obj (vector-ref obj 0)))) +;; TODO: does not compile. I suspect the let is not getting expanded for some reason... (define (make-thread thunk . name) -; (let ((name-str (if (pair? name) -; (car name) -; ""))) + (let ((name-str (if (pair? name) + (car name) + ""))) + (vector 'cyc-thread-obj thunk #f name-str #f))) ;; Fields supported so far: ;; - type marker (implementation-specific) ;; - thunk ;; - internal thread id (implementation-specific) ;; - name ;; - specific - (vector 'cyc-thread-obj thunk #f name #f)) +; (vector 'cyc-thread-obj thunk #f name #f)) ; (vector 'cyc-thread-obj thunk #f 'name-str #f))) (define (thread-name t) (vector-ref t 3)) From d478132d8ad48ab03b1565ad53bdc0e70785321d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 16 Dec 2015 21:59:58 -0500 Subject: [PATCH 252/339] Fixed-up make-thread --- scheme/base.sld | 61 +++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/scheme/base.sld b/scheme/base.sld index 27af254c..a2834fda 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -103,38 +103,6 @@ quasiquote ) (begin - ;; Threading - (define (thread? obj) - (and (vector? obj) - (> (vector-length obj) 0) - (equal? 'cyc-thread-obj (vector-ref obj 0)))) - -;; TODO: does not compile. I suspect the let is not getting expanded for some reason... - (define (make-thread thunk . name) - (let ((name-str (if (pair? name) - (car name) - ""))) - (vector 'cyc-thread-obj thunk #f name-str #f))) - ;; Fields supported so far: - ;; - type marker (implementation-specific) - ;; - thunk - ;; - internal thread id (implementation-specific) - ;; - name - ;; - specific -; (vector 'cyc-thread-obj thunk #f name #f)) -; (vector 'cyc-thread-obj thunk #f 'name-str #f))) - - (define (thread-name t) (vector-ref t 3)) - (define (thread-specific t) (vector-ref t 4)) - (define (thread-specific-set! t obj) (vector-set! t 4 obj)) - -; TODO: -; current-thread - not sure how to look this up yet... may need a global list of running threads -; (define (thread-start! t) -; (let* ((thunk (vector-ref t 1)) -; (mutator-id (Cyc-thread-start! thunk))) -; (vector-set! t 2 mutator-id))) - ;; Features implemented by this Scheme (define (features) '(cyclone r7rs exact-closed)) @@ -686,4 +654,33 @@ (else #f)))) + ;; Threading + (define (thread? obj) + (and (vector? obj) + (> (vector-length obj) 0) + (equal? 'cyc-thread-obj (vector-ref obj 0)))) + + (define (make-thread thunk . name) + (let ((name-str (if (pair? name) + (car name) + ""))) + ;; Fields supported so far: + ;; - type marker (implementation-specific) + ;; - thunk + ;; - internal thread id (implementation-specific) + ;; - name + ;; - specific + (vector 'cyc-thread-obj thunk #f name-str #f))) + + (define (thread-name t) (vector-ref t 3)) + (define (thread-specific t) (vector-ref t 4)) + (define (thread-specific-set! t obj) (vector-set! t 4 obj)) + +; TODO: +; current-thread - not sure how to look this up yet... may need a global list of running threads +; (define (thread-start! t) +; (let* ((thunk (vector-ref t 1)) +; (mutator-id (Cyc-thread-start! thunk))) +; (vector-set! t 2 mutator-id))) + )) From 43d29e3a4cf990d67a11b7b20826f457851ddd81 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 16 Dec 2015 23:03:27 -0500 Subject: [PATCH 253/339] Added Cyc_setup_thread stub --- runtime.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/runtime.c b/runtime.c index 14bea76e..568bf50b 100644 --- a/runtime.c +++ b/runtime.c @@ -2475,6 +2475,19 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} +void Cyc_setup_thread(thunk) +{ + // TODO: how to use pthread? need to run this in a pthread, I think. when/how to do that? + // TODO: this function should be start_thread, call below one run_thread + // TODO: + gc_thread_data *thd; + // malloc thread, init it + // setup gc_cont, args + // gc_add_mutator + // Cyc_start_thread(thd) + +} + void Cyc_start_thread(gc_thread_data *thd) { /* Tank, load the jump program... */ From e57688a7742b07fb88b40a3db59e8ed54feba92e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 22:45:45 -0500 Subject: [PATCH 254/339] Added thread start/end functions to runtime --- gc.c | 1 + include/cyclone/runtime.h | 2 ++ runtime.c | 60 +++++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/gc.c b/gc.c index 82fa9971..2c0b7150 100644 --- a/gc.c +++ b/gc.c @@ -1181,6 +1181,7 @@ void *collector_main(void *arg) } nanosleep(&tim, NULL); } + return NULL; } static pthread_t collector_thread; diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 4db8d288..ade5fac2 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -186,7 +186,9 @@ object equalp(object,object); object memberp(void *,object,list); object memqp(void *,object,list); +object Cyc_spawn_thread(object thunk); void Cyc_start_thread(gc_thread_data *thd); +void Cyc_end_thread(gc_thread_data *thd); void GC(void *,closure,object*,int); void Cyc_st_add(void *data, char *frame); diff --git a/runtime.c b/runtime.c index 568bf50b..a43fa31a 100644 --- a/runtime.c +++ b/runtime.c @@ -2475,19 +2475,46 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} -void Cyc_setup_thread(thunk) +/** + * Thread initialization function only called from within the runtime + */ +void *Cyc_init_thread(object thunk) { - // TODO: how to use pthread? need to run this in a pthread, I think. when/how to do that? - // TODO: this function should be start_thread, call below one run_thread - // TODO: + long stack_start; gc_thread_data *thd; - // malloc thread, init it - // setup gc_cont, args - // gc_add_mutator - // Cyc_start_thread(thd) - +// TODO: I don't think we want a closure here, but rather want to +// init the end-thread primitive, and call into that instead. that way +// we can explicitly provide the thread_data argument. + mclosure0(clo_end, Cyc_end_thread); + thd = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(thd, 0, (char *) &stack_start, global_stack_size); + thd->gc_cont = thunk; + thd->gc_num_args = 1; + thd->gc_args[0] = &clo_end; + gc_add_mutator(thd); + Cyc_start_thread(thd); + return NULL; } +/** + * Spawn a new thread to execute the given thunk + */ +object Cyc_spawn_thread(object thunk) +{ + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&thread, NULL, Cyc_init_thread, thunk)) { + fprintf(stderr, "Error creating a new thread\n"); + exit(1); + } + return boolean_t; +} + +/** + * Start a thread's trampoline + */ void Cyc_start_thread(gc_thread_data *thd) { /* Tank, load the jump program... */ @@ -2507,10 +2534,19 @@ void Cyc_start_thread(gc_thread_data *thd) exit(0); } -void Cyc_end_thread(gc_thread_data *thd) { - // TODO: call pthread_exit? +/** + * Terminate a thread + */ +void Cyc_end_thread(gc_thread_data *thd) +{ // alternatively could call longjmp with a null continuation, but that seems - // more complicated than necessary + // more complicated than necessary. or does it... see next comment: + + // TODO: what if there are any locals from the thread's stack still being + // referenced? might want to do one more minor GC to clear the stack before + // terminating the thread + + pthread_exit(NULL); // For now, just a proof of concept } // Mark globals as part of the tracing collector From 62e4e5afe9fde1d4d7b25da95f95b5424cded93e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:19:41 -0500 Subject: [PATCH 255/339] Added thread primitives --- include/cyclone/runtime.h | 2 ++ runtime.c | 51 +++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index ade5fac2..dd7550bd 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -226,6 +226,8 @@ extern const object primitive_Cyc_91get_91cvar; extern const object primitive_Cyc_91set_91cvar_67; extern const object primitive_Cyc_91cvar_127; extern const object primitive_Cyc_91has_91cycle_127; +extern const object primitive_Cyc_91spawn_91thread_127; +extern const object primitive_Cyc_91end_91thread_127; extern const object primitive__87; extern const object primitive__91; extern const object primitive__85; diff --git a/runtime.c b/runtime.c index a43fa31a..135f98e4 100644 --- a/runtime.c +++ b/runtime.c @@ -1702,6 +1702,14 @@ void _set_91cdr_67(void *data, object cont, object args) { void _Cyc_91has_91cycle_127(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-has-cycle?", 1, args); return_closcall1(data, cont, Cyc_has_cycle(car(args))); } +void _Cyc_91spawn_91thread_127(void *data, object cont, object args) { + Cyc_check_num_args(data, "Cyc-spawn-thread!", 1, args); + // TODO: validate argument type? + return_closcall1(data, cont, Cyc_spawn_thread(car(args))); } +void _Cyc_91end_91thread_127(void *data, object cont, object args) { + Cyc_check_num_args(data, "Cyc-end-thread!", 0, args); + Cyc_end_thread((gc_thread_data *)data); + return_closcall1(data, cont, boolean_f); } void __87(void *data, object cont, object args) { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_sum, cont, cont, args); } @@ -2501,6 +2509,12 @@ void *Cyc_init_thread(object thunk) */ object Cyc_spawn_thread(object thunk) { +// TODO: if we want to return mutator number to the caller, we need +// to reserve a number here. need to figure out how we are going to +// synchronize access to GC mutator fields, and then reserve one +// here. will need to pass it, along with thunk, to Cyc_init_thread. +// Then can use a new function up there to add the mutator, since we +// already have the number. pthread_t thread; pthread_attr_t attr; pthread_attr_init(&attr); @@ -2512,8 +2526,26 @@ object Cyc_spawn_thread(object thunk) return boolean_t; } +/** + * Terminate a thread + */ +void Cyc_end_thread(gc_thread_data *thd) +{ + // alternatively could call longjmp with a null continuation, but that seems + // more complicated than necessary. or does it... see next comment: + + // TODO: what if there are any locals from the thread's stack still being + // referenced? might want to do one more minor GC to clear the stack before + // terminating the thread + + pthread_exit(NULL); // For now, just a proof of concept +} + /** * Start a thread's trampoline + +TODO: should rename this function to make it more clear what is really going on + */ void Cyc_start_thread(gc_thread_data *thd) { @@ -2534,21 +2566,6 @@ void Cyc_start_thread(gc_thread_data *thd) exit(0); } -/** - * Terminate a thread - */ -void Cyc_end_thread(gc_thread_data *thd) -{ - // alternatively could call longjmp with a null continuation, but that seems - // more complicated than necessary. or does it... see next comment: - - // TODO: what if there are any locals from the thread's stack still being - // referenced? might want to do one more minor GC to clear the stack before - // terminating the thread - - pthread_exit(NULL); // For now, just a proof of concept -} - // Mark globals as part of the tracing collector // This is called by the collector thread void gc_mark_globals() @@ -2937,6 +2954,8 @@ static primitive_type Cyc_91get_91cvar_primitive = {{0}, primitive_tag, "Cyc-get static primitive_type Cyc_91set_91cvar_67_primitive = {{0}, primitive_tag, "Cyc-set-cvar!", &_Cyc_91set_91cvar_67}; static primitive_type Cyc_91cvar_127_primitive = {{0}, primitive_tag, "Cyc-cvar?", &_Cyc_91cvar_127}; static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; +static primitive_type Cyc_91spawn_91thread_127_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_127}; +static primitive_type Cyc_91end_91thread_127_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_127}; static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; @@ -3054,6 +3073,8 @@ const object primitive_Cyc_91get_91cvar = &Cyc_91get_91cvar_primitive; const object primitive_Cyc_91set_91cvar_67 = &Cyc_91set_91cvar_67_primitive; const object primitive_Cyc_91cvar_127 = &Cyc_91cvar_127_primitive; const object primitive_Cyc_91has_91cycle_127 = &Cyc_91has_91cycle_127_primitive; +const object primitive_Cyc_91spawn_91thread_127 = &Cyc_91spawn_91thread_127_primitive; +const object primitive_Cyc_91end_91thread_127 = &Cyc_91end_91thread_127_primitive; const object primitive__87 = &_87_primitive; const object primitive__91 = &_91_primitive; const object primitive__85 = &_85_primitive; From 7d57cec8a653a247933e2904e08df616710e4ff9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:24:23 -0500 Subject: [PATCH 256/339] Pass Cyc_end_thread primitive --- runtime.c | 112 ++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 58 deletions(-) diff --git a/runtime.c b/runtime.c index 135f98e4..0a4c68e2 100644 --- a/runtime.c +++ b/runtime.c @@ -2483,64 +2483,6 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { // longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ //} -/** - * Thread initialization function only called from within the runtime - */ -void *Cyc_init_thread(object thunk) -{ - long stack_start; - gc_thread_data *thd; -// TODO: I don't think we want a closure here, but rather want to -// init the end-thread primitive, and call into that instead. that way -// we can explicitly provide the thread_data argument. - mclosure0(clo_end, Cyc_end_thread); - thd = malloc(sizeof(gc_thread_data)); - gc_thread_data_init(thd, 0, (char *) &stack_start, global_stack_size); - thd->gc_cont = thunk; - thd->gc_num_args = 1; - thd->gc_args[0] = &clo_end; - gc_add_mutator(thd); - Cyc_start_thread(thd); - return NULL; -} - -/** - * Spawn a new thread to execute the given thunk - */ -object Cyc_spawn_thread(object thunk) -{ -// TODO: if we want to return mutator number to the caller, we need -// to reserve a number here. need to figure out how we are going to -// synchronize access to GC mutator fields, and then reserve one -// here. will need to pass it, along with thunk, to Cyc_init_thread. -// Then can use a new function up there to add the mutator, since we -// already have the number. - pthread_t thread; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (pthread_create(&thread, NULL, Cyc_init_thread, thunk)) { - fprintf(stderr, "Error creating a new thread\n"); - exit(1); - } - return boolean_t; -} - -/** - * Terminate a thread - */ -void Cyc_end_thread(gc_thread_data *thd) -{ - // alternatively could call longjmp with a null continuation, but that seems - // more complicated than necessary. or does it... see next comment: - - // TODO: what if there are any locals from the thread's stack still being - // referenced? might want to do one more minor GC to clear the stack before - // terminating the thread - - pthread_exit(NULL); // For now, just a proof of concept -} - /** * Start a thread's trampoline @@ -3187,3 +3129,57 @@ const object primitive_Cyc_91write = &Cyc_91write_primitive; const object primitive_Cyc_91display = &Cyc_91display_primitive; const object primitive_call_95cc = &call_95cc_primitive; +/** + * Thread initialization function only called from within the runtime + */ +void *Cyc_init_thread(object thunk) +{ + long stack_start; + gc_thread_data *thd; + thd = malloc(sizeof(gc_thread_data)); + gc_thread_data_init(thd, 0, (char *) &stack_start, global_stack_size); + thd->gc_cont = thunk; + thd->gc_num_args = 1; + thd->gc_args[0] = &Cyc_91end_91thread_127_primitive; + gc_add_mutator(thd); + Cyc_start_thread(thd); + return NULL; +} + +/** + * Spawn a new thread to execute the given thunk + */ +object Cyc_spawn_thread(object thunk) +{ +// TODO: if we want to return mutator number to the caller, we need +// to reserve a number here. need to figure out how we are going to +// synchronize access to GC mutator fields, and then reserve one +// here. will need to pass it, along with thunk, to Cyc_init_thread. +// Then can use a new function up there to add the mutator, since we +// already have the number. + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&thread, NULL, Cyc_init_thread, thunk)) { + fprintf(stderr, "Error creating a new thread\n"); + exit(1); + } + return boolean_t; +} + +/** + * Terminate a thread + */ +void Cyc_end_thread(gc_thread_data *thd) +{ + // alternatively could call longjmp with a null continuation, but that seems + // more complicated than necessary. or does it... see next comment: + + // TODO: what if there are any locals from the thread's stack still being + // referenced? might want to do one more minor GC to clear the stack before + // terminating the thread + + pthread_exit(NULL); // For now, just a proof of concept +} + From a539027b0ffe198be97118d638714c583dc0199c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:50:11 -0500 Subject: [PATCH 257/339] Added thread primitives --- include/cyclone/runtime.h | 4 ++-- runtime.c | 14 +++++++------- scheme/cyclone/cgen.sld | 3 +++ scheme/cyclone/transforms.sld | 2 ++ scheme/eval.sld | 2 ++ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index dd7550bd..30cbe7a1 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -226,8 +226,8 @@ extern const object primitive_Cyc_91get_91cvar; extern const object primitive_Cyc_91set_91cvar_67; extern const object primitive_Cyc_91cvar_127; extern const object primitive_Cyc_91has_91cycle_127; -extern const object primitive_Cyc_91spawn_91thread_127; -extern const object primitive_Cyc_91end_91thread_127; +extern const object primitive_Cyc_91spawn_91thread_67; +extern const object primitive_Cyc_91end_91thread_67; extern const object primitive__87; extern const object primitive__91; extern const object primitive__85; diff --git a/runtime.c b/runtime.c index 0a4c68e2..21bf948d 100644 --- a/runtime.c +++ b/runtime.c @@ -1702,11 +1702,11 @@ void _set_91cdr_67(void *data, object cont, object args) { void _Cyc_91has_91cycle_127(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-has-cycle?", 1, args); return_closcall1(data, cont, Cyc_has_cycle(car(args))); } -void _Cyc_91spawn_91thread_127(void *data, object cont, object args) { +void _Cyc_91spawn_91thread_67(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-spawn-thread!", 1, args); // TODO: validate argument type? return_closcall1(data, cont, Cyc_spawn_thread(car(args))); } -void _Cyc_91end_91thread_127(void *data, object cont, object args) { +void _Cyc_91end_91thread_67(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-end-thread!", 0, args); Cyc_end_thread((gc_thread_data *)data); return_closcall1(data, cont, boolean_f); } @@ -2896,8 +2896,8 @@ static primitive_type Cyc_91get_91cvar_primitive = {{0}, primitive_tag, "Cyc-get static primitive_type Cyc_91set_91cvar_67_primitive = {{0}, primitive_tag, "Cyc-set-cvar!", &_Cyc_91set_91cvar_67}; static primitive_type Cyc_91cvar_127_primitive = {{0}, primitive_tag, "Cyc-cvar?", &_Cyc_91cvar_127}; static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; -static primitive_type Cyc_91spawn_91thread_127_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_127}; -static primitive_type Cyc_91end_91thread_127_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_127}; +static primitive_type Cyc_91spawn_91thread_67_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_67}; +static primitive_type Cyc_91end_91thread_67_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_67}; static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; @@ -3015,8 +3015,8 @@ const object primitive_Cyc_91get_91cvar = &Cyc_91get_91cvar_primitive; const object primitive_Cyc_91set_91cvar_67 = &Cyc_91set_91cvar_67_primitive; const object primitive_Cyc_91cvar_127 = &Cyc_91cvar_127_primitive; const object primitive_Cyc_91has_91cycle_127 = &Cyc_91has_91cycle_127_primitive; -const object primitive_Cyc_91spawn_91thread_127 = &Cyc_91spawn_91thread_127_primitive; -const object primitive_Cyc_91end_91thread_127 = &Cyc_91end_91thread_127_primitive; +const object primitive_Cyc_91spawn_91thread_67 = &Cyc_91spawn_91thread_67_primitive; +const object primitive_Cyc_91end_91thread_67 = &Cyc_91end_91thread_67_primitive; const object primitive__87 = &_87_primitive; const object primitive__91 = &_91_primitive; const object primitive__85 = &_85_primitive; @@ -3140,7 +3140,7 @@ void *Cyc_init_thread(object thunk) gc_thread_data_init(thd, 0, (char *) &stack_start, global_stack_size); thd->gc_cont = thunk; thd->gc_num_args = 1; - thd->gc_args[0] = &Cyc_91end_91thread_127_primitive; + thd->gc_args[0] = &Cyc_91end_91thread_67_primitive; gc_add_mutator(thd); Cyc_start_thread(thd); return NULL; diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index b6bd7f43..58abed71 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -450,6 +450,8 @@ ((eq? p 'Cyc-set-cvar!) "Cyc_set_cvar") ((eq? p 'Cyc-cvar?) "Cyc_is_cvar") ((eq? p 'Cyc-has-cycle?) "Cyc_has_cycle") + ((eq? p 'Cyc-spawn-thread!) "Cyc_spawn_thread") + ((eq? p 'Cyc-end-thread!) "Cyc_end_thread") ((eq? p 'Cyc-stdout) "Cyc_stdout") ((eq? p 'Cyc-stdin) "Cyc_stdin") ((eq? p 'Cyc-stderr) "Cyc_stderr") @@ -580,6 +582,7 @@ <= apply Cyc-default-exception-handler + Cyc-end-thread! open-input-file open-output-file close-port diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index 3a5d23df..8630f6b6 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -451,6 +451,8 @@ Cyc-set-cvar! Cyc-cvar? ;; Cyclone-specific Cyc-has-cycle? + Cyc-spawn-thread! + Cyc-end-thread! Cyc-stdout Cyc-stdin Cyc-stderr diff --git a/scheme/eval.sld b/scheme/eval.sld index 45f69be6..79197b0f 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -136,6 +136,8 @@ (list 'Cyc-set-cvar! Cyc-set-cvar!) (list 'Cyc-cvar? Cyc-cvar?) (list 'Cyc-has-cycle? Cyc-has-cycle?) + (list 'Cyc-spawn-thread! Cyc-spawn-thread!) + (list 'Cyc-end-thread! Cyc-end-thread!) (list 'Cyc-default-exception-handler Cyc-default-exception-handler) (list 'Cyc-current-exception-handler Cyc-current-exception-handler) (list '+ +) From efd00b712f4758c3fc48e0febda10d8132f4c2cf Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:56:03 -0500 Subject: [PATCH 258/339] Updated instructions for adding primitives --- docs/Developer-How-To.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/Developer-How-To.md b/docs/Developer-How-To.md index a0d34ba1..0fec3f9b 100644 --- a/docs/Developer-How-To.md +++ b/docs/Developer-How-To.md @@ -3,12 +3,15 @@ WIP set of instructions for doing this. working to refine this down: - Add function/definitions to runtime.h and runtime.c -- Add to prim? section in transforms.scm. Some functions may need to added to the next section in the file, so they are not constant-folded (IE, evaluated at compile time). -- Add to the c-compile-primitive section in cgen.scm. -- install modified .scm files +- Rebuild and install runtime library. + +- Add to prim? section in transforms.sld. Some functions may need to added to the next section in the file, so they are not constant-folded (IE, evaluated at compile time). +- Add to the c-compile-primitive section in cgen.sld. +- install modified .sld files - cyclone scheme/cyclone/cgen.sld - copy modified files to cyclone-bootstrap, including cgen.c - install cyclone-bootstrap - run 'make clean ; make && make bootstrap' from cyclone repo - run 'make clean ; ./install' from bootstrap repo +- Add primitives to the list in eval.sld From f6347de299b1f810d3e13f8dc89c9ac13ddbdc23 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:56:12 -0500 Subject: [PATCH 259/339] Do not constant fold thread functions --- scheme/cyclone/transforms.sld | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index 8630f6b6..024f320b 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -556,6 +556,8 @@ Cyc-get-cvar Cyc-set-cvar! Cyc-cvar? + Cyc-spawn-thread! + Cyc-end-thread! apply %halt exit From c773af78fbf1eaf0987e0e31c902eb2af28ca7b8 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 00:00:13 -0500 Subject: [PATCH 260/339] Revisions --- docs/Developer-How-To.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/Developer-How-To.md b/docs/Developer-How-To.md index 0fec3f9b..6ea11d5c 100644 --- a/docs/Developer-How-To.md +++ b/docs/Developer-How-To.md @@ -1,17 +1,17 @@ ## Add a primitive -WIP set of instructions for doing this. working to refine this down: - -- Add function/definitions to runtime.h and runtime.c +- Add function/definitions to `runtime.h` and `runtime.c` - Rebuild and install runtime library. +- Add to `prim?` section in `transforms.sld`. Some functions may need to added to the next section in the file, so they are not constant-folded (IE, evaluated at compile time). +- Add above the `c-compile-primitive` section in `cgen.sld`. Some functions may need to be added in multiple places to indicate they take additional arguments, call their continuation, etc. -- Add to prim? section in transforms.sld. Some functions may need to added to the next section in the file, so they are not constant-folded (IE, evaluated at compile time). -- Add to the c-compile-primitive section in cgen.sld. -- install modified .sld files -- cyclone scheme/cyclone/cgen.sld -- copy modified files to cyclone-bootstrap, including cgen.c +TODO: need to develop this section better to come up with a workable/optimal approach to building things: + +- Install modified `.sld` files -- ??? +- Compile: `cyclone scheme/cyclone/cgen.sld` +- Copy modified files to cyclone-bootstrap, including `cgen.c` - install cyclone-bootstrap -- run 'make clean ; make && make bootstrap' from cyclone repo -- run 'make clean ; ./install' from bootstrap repo +- run `make clean ; make && make bootstrap` from cyclone repo +- run `make clean ; ./install` from bootstrap repo -- Add primitives to the list in eval.sld +- Add primitives to the list in eval.sld. Rebuild one more time. From f3fac78e356c6b99dbfed6d8c520ab8371784833 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 17 Dec 2015 23:00:38 -0500 Subject: [PATCH 261/339] Added notes --- runtime.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/runtime.c b/runtime.c index 21bf948d..d695abbe 100644 --- a/runtime.c +++ b/runtime.c @@ -3157,6 +3157,19 @@ object Cyc_spawn_thread(object thunk) // here. will need to pass it, along with thunk, to Cyc_init_thread. // Then can use a new function up there to add the mutator, since we // already have the number. +/* +how to manage gc mutators. need to handle: +- need to be able to allocate a thread but not run it yet. + maybe have a run level, or status +- need to make mutators thread safe, ideally without major performance impacts +- thread terminates + - should mark mutator as 'done' + - at an opportune moment, free mutator and set it back + to null + +what is the right data structure? is the array OK? or would it be better +to look at the lock-free structures provided by ck? +*/ pthread_t thread; pthread_attr_t attr; pthread_attr_init(&attr); From 4e9bd1ea022f355217d757cdf9a5e69184321820 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 23:49:32 -0500 Subject: [PATCH 262/339] Added GC thread state, and notes --- gc-notes.txt | 3 +++ gc.c | 2 ++ include/cyclone/types.h | 9 +++++++++ runtime.c | 8 ++++++++ 4 files changed, 22 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index c36bbd08..98014d9c 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -12,6 +12,9 @@ TODO: - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc + TODO items: + - lock writes to symbol table + - need to cooperate when a mutator is blocked might be able to stop a thread and do a minor GC on it, but no longjmp until after major GC. would need to figure out how to repack gc_cont and args diff --git a/gc.c b/gc.c index 2c0b7150..cc174ee8 100644 --- a/gc.c +++ b/gc.c @@ -1220,6 +1220,8 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->stack_traces = calloc(MAX_STACK_TRACES, sizeof(char *)); thd->stack_trace_idx = 0; thd->stack_prev_frame = NULL; +// thd->thread = NULL; + thd->thread_state = CYC_THREAD_STATE_NEW; //thd->mutator_num = mut_num; thd->jmp_start = malloc(sizeof(jmp_buf)); thd->gc_args = malloc(sizeof(object) * NUM_GC_ANS); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 9ba3b8da..d88b557e 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -47,9 +47,18 @@ /* Define general object type. */ typedef void *object; +/* Threading */ +typedef enum { CYC_THREAD_STATE_NEW + , CYC_THREAD_STATE_RUNNABLE + , CYC_THREAD_STATE_TERMINATED + } cyc_thread_state_type; + /* Thread data structures */ typedef struct gc_thread_data_t gc_thread_data; struct gc_thread_data_t { +// TODO: +// pthread_t *thread; + cyc_thread_state_type thread_state; // Data needed to initiate stack-based minor GC char *stack_start; char *stack_limit; diff --git a/runtime.c b/runtime.c index d695abbe..578daba6 100644 --- a/runtime.c +++ b/runtime.c @@ -2491,6 +2491,9 @@ TODO: should rename this function to make it more clear what is really going on */ void Cyc_start_thread(gc_thread_data *thd) { +// TODO: should use an atomic set to modify this + thd->thread_state = CYC_THREAD_STATE_RUNNABLE; + /* Tank, load the jump program... */ setjmp(*(thd->jmp_start)); @@ -3141,6 +3144,9 @@ void *Cyc_init_thread(object thunk) thd->gc_cont = thunk; thd->gc_num_args = 1; thd->gc_args[0] = &Cyc_91end_91thread_67_primitive; +// thd->thread = pthread_self(); // TODO: ptr vs instance +// returns instance so would need to malloc here +// would also need to update termination code to free that memory gc_add_mutator(thd); Cyc_start_thread(thd); return NULL; @@ -3193,6 +3199,8 @@ void Cyc_end_thread(gc_thread_data *thd) // referenced? might want to do one more minor GC to clear the stack before // terminating the thread +// TODO: use ATOMIC set to modify this + thd->thread_state = CYC_THREAD_STATE_TERMINATED; pthread_exit(NULL); // For now, just a proof of concept } From c4e14302c421b3446a0f069e2b0778b3a009fcea Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 01:28:38 -0500 Subject: [PATCH 263/339] Array example --- test.c | 326 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 195 insertions(+), 131 deletions(-) diff --git a/test.c b/test.c index 01e8a8fe..e497de63 100644 --- a/test.c +++ b/test.c @@ -1,155 +1,219 @@ /* compile with ck in above directory, and using: gcc test.c -g -lck && ./a.out +gcc test.c -std=c99 -g -lck && ./a.out */ -#include -#include "../ck/src/ck_ht_hash.h" + +#include #include "include/cyclone/types.h" -static ck_hs_t hs_symbol_table; - -static void *hs_malloc(size_t r) +static void +my_free(void *p, size_t m, bool d) { - return malloc(r); + free(p); + return; } -static void hs_free(void *p, size_t b, bool r) -{ - (void)b; - (void)r; - free(p); - return; -} - -static struct ck_malloc my_allocator = { - .malloc = hs_malloc, - .free = hs_free -}; - -static unsigned long hs_hash(const void *object, unsigned long seed) -{ -// const char *c = object; -// unsigned long h; -// -// h = (unsigned long)MurmurHash64A(c, strlen(c), seed); -// return h; - const symbol_type *c = object; - unsigned long h; - - h = (unsigned long)MurmurHash64A(c->pname, strlen(c->pname), seed); - return h; -} - -static bool -hs_compare(const void *previous, const void *compare) -{ - - return strcmp((previous), (compare)) == 0; - //return strcmp(symbol_pname(previous), symbol_pname(compare)) == 0; -} static void * -set_get(ck_hs_t *hs, const void *value) +my_malloc(size_t b) { - unsigned long h; - void *v; - - h = CK_HS_HASH(hs, hs_hash, value); - v = ck_hs_get(hs, h, value); - return v; + return malloc(b); } -static bool -set_insert(ck_hs_t *hs, const void *value) +static void * +my_realloc(void *r, size_t a, size_t b, bool d) { - unsigned long h; - - h = CK_HS_HASH(hs, hs_hash, value); - return ck_hs_put(hs, h, value); -} - -char *_strdup (const char *s) { - char *d = malloc (strlen (s) + 1); - if (d) { strcpy (d,s); } - return d; -} - -object find_symbol_by_name(const char *name) { - symbol_type tmp = {{0}, symbol_tag, name, nil}; - object result = set_get(&hs_symbol_table, &tmp); - if (result) { - printf("found symbol %s\n", symbol_pname(result)); - } - return result; -} - -object add_symbol(symbol_type *psym) { - printf("Adding symbol %s\n", symbol_pname(psym)); - set_insert(&hs_symbol_table, psym); - return psym; -} - -object add_symbol_by_name(const char *name) { - symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; - symbol_type *psym = malloc(sizeof(symbol_type)); - memcpy(psym, &sym, sizeof(symbol_type)); - return add_symbol(psym); -} - -object find_or_add_symbol(const char *name){ - object sym = find_symbol_by_name(name); - if (sym){ - return sym; - } else { - return add_symbol_by_name(name); - } + return realloc(r, b); } +static struct ck_malloc m = { + .malloc = my_malloc, + .free = my_free, + .realloc = my_realloc +}; void main() { - char astr[] = "a"; - char bstr[] = "b"; - char cstr[] = "c"; - symbol_type a = {{0}, symbol_tag, astr, nil}; - symbol_type aa = {{0}, symbol_tag, astr, nil}; - symbol_type b = {{0}, symbol_tag, bstr, nil}; - symbol_type c = {{0}, symbol_tag, cstr, nil}; + ck_array_t array; + ck_array_iterator_t iterator; + gc_thread_data a, b, c; + void *pointer; + a.gc_num_args = 0; + b.gc_num_args = 1; + c.gc_num_args = 2; - if (!ck_hs_init(&hs_symbol_table, - CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, - hs_hash, hs_compare, - &my_allocator, - 1024, 43423)){ - fprintf(stderr, "Unable to initialize symbol table\n"); + if (ck_array_init(&array, CK_ARRAY_MODE_SPMC, &m, 10) == 0){ + printf("Unable to init array\n"); exit(1); } - -// set_insert(&hs_symbol_table, &a); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); -// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); -// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); -// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); -// -// set_insert(&hs_symbol_table, &b); -// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); -// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); -// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); -// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); + ck_array_put_unique(&array, (void *)&a); + ck_array_put_unique(&array, (void *)&b); + ck_array_put_unique(&array, (void *)&b); + ck_array_commit(&array); + CK_ARRAY_FOREACH(&array, &iterator, &pointer){ + printf("value = %d\n", ((gc_thread_data *)pointer)->gc_num_args); + } + printf("length = %d\n", ck_array_length(&array)); + ck_array_remove(&array, &a); + ck_array_commit(&array); - object asym = find_or_add_symbol("producer"); - printf("%p\n", asym); - - object bsym = find_or_add_symbol("b"); - printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - - object csym = find_or_add_symbol("lambda"); - printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - - object dsym = find_or_add_symbol("d"); - printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - - object aasym = find_or_add_symbol("producer"); - printf("%p\n", aasym); - printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); - return; + printf("length = %d\n", ck_array_length(&array)); + CK_ARRAY_FOREACH(&array, &iterator, &pointer){ + printf("looping, value = %d\n", ((gc_thread_data *)pointer)->gc_num_args); + ck_array_put_unique(&array, (void *)&c); + ck_array_commit(&array); + } + printf("length = %d\n", ck_array_length(&array)); + ck_array_deinit(&array, false); } +//#include +//#include "../ck/src/ck_ht_hash.h" +//#include "include/cyclone/types.h" +// +//static ck_hs_t hs_symbol_table; +// +//static void *hs_malloc(size_t r) +//{ +// return malloc(r); +//} +// +//static void hs_free(void *p, size_t b, bool r) +//{ +// (void)b; +// (void)r; +// free(p); +// return; +//} +// +//static struct ck_malloc my_allocator = { +// .malloc = hs_malloc, +// .free = hs_free +//}; +// +//static unsigned long hs_hash(const void *object, unsigned long seed) +//{ +//// const char *c = object; +//// unsigned long h; +//// +//// h = (unsigned long)MurmurHash64A(c, strlen(c), seed); +//// return h; +// const symbol_type *c = object; +// unsigned long h; +// +// h = (unsigned long)MurmurHash64A(c->pname, strlen(c->pname), seed); +// return h; +//} +// +//static bool +//hs_compare(const void *previous, const void *compare) +//{ +// +// return strcmp((previous), (compare)) == 0; +// //return strcmp(symbol_pname(previous), symbol_pname(compare)) == 0; +//} +//static void * +//set_get(ck_hs_t *hs, const void *value) +//{ +// unsigned long h; +// void *v; +// +// h = CK_HS_HASH(hs, hs_hash, value); +// v = ck_hs_get(hs, h, value); +// return v; +//} +// +//static bool +//set_insert(ck_hs_t *hs, const void *value) +//{ +// unsigned long h; +// +// h = CK_HS_HASH(hs, hs_hash, value); +// return ck_hs_put(hs, h, value); +//} +// +//char *_strdup (const char *s) { +// char *d = malloc (strlen (s) + 1); +// if (d) { strcpy (d,s); } +// return d; +//} +// +//object find_symbol_by_name(const char *name) { +// symbol_type tmp = {{0}, symbol_tag, name, nil}; +// object result = set_get(&hs_symbol_table, &tmp); +// if (result) { +// printf("found symbol %s\n", symbol_pname(result)); +// } +// return result; +//} +// +//object add_symbol(symbol_type *psym) { +// printf("Adding symbol %s\n", symbol_pname(psym)); +// set_insert(&hs_symbol_table, psym); +// return psym; +//} +// +//object add_symbol_by_name(const char *name) { +// symbol_type sym = {{0}, symbol_tag, _strdup(name), nil}; +// symbol_type *psym = malloc(sizeof(symbol_type)); +// memcpy(psym, &sym, sizeof(symbol_type)); +// return add_symbol(psym); +//} +// +//object find_or_add_symbol(const char *name){ +// object sym = find_symbol_by_name(name); +// if (sym){ +// return sym; +// } else { +// return add_symbol_by_name(name); +// } +//} +// +//void main() +//{ +// char astr[] = "a"; +// char bstr[] = "b"; +// char cstr[] = "c"; +// symbol_type a = {{0}, symbol_tag, astr, nil}; +// symbol_type aa = {{0}, symbol_tag, astr, nil}; +// symbol_type b = {{0}, symbol_tag, bstr, nil}; +// symbol_type c = {{0}, symbol_tag, cstr, nil}; +// +// if (!ck_hs_init(&hs_symbol_table, +// CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC, +// hs_hash, hs_compare, +// &my_allocator, +// 1024, 43423)){ +// fprintf(stderr, "Unable to initialize symbol table\n"); +// exit(1); +// } +// +// +//// set_insert(&hs_symbol_table, &a); +//// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +//// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); +//// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); +//// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); +//// +//// set_insert(&hs_symbol_table, &b); +//// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +//// printf("has \"a\" = %p\n", set_get(&hs_symbol_table, &aa)); +//// printf("has \"b\" = %p\n", set_get(&hs_symbol_table, &b)); +//// printf("has \"c\" = %p\n", set_get(&hs_symbol_table, &c)); +// +// object asym = find_or_add_symbol("producer"); +// printf("%p\n", asym); +// +// object bsym = find_or_add_symbol("b"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object csym = find_or_add_symbol("lambda"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object dsym = find_or_add_symbol("d"); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// +// object aasym = find_or_add_symbol("producer"); +// printf("%p\n", aasym); +// printf("hs length = %ld\n", ck_hs_count(&hs_symbol_table)); +// return; +//} From 4110c6a4e1e2e9766f63189ffbba3a7369ad5cc6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 22:05:37 -0500 Subject: [PATCH 264/339] New container for mutator threads --- Makefile | 2 +- gc.c | 84 +++++++++++++++++++++++++---------------- include/cyclone/types.h | 2 +- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 00403ef5..2651d8bc 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ libcyclone.so.1: runtime.c include/cyclone/runtime.h libcyclone.a: runtime.c include/cyclone/runtime.h include/cyclone/types.h gc.c dispatch.c $(CC) -g -c -Iinclude dispatch.c -o dispatch.o - $(CC) -g -c -Iinclude gc.c -o gc.o + $(CC) -g -std=gnu99 -c -Iinclude gc.c -o gc.o $(CC) -g -c -Iinclude -DCYC_INSTALL_DIR=\"$(PREFIX)\" -DCYC_INSTALL_LIB=\"$(LIBDIR)\" -DCYC_INSTALL_INC=\"$(INCDIR)\" -DCYC_INSTALL_SLD=\"$(DATADIR)\" runtime.c -o runtime.o $(AR) rcs libcyclone.a runtime.o gc.o dispatch.o # Instructions from: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html diff --git a/gc.c b/gc.c index cc174ee8..be4bc20d 100644 --- a/gc.c +++ b/gc.c @@ -10,7 +10,9 @@ * The heap implementation (alloc / sweep, etc) is based on code from Chibi Scheme. */ +#include #include "cyclone/types.h" +#include //////////////////// // Global variables @@ -42,8 +44,30 @@ static int cached_heap_free_size = 0; static int cached_heap_total_size = 0; // Data for each individual mutator thread -static gc_thread_data **Cyc_mutators; -static int Cyc_num_mutators; +ck_array_t Cyc_mutators; +static pthread_mutex_t mutators_lock; + +static void my_free(void *p, size_t m, bool d) +{ + free(p); + return; +} + +static void *my_malloc(size_t b) +{ + return malloc(b); +} + +static void *my_realloc(void *r, size_t a, size_t b, bool d) +{ + return realloc(r, b); +} + +static struct ck_malloc my_allocator = { + .malloc = my_malloc, + .free = my_free, + .realloc = my_realloc +}; ///////////// // Functions @@ -51,12 +75,10 @@ static int Cyc_num_mutators; // Perform one-time initialization before mutators can be executed void gc_initialize() { - // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? - // Will need this list for later use, but only by the collector thread. so it would be - // nice if there was a way to allocate mutators that avoids expensive synchronization... - // need to think on this when adding thread support, after upgrading the collector - Cyc_num_mutators = 1; - Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); + if (ck_array_init(&Cyc_mutators, CK_ARRAY_MODE_SPMC, &my_allocator, 10) == 0){ + fprintf(stderr, "Unable to initialize mutator array\n"); + exit(1); + } // Initialize collector's mark stack mark_stack_len = 128; @@ -67,24 +89,22 @@ void gc_initialize() fprintf(stderr, "Unable to initialize heap_lock mutex\n"); exit(1); } + if (pthread_mutex_init(&(mutators_lock), NULL) != 0) { + fprintf(stderr, "Unable to initialize mutators_lock mutex\n"); + exit(1); + } } // Add data for a new mutator -int gc_add_mutator(gc_thread_data *thd) +void gc_add_mutator(gc_thread_data *thd) { - // TODO: need to sync access to these static variables. both here and - // elsewhere in the module!! - int i; - for (i = 0; i < Cyc_num_mutators; i++) { - if (!Cyc_mutators[i]) { - Cyc_mutators[i] = thd; - return i; - } + pthread_mutex_lock(&mutators_lock); + if (ck_array_put_unique(&Cyc_mutators, (void *)thd) < 0) { + fprintf(stderr, "Unable to allocate memory for a new thread, exiting\n"); + exit(1); } - // TODO: unable to create any more mutators. what to do??? - fprintf(stderr, "Unable to create a new thread, exiting\n"); - exit(1); - return -1; + ck_array_commit(&Cyc_mutators); + pthread_mutex_unlock(&mutators_lock); } gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) @@ -100,7 +120,7 @@ gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) cached_heap_free_size += size; h->chunk_size = chunk_size; h->max_size = max_size; - h->data = (char *) gc_heap_align(sizeof(h->data) + (uint)&(h->data)); + h->data = (char *) gc_heap_align(sizeof(h->data) + (unsigned int)&(h->data)); h->next = NULL; free = h->free_list = (gc_free_list *)h->data; next = (gc_free_list *)(((char *) free) + gc_heap_align(gc_free_chunk_size)); @@ -898,15 +918,13 @@ void gc_mark_gray2(gc_thread_data *thd, object obj) void gc_collector_trace() { + ck_array_iterator_t iterator; gc_thread_data *m; - int clean = 0, i; + int clean = 0; while (!clean) { clean = 1; - // TODO: need to sync access to mutator int/void data, UNLESS - // the collector thread is the only one that is using these - // fields. - for (i = 0; i < Cyc_num_mutators; i++) { - m = Cyc_mutators[i]; + + CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m){ // TODO: ideally, want to use a lock-free data structure to prevent // having to use a mutex here. see corresponding code in gc_mark_gray @@ -1066,17 +1084,17 @@ void gc_post_handshake(gc_status_type s) void gc_wait_handshake() { - int i, statusm, statusc; + ck_array_iterator_t iterator; + gc_thread_data *m; + int statusm, statusc; struct timespec tim; tim.tv_sec = 0; tim.tv_nsec = 1000000; // 1 millisecond - // TODO: same as in other places, need to either sync access to - // mutator vars, or ensure only the collector uses them - for (i = 0; i < Cyc_num_mutators; i++) { + CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) { while (1) { statusc = ATOMIC_GET(&gc_status_col); - statusm = ATOMIC_GET(&(Cyc_mutators[i]->gc_status)); + statusm = ATOMIC_GET(&(m->gc_status)); if (statusc == statusm) { // Handshake succeeded, check next mutator break; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index d88b557e..26e05d82 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -168,7 +168,7 @@ void vpbuffer_free(void **buf); /* GC prototypes */ void gc_initialize(); -int gc_add_mutator(gc_thread_data *thd); +void gc_add_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); From e4d21335cf84e0de61f1f7aa2ebc0cc26757f10d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 22:37:48 -0500 Subject: [PATCH 265/339] Added thread-start! --- scheme/base.sld | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/scheme/base.sld b/scheme/base.sld index a2834fda..840debbd 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -6,7 +6,7 @@ thread-name thread-specific thread-specific-set! - ;thread-start! + thread-start! ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete @@ -675,12 +675,10 @@ (define (thread-name t) (vector-ref t 3)) (define (thread-specific t) (vector-ref t 4)) (define (thread-specific-set! t obj) (vector-set! t 4 obj)) - ; TODO: ; current-thread - not sure how to look this up yet... may need a global list of running threads -; (define (thread-start! t) -; (let* ((thunk (vector-ref t 1)) -; (mutator-id (Cyc-thread-start! thunk))) -; (vector-set! t 2 mutator-id))) - + (define (thread-start! t) + (let* ((thunk (vector-ref t 1)) + (mutator-id (Cyc-spawn-thread! thunk))) + (vector-set! t 2 mutator-id))) )) From 9d0130bd25964a7b54b4c10168ca351fea1a8873 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 23:07:15 -0500 Subject: [PATCH 266/339] Remove unnecessary check --- runtime.c | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime.c b/runtime.c index 578daba6..a908eecb 100644 --- a/runtime.c +++ b/runtime.c @@ -1707,7 +1707,6 @@ void _Cyc_91spawn_91thread_67(void *data, object cont, object args) { // TODO: validate argument type? return_closcall1(data, cont, Cyc_spawn_thread(car(args))); } void _Cyc_91end_91thread_67(void *data, object cont, object args) { - Cyc_check_num_args(data, "Cyc-end-thread!", 0, args); Cyc_end_thread((gc_thread_data *)data); return_closcall1(data, cont, boolean_f); } void __87(void *data, object cont, object args) { From 621fd0abd05b0c48a742a231e0f8f188f1dea0f4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 23:09:50 -0500 Subject: [PATCH 267/339] Basic thread example with a busy-wait --- test.scm | 67 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/test.scm b/test.scm index d668b741..1dcb3314 100644 --- a/test.scm +++ b/test.scm @@ -1,33 +1,44 @@ -;; A temporary file to attempt to repro crashing / data corruption -(import (scheme base) (scheme write)) +(import (scheme base) + (scheme write)) -(define lambdas (list)) - -;; TODO: fill lambdas list - -(letrec - ((init (lambda (n) - (cond - ((equal? n 0) #f) - (else - (set! lambdas (cons '(9 ("test")) lambdas)) - (init (- n 1)))))) - (main (lambda () - (for-each - (lambda (l) - (write (list - "static void __lambda_" - (number->string (car l)) "(void *data, int argc, " - (cdadr l) - ") ;"))) - lambdas))) - (loop (lambda () - (main) - (loop))) - ) - (init 1000) - (loop) +;; Spawn off a thread +(let ((t (thread-start! (make-thread (lambda () (write 'a)))))) + ;; Busy wait + (letrec ((foo (lambda () (bar))) + (bar (lambda () (foo)))) + (foo)) ) + +;;;; A temporary file to attempt to repro crashing / data corruption +;;(import (scheme base) (scheme write)) +;; +;;(define lambdas (list)) +;; +;;;; TODO: fill lambdas list +;; +;;(letrec +;; ((init (lambda (n) +;; (cond +;; ((equal? n 0) #f) +;; (else +;; (set! lambdas (cons '(9 ("test")) lambdas)) +;; (init (- n 1)))))) +;; (main (lambda () +;; (for-each +;; (lambda (l) +;; (write (list +;; "static void __lambda_" +;; (number->string (car l)) "(void *data, int argc, " +;; (cdadr l) +;; ") ;"))) +;; lambdas))) +;; (loop (lambda () +;; (main) +;; (loop))) +;; ) +;; (init 1000) +;; (loop) +;;) ; TODO: a long list like this seems to cause trouble. but revisit later, after GC is stabilized ;(define lambdas ; '( From 38c1ca7b31fdffc6ab9fc33dfc1f9d13b6bb5ad6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 18 Dec 2015 23:53:24 -0500 Subject: [PATCH 268/339] Added thread_sleep --- gc.c | 2 -- include/cyclone/runtime.h | 2 ++ include/cyclone/types.h | 2 ++ runtime.c | 16 ++++++++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/gc.c b/gc.c index be4bc20d..04eb126a 100644 --- a/gc.c +++ b/gc.c @@ -17,8 +17,6 @@ //////////////////// // Global variables -static const int NANOSECONDS_PER_MILLISECOND = 1000000; - // Note: will need to use atomics and/or locking to access any // variables shared between threads static int gc_color_mark = 1; // Black, is swapped during GC diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 30cbe7a1..7a2aa7a4 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -189,6 +189,7 @@ object memqp(void *,object,list); object Cyc_spawn_thread(object thunk); void Cyc_start_thread(gc_thread_data *thd); void Cyc_end_thread(gc_thread_data *thd); +object Cyc_thread_sleep(void *data, object timeout); void GC(void *,closure,object*,int); void Cyc_st_add(void *data, char *frame); @@ -228,6 +229,7 @@ extern const object primitive_Cyc_91cvar_127; extern const object primitive_Cyc_91has_91cycle_127; extern const object primitive_Cyc_91spawn_91thread_67; extern const object primitive_Cyc_91end_91thread_67; +extern const object primitive_Cyc_91thread_91sleep_67; extern const object primitive__87; extern const object primitive__91; extern const object primitive__85; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 26e05d82..7d3b7006 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -43,6 +43,8 @@ necessary if GC is working correctly. */ #define GC_SAFETY_CHECKS 1 +// General constants +#define NANOSECONDS_PER_MILLISECOND 1000000 /* Define general object type. */ typedef void *object; diff --git a/runtime.c b/runtime.c index a908eecb..77a4132d 100644 --- a/runtime.c +++ b/runtime.c @@ -1709,6 +1709,9 @@ void _Cyc_91spawn_91thread_67(void *data, object cont, object args) { void _Cyc_91end_91thread_67(void *data, object cont, object args) { Cyc_end_thread((gc_thread_data *)data); return_closcall1(data, cont, boolean_f); } +void _Cyc_91thread_91sleep_67(void *data, object cont, object args) { + Cyc_check_num_args(data, "Cyc-thread-sleep!", 1, args); + return_closcall1(data, cont, Cyc_thread_sleep(data, car(args))); } void __87(void *data, object cont, object args) { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_sum, cont, cont, args); } @@ -2900,6 +2903,7 @@ static primitive_type Cyc_91cvar_127_primitive = {{0}, primitive_tag, "Cyc-cvar? static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; static primitive_type Cyc_91spawn_91thread_67_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_67}; static primitive_type Cyc_91end_91thread_67_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_67}; +static primitive_type Cyc_91thread_91sleep_67_primitive = {{0}, primitive_tag, "Cyc-thread-sleep!", &_Cyc_91thread_91sleep_67}; static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; @@ -3019,6 +3023,7 @@ const object primitive_Cyc_91cvar_127 = &Cyc_91cvar_127_primitive; const object primitive_Cyc_91has_91cycle_127 = &Cyc_91has_91cycle_127_primitive; const object primitive_Cyc_91spawn_91thread_67 = &Cyc_91spawn_91thread_67_primitive; const object primitive_Cyc_91end_91thread_67 = &Cyc_91end_91thread_67_primitive; +const object primitive_Cyc_91thread_91sleep_67 = &Cyc_91thread_91sleep_67_primitive; const object primitive__87 = &_87_primitive; const object primitive__91 = &_91_primitive; const object primitive__85 = &_85_primitive; @@ -3203,3 +3208,14 @@ void Cyc_end_thread(gc_thread_data *thd) pthread_exit(NULL); // For now, just a proof of concept } +// For now, accept a number of milliseconds to sleep +object Cyc_thread_sleep(void *data, object timeout) +{ + struct timespec tim; + Cyc_check_num(data, timeout); + tim.tv_sec = 0; + tim.tv_nsec = ((integer_type *)timeout)->value * NANOSECONDS_PER_MILLISECOND; + nanosleep(&tim, NULL); + return boolean_t; +} + From 8895bee4eda3d702ac0f365b7716d1d1a871385b Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 00:08:36 -0500 Subject: [PATCH 269/339] Adding sleep function --- docs/Developer-How-To.md | 11 +++++------ scheme/cyclone/cgen.sld | 2 ++ scheme/cyclone/transforms.sld | 2 ++ scheme/eval.sld | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/Developer-How-To.md b/docs/Developer-How-To.md index 6ea11d5c..9a7514e9 100644 --- a/docs/Developer-How-To.md +++ b/docs/Developer-How-To.md @@ -7,11 +7,10 @@ TODO: need to develop this section better to come up with a workable/optimal approach to building things: -- Install modified `.sld` files -- ??? -- Compile: `cyclone scheme/cyclone/cgen.sld` -- Copy modified files to cyclone-bootstrap, including `cgen.c` -- install cyclone-bootstrap -- run `make clean ; make && make bootstrap` from cyclone repo -- run `make clean ; ./install` from bootstrap repo +- Compile: + cyclone scheme/cyclone/cgen.sld + cyclone scheme/cyclone/transforms.sld +- Copy modified files to cyclone-bootstrap, including runtime, `.sld`, and compiled `.c` files. +- Run `make clean ; ./install` from bootstrap repo - Add primitives to the list in eval.sld. Rebuild one more time. diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 58abed71..a2e2e58e 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -452,6 +452,7 @@ ((eq? p 'Cyc-has-cycle?) "Cyc_has_cycle") ((eq? p 'Cyc-spawn-thread!) "Cyc_spawn_thread") ((eq? p 'Cyc-end-thread!) "Cyc_end_thread") + ((eq? p 'Cyc-thread-sleep!) "Cyc_thread_sleep") ((eq? p 'Cyc-stdout) "Cyc_stdout") ((eq? p 'Cyc-stdin) "Cyc_stdin") ((eq? p 'Cyc-stderr) "Cyc_stderr") @@ -583,6 +584,7 @@ apply Cyc-default-exception-handler Cyc-end-thread! + Cyc-thread-sleep! open-input-file open-output-file close-port diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index 024f320b..9d115abb 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -453,6 +453,7 @@ Cyc-has-cycle? Cyc-spawn-thread! Cyc-end-thread! + Cyc-thread-sleep! Cyc-stdout Cyc-stdin Cyc-stderr @@ -558,6 +559,7 @@ Cyc-cvar? Cyc-spawn-thread! Cyc-end-thread! + Cyc-thread-sleep! apply %halt exit diff --git a/scheme/eval.sld b/scheme/eval.sld index 79197b0f..1cabf452 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -138,6 +138,7 @@ (list 'Cyc-has-cycle? Cyc-has-cycle?) (list 'Cyc-spawn-thread! Cyc-spawn-thread!) (list 'Cyc-end-thread! Cyc-end-thread!) + (list 'Cyc-thread-sleep! Cyc-thread-sleep!) (list 'Cyc-default-exception-handler Cyc-default-exception-handler) (list 'Cyc-current-exception-handler Cyc-current-exception-handler) (list '+ +) From d9656fc793c5203c9487dae8ef6f962accb4e942 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 00:22:49 -0500 Subject: [PATCH 270/339] Use the name `thread-sleep!` --- include/cyclone/runtime.h | 2 +- runtime.c | 9 +++++---- scheme/cyclone/cgen.sld | 4 ++-- scheme/cyclone/transforms.sld | 4 ++-- scheme/eval.sld | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 7a2aa7a4..91e3927d 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -229,7 +229,7 @@ extern const object primitive_Cyc_91cvar_127; extern const object primitive_Cyc_91has_91cycle_127; extern const object primitive_Cyc_91spawn_91thread_67; extern const object primitive_Cyc_91end_91thread_67; -extern const object primitive_Cyc_91thread_91sleep_67; +extern const object primitive_thread_91sleep_67; extern const object primitive__87; extern const object primitive__91; extern const object primitive__85; diff --git a/runtime.c b/runtime.c index 77a4132d..0606400a 100644 --- a/runtime.c +++ b/runtime.c @@ -1709,8 +1709,8 @@ void _Cyc_91spawn_91thread_67(void *data, object cont, object args) { void _Cyc_91end_91thread_67(void *data, object cont, object args) { Cyc_end_thread((gc_thread_data *)data); return_closcall1(data, cont, boolean_f); } -void _Cyc_91thread_91sleep_67(void *data, object cont, object args) { - Cyc_check_num_args(data, "Cyc-thread-sleep!", 1, args); +void _thread_91sleep_67(void *data, object cont, object args) { + Cyc_check_num_args(data, "thread-sleep!", 1, args); return_closcall1(data, cont, Cyc_thread_sleep(data, car(args))); } void __87(void *data, object cont, object args) { integer_type argc = Cyc_length(data, args); @@ -2903,7 +2903,7 @@ static primitive_type Cyc_91cvar_127_primitive = {{0}, primitive_tag, "Cyc-cvar? static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cyc-has-cycle?", &_Cyc_91has_91cycle_127}; static primitive_type Cyc_91spawn_91thread_67_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_67}; static primitive_type Cyc_91end_91thread_67_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_67}; -static primitive_type Cyc_91thread_91sleep_67_primitive = {{0}, primitive_tag, "Cyc-thread-sleep!", &_Cyc_91thread_91sleep_67}; +static primitive_type thread_91sleep_67_primitive = {{0}, primitive_tag, "thread-sleep!", &_thread_91sleep_67}; static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; @@ -3023,7 +3023,7 @@ const object primitive_Cyc_91cvar_127 = &Cyc_91cvar_127_primitive; const object primitive_Cyc_91has_91cycle_127 = &Cyc_91has_91cycle_127_primitive; const object primitive_Cyc_91spawn_91thread_67 = &Cyc_91spawn_91thread_67_primitive; const object primitive_Cyc_91end_91thread_67 = &Cyc_91end_91thread_67_primitive; -const object primitive_Cyc_91thread_91sleep_67 = &Cyc_91thread_91sleep_67_primitive; +const object primitive_thread_91sleep_67 = &thread_91sleep_67_primitive; const object primitive__87 = &_87_primitive; const object primitive__91 = &_91_primitive; const object primitive__85 = &_85_primitive; @@ -3211,6 +3211,7 @@ void Cyc_end_thread(gc_thread_data *thd) // For now, accept a number of milliseconds to sleep object Cyc_thread_sleep(void *data, object timeout) { + // TODO: looks like there are overflow issues here: struct timespec tim; Cyc_check_num(data, timeout); tim.tv_sec = 0; diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index a2e2e58e..f6cdc891 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -452,7 +452,7 @@ ((eq? p 'Cyc-has-cycle?) "Cyc_has_cycle") ((eq? p 'Cyc-spawn-thread!) "Cyc_spawn_thread") ((eq? p 'Cyc-end-thread!) "Cyc_end_thread") - ((eq? p 'Cyc-thread-sleep!) "Cyc_thread_sleep") + ((eq? p 'thread-sleep!) "Cyc_thread_sleep") ((eq? p 'Cyc-stdout) "Cyc_stdout") ((eq? p 'Cyc-stdin) "Cyc_stdin") ((eq? p 'Cyc-stderr) "Cyc_stderr") @@ -584,7 +584,7 @@ apply Cyc-default-exception-handler Cyc-end-thread! - Cyc-thread-sleep! + thread-sleep! open-input-file open-output-file close-port diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index 9d115abb..290630e3 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -453,7 +453,7 @@ Cyc-has-cycle? Cyc-spawn-thread! Cyc-end-thread! - Cyc-thread-sleep! + thread-sleep! Cyc-stdout Cyc-stdin Cyc-stderr @@ -559,7 +559,7 @@ Cyc-cvar? Cyc-spawn-thread! Cyc-end-thread! - Cyc-thread-sleep! + thread-sleep! apply %halt exit diff --git a/scheme/eval.sld b/scheme/eval.sld index 1cabf452..2171b490 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -138,7 +138,7 @@ (list 'Cyc-has-cycle? Cyc-has-cycle?) (list 'Cyc-spawn-thread! Cyc-spawn-thread!) (list 'Cyc-end-thread! Cyc-end-thread!) - (list 'Cyc-thread-sleep! Cyc-thread-sleep!) + (list 'thread-sleep! thread-sleep!) (list 'Cyc-default-exception-handler Cyc-default-exception-handler) (list 'Cyc-current-exception-handler Cyc-current-exception-handler) (list '+ +) From 5e4ab77f33a8c40047c734e19fa5cfab30057d6f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 23:25:27 -0500 Subject: [PATCH 271/339] Fix overflow issues with thread-sleep! --- runtime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runtime.c b/runtime.c index 0606400a..57e9aa96 100644 --- a/runtime.c +++ b/runtime.c @@ -3211,11 +3211,12 @@ void Cyc_end_thread(gc_thread_data *thd) // For now, accept a number of milliseconds to sleep object Cyc_thread_sleep(void *data, object timeout) { - // TODO: looks like there are overflow issues here: struct timespec tim; + long value; Cyc_check_num(data, timeout); - tim.tv_sec = 0; - tim.tv_nsec = ((integer_type *)timeout)->value * NANOSECONDS_PER_MILLISECOND; + value = ((integer_type *)timeout)->value; + tim.tv_sec = value / 1000; + tim.tv_nsec = (value % 1000) * NANOSECONDS_PER_MILLISECOND; nanosleep(&tim, NULL); return boolean_t; } From 72e3a2e91bac50b60c4faf2030136f21d4f13ceb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 23:44:39 -0500 Subject: [PATCH 272/339] Added thread-yield --- scheme/base.sld | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scheme/base.sld b/scheme/base.sld index 840debbd..c368ec58 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -1,12 +1,14 @@ (define-library (scheme base) (export ;; Thread functions. these are not standard, and may be relocated + ;; TODO: relocate to (scheme srfi 18) or such thread? make-thread thread-name thread-specific thread-specific-set! thread-start! + thread-yield! ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete @@ -681,4 +683,7 @@ (let* ((thunk (vector-ref t 1)) (mutator-id (Cyc-spawn-thread! thunk))) (vector-set! t 2 mutator-id))) + (define (thread-yield!) (thread-sleep! 1)) + ;; TODO: thread-terminate! + ;; TODO: thread-join! )) From 00210623d75fc73c01bf73be1f85dfaa8158bf2d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 19 Dec 2015 23:59:52 -0500 Subject: [PATCH 273/339] Added thread-terminate --- scheme/base.sld | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scheme/base.sld b/scheme/base.sld index c368ec58..4530c4c5 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -9,6 +9,7 @@ thread-specific-set! thread-start! thread-yield! + thread-terminate! ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete @@ -684,6 +685,6 @@ (mutator-id (Cyc-spawn-thread! thunk))) (vector-set! t 2 mutator-id))) (define (thread-yield!) (thread-sleep! 1)) - ;; TODO: thread-terminate! + (define (thread-terminate!) (Cyc-end-thread!)) ;; TODO: thread-join! )) From aad3cebd7a4ea041d479d7c14675bb10350044a5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 20 Dec 2015 00:31:50 -0500 Subject: [PATCH 274/339] Allow module to compile --- scheme/base.sld | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scheme/base.sld b/scheme/base.sld index 4530c4c5..e3e06797 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -9,7 +9,7 @@ thread-specific-set! thread-start! thread-yield! - thread-terminate! +; thread-terminate! ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete @@ -685,6 +685,6 @@ (mutator-id (Cyc-spawn-thread! thunk))) (vector-set! t 2 mutator-id))) (define (thread-yield!) (thread-sleep! 1)) - (define (thread-terminate!) (Cyc-end-thread!)) +; (define (thread-terminate!) (Cyc-end-thread!)) ;; TODO: thread-join! )) From 6463b2bf06c588d89e977e6383e377d2c3cf94c7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 20 Dec 2015 21:59:40 -0500 Subject: [PATCH 275/339] Trigger GC prior to thread exit --- include/cyclone/runtime.h | 1 + runtime.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 91e3927d..088e2024 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -189,6 +189,7 @@ object memqp(void *,object,list); object Cyc_spawn_thread(object thunk); void Cyc_start_thread(gc_thread_data *thd); void Cyc_end_thread(gc_thread_data *thd); +void Cyc_exit_thread(gc_thread_data *thd); object Cyc_thread_sleep(void *data, object timeout); void GC(void *,closure,object*,int); diff --git a/runtime.c b/runtime.c index 57e9aa96..160f8680 100644 --- a/runtime.c +++ b/runtime.c @@ -3152,6 +3152,7 @@ void *Cyc_init_thread(object thunk) // returns instance so would need to malloc here // would also need to update termination code to free that memory gc_add_mutator(thd); + ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE); Cyc_start_thread(thd); return NULL; } @@ -3195,6 +3196,12 @@ to look at the lock-free structures provided by ck? * Terminate a thread */ void Cyc_end_thread(gc_thread_data *thd) +{ + mclosure0(clo, Cyc_exit_thread); + GC(thd, &clo, thd->gc_args, 0); +} + +void Cyc_exit_thread(gc_thread_data *thd) { // alternatively could call longjmp with a null continuation, but that seems // more complicated than necessary. or does it... see next comment: @@ -3203,8 +3210,8 @@ void Cyc_end_thread(gc_thread_data *thd) // referenced? might want to do one more minor GC to clear the stack before // terminating the thread -// TODO: use ATOMIC set to modify this - thd->thread_state = CYC_THREAD_STATE_TERMINATED; +printf("DEBUG - exiting thread\n"); + ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); pthread_exit(NULL); // For now, just a proof of concept } From a5fefda485fb200ea4b8be72318c283547cae1fc Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 20 Dec 2015 22:48:22 -0500 Subject: [PATCH 276/339] WIP - thread cleanup --- gc.c | 19 ++++++++++++++++++- include/cyclone/types.h | 1 + runtime.c | 8 +++++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/gc.c b/gc.c index 04eb126a..34d27d03 100644 --- a/gc.c +++ b/gc.c @@ -105,6 +105,17 @@ void gc_add_mutator(gc_thread_data *thd) pthread_mutex_unlock(&mutators_lock); } +void gc_remove_mutator(gc_thread_data *thd) +{ + pthread_mutex_lock(&mutators_lock); + if (!ck_array_remove(&Cyc_mutators, (void *)thd)) { + fprintf(stderr, "Unable to remove thread data, exiting\n"); + exit(1); + } + ck_array_commit(&Cyc_mutators); + pthread_mutex_unlock(&mutators_lock); +} + gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) { gc_free_list *free, *next; @@ -1084,7 +1095,7 @@ void gc_wait_handshake() { ck_array_iterator_t iterator; gc_thread_data *m; - int statusm, statusc; + int statusm, statusc, thread_status; struct timespec tim; tim.tv_sec = 0; tim.tv_nsec = 1000000; // 1 millisecond @@ -1093,11 +1104,17 @@ void gc_wait_handshake() while (1) { statusc = ATOMIC_GET(&gc_status_col); statusm = ATOMIC_GET(&(m->gc_status)); + thread_status = ATOMIC_GET(&(m->thread_state)); if (statusc == statusm) { // Handshake succeeded, check next mutator break; } + if (thread_status == CYC_THREAD_STATE_TERMINATED) { + // Thread is no longer running + break; + } + // At least for now, just give up quantum and come back to // this quickly to test again. This probably could be more // efficient. diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 7d3b7006..b2c23252 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -171,6 +171,7 @@ void vpbuffer_free(void **buf); /* GC prototypes */ void gc_initialize(); void gc_add_mutator(gc_thread_data *thd); +void gc_remove_mutator(gc_thread_data *thd); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); diff --git a/runtime.c b/runtime.c index 160f8680..3d8911a6 100644 --- a/runtime.c +++ b/runtime.c @@ -2493,9 +2493,6 @@ TODO: should rename this function to make it more clear what is really going on */ void Cyc_start_thread(gc_thread_data *thd) { -// TODO: should use an atomic set to modify this - thd->thread_state = CYC_THREAD_STATE_RUNNABLE; - /* Tank, load the jump program... */ setjmp(*(thd->jmp_start)); @@ -3211,7 +3208,12 @@ void Cyc_exit_thread(gc_thread_data *thd) // terminating the thread printf("DEBUG - exiting thread\n"); +// TODO: race condition, cannot free thread data if the collector is using it + gc_remove_mutator(thd); ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); +// TODO: could maintain a dedicated list of old thread data to clean up... +// collector could do it at a time that is safe +// gc_thread_data_free(thd); pthread_exit(NULL); // For now, just a proof of concept } From ac9b197803cce4dfc5c5fa7e6fe984dd06189e13 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 21 Dec 2015 21:34:35 -0500 Subject: [PATCH 277/339] Remove dead code --- runtime.c | 399 ------------------------------------------------------ 1 file changed, 399 deletions(-) diff --git a/runtime.c b/runtime.c index 3d8911a6..1086258c 100644 --- a/runtime.c +++ b/runtime.c @@ -2086,405 +2086,6 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { apply(data, cont, prim, (object)&args[0]); } -///** -// * Copy an object to the GC heap -// */ -//char *transport(x, gcgen) char *x; int gcgen; -//{ -// if (nullp(x)) return x; -// if (obj_is_char(x)) return x; -//#if DEBUG_GC -// printf("entered transport "); -// printf("transport %ld\n", type_of(x)); -//#endif -// switch (type_of(x)) -// {case cons_tag: -// {register list nx = (list) allocp; -// type_of(nx) = cons_tag; car(nx) = car(x); cdr(nx) = cdr(x); -// forward(x) = nx; type_of(x) = forward_tag; -// allocp = ((char *) nx)+sizeof(cons_type); -// return (char *) nx;} -// case macro_tag: -// {register macro nx = (macro) allocp; -// type_of(nx) = macro_tag; nx->fn = ((macro) x)->fn; -// nx->num_args = ((macro) x)->num_args; -// forward(x) = nx; type_of(x) = forward_tag; -// allocp = ((char *) nx)+sizeof(macro_type); -// return (char *) nx;} -// case closure0_tag: -// {register closure0 nx = (closure0) allocp; -// type_of(nx) = closure0_tag; nx->fn = ((closure0) x)->fn; -// nx->num_args = ((closure0) x)->num_args; -// forward(x) = nx; type_of(x) = forward_tag; -// allocp = ((char *) nx)+sizeof(closure0_type); -// return (char *) nx;} -// case closure1_tag: -// {register closure1 nx = (closure1) allocp; -// type_of(nx) = closure1_tag; nx->fn = ((closure1) x)->fn; -// nx->num_args = ((closure1) x)->num_args; -// nx->elt1 = ((closure1) x)->elt1; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure1_type); -// return (char *) nx;} -// case closure2_tag: -// {register closure2 nx = (closure2) allocp; -// type_of(nx) = closure2_tag; nx->fn = ((closure2) x)->fn; -// nx->num_args = ((closure2) x)->num_args; -// nx->elt1 = ((closure2) x)->elt1; -// nx->elt2 = ((closure2) x)->elt2; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure2_type); -// return (char *) nx;} -// case closure3_tag: -// {register closure3 nx = (closure3) allocp; -// type_of(nx) = closure3_tag; nx->fn = ((closure3) x)->fn; -// nx->num_args = ((closure3) x)->num_args; -// nx->elt1 = ((closure3) x)->elt1; -// nx->elt2 = ((closure3) x)->elt2; -// nx->elt3 = ((closure3) x)->elt3; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure3_type); -// return (char *) nx;} -// case closure4_tag: -// {register closure4 nx = (closure4) allocp; -// type_of(nx) = closure4_tag; nx->fn = ((closure4) x)->fn; -// nx->num_args = ((closure4) x)->num_args; -// nx->elt1 = ((closure4) x)->elt1; -// nx->elt2 = ((closure4) x)->elt2; -// nx->elt3 = ((closure4) x)->elt3; -// nx->elt4 = ((closure4) x)->elt4; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(closure4_type); -// return (char *) nx;} -// case closureN_tag: -// {register closureN nx = (closureN) allocp; -// int i; -// type_of(nx) = closureN_tag; nx->fn = ((closureN) x)->fn; -// nx->num_args = ((closureN) x)->num_args; -// nx->num_elt = ((closureN) x)->num_elt; -// nx->elts = (object *)(((char *)nx) + sizeof(closureN_type)); -// for (i = 0; i < nx->num_elt; i++) { -// nx->elts[i] = ((closureN) x)->elts[i]; -// } -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(closureN_type) + sizeof(object) * nx->num_elt; -// return (char *) nx;} -// case vector_tag: -// {register vector nx = (vector) allocp; -// int i; -// type_of(nx) = vector_tag; -// nx->num_elt = ((vector) x)->num_elt; -// nx->elts = (object *)(((char *)nx) + sizeof(vector_type)); -// for (i = 0; i < nx->num_elt; i++) { -// nx->elts[i] = ((vector) x)->elts[i]; -// } -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(vector_type) + sizeof(object) * nx->num_elt; -// return (char *) nx;} -// case string_tag: -// {register string_type *nx = (string_type *) allocp; -// int str_size = gc_word_align(((string_type *)x)->len + 1); -// type_of(nx) = string_tag; -// nx->len = ((string_type *)x)->len; -// nx->str = ((char *)nx) + sizeof(string_type); -// memcpy(nx->str, ((string_type *)x)->str, nx->len + 1); -////TODO: below is changing, now we will need to always copy the cstring -////along with the string_type. need to be careful of any off-by-one errors -////here... -//// if (gcgen == 0) { -//// // Minor, data heap is not relocated -//// nx->str = ((string_type *)x)->str; -//// } else { -//// // Major collection, data heap is moving -//// nx->str = dhallocp; -//// int len = strlen(((string_type *) x)->str); -//// memcpy(dhallocp, ((string_type *) x)->str, len + 1); -//// dhallocp += len + 1; -//// } -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(string_type)+str_size; -// return (char *) nx;} -// case integer_tag: -// {register integer_type *nx = (integer_type *) allocp; -// type_of(nx) = integer_tag; nx->value = ((integer_type *) x)->value; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(integer_type); -// return (char *) nx;} -// case double_tag: -// {register double_type *nx = (double_type *) allocp; -// type_of(nx) = double_tag; nx->value = ((double_type *) x)->value; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(double_type); -// return (char *) nx;} -// case port_tag: -// {register port_type *nx = (port_type *) allocp; -// type_of(nx) = port_tag; nx->fp = ((port_type *) x)->fp; -// nx->mode = ((port_type *) x)->mode; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(port_type); -// return (char *) nx;} -// case cvar_tag: -// {register cvar_type *nx = (cvar_type *) allocp; -// type_of(nx) = cvar_tag; nx->pvar = ((cvar_type *) x)->pvar; -// forward(x) = nx; type_of(x) = forward_tag; -// x = (char *) nx; allocp = ((char *) nx)+sizeof(cvar_type); -// return (char *) nx;} -// case forward_tag: -// return (char *) forward(x); -// case eof_tag: break; -// case primitive_tag: break; -// case boolean_tag: break; -// case symbol_tag: break; // JAE TODO: raise an error here? Should not be possible in real code, though (IE, without GC DEBUG flag) -// default: -// printf("transport: bad tag x=%p x.tag=%ld\n",(void *)x,type_of(x)); exit(0);} -// return x;} -// -///* Use overflow macro which already knows which way the stack goes. */ -///* Major collection, transport objects on stack or old heap */ -//#define transp(p) \ -//temp = (p); \ -//if ((check_overflow(low_limit,temp) && \ -// check_overflow(temp,high_limit)) || \ -// (check_overflow(old_heap_low_limit - 1, temp) && \ -// check_overflow(temp,old_heap_high_limit + 1))) \ -// (p) = (object) transport(temp,major); -// -//void GC_loop(int major, closure cont, object *ans, int num_ans) -//{char foo; -// int i; -// register object temp; -// register object low_limit = &foo; /* Move live data above us. */ -// register object high_limit = stack_begin; -// register char *scanp = allocp; /* Cheney scan pointer. */ -// register object old_heap_low_limit = low_limit; // Minor-GC default -// register object old_heap_high_limit = high_limit; // Minor-GC default -// -// char *tmp_bottom = bottom; /* Bottom of tospace. */ -// char *tmp_allocp = allocp; /* Cheney allocate pointer. */ -// char *tmp_alloc_end = alloc_end; -// char *tmp_dhbottom = dhbottom; -// char *tmp_dhallocp = dhallocp; -// char *tmp_dhallocp_end = dhalloc_end; -// -// if (dhallocp > dhalloc_limit) { -// // Upgrade to major GC -// major = 1; -// no_major_gcs++; -// no_gcs--; -// } -// -// if (major) { -// // Initialize new heap (TODO: make a function for this) -// bottom = calloc(1,global_heap_size); -// allocp = (char *) ((((long) bottom)+7) & -8); -// alloc_end = allocp + global_heap_size - 8; -// scanp = allocp; -// old_heap_low_limit = tmp_bottom; -// old_heap_high_limit = tmp_alloc_end; -// -// dhallocp = dhbottom = calloc(1, global_heap_size); -// dhalloc_limit = dhallocp + (long)((global_heap_size - 8) * 0.90); -// dhalloc_end = dhallocp + global_heap_size - 8; -// } -// -//#if DEBUG_GC -// printf("\n=== started GC type = %d === \n", major); -//#endif -// /* Transport GC's continuation and its argument. */ -// transp(cont); -// gc_cont = cont; -// gc_num_ans = num_ans; -//#if DEBUG_GC -// printf("DEBUG done transporting cont\n"); -//#endif -// -// /* Prevent overrunning buffer */ -// if (num_ans > NUM_GC_ANS) { -// printf("Fatal error - too many arguments (%d) to GC\n", num_ans); -// exit(1); -// } -// -// for (i = 0; i < num_ans; i++){ -// transp(ans[i]); -// gc_ans[i] = ans[i]; -// } -//#if DEBUG_GC -// printf("DEBUG done transporting gc_ans\n"); -//#endif -// -// /* Transport mutations. */ -// { -// list l; -// for (l = mutation_table; !nullp(l); l = cdr(l)) { -// object o = car(l); -// if (type_of(o) == cons_tag) { -// // Transport, if necessary -// // TODO: need to test this with major GC, and -// // GC's of list/car-cdr from same generation -// transp(car(o)); -// transp(cdr(o)); -// } else if (type_of(o) == vector_tag) { -// int i; -// // TODO: probably too inefficient, try collecting single index -// for (i = 0; i < ((vector)o)->num_elt; i++) { -// transp(((vector)o)->elts[i]); -// } -// } else if (type_of(o) == forward_tag) { -// // Already transported, skip -// } else { -// printf("Unexpected type %ld transporting mutation\n", type_of(o)); -// exit(1); -// } -// } -// } -// clear_mutations(); /* Reset for next time */ -// -// /* Transport global variables. */ -// transp(Cyc_global_variables); /* Internal global used by the runtime */ -// { -// list l = global_table; -// for(; !nullp(l); l = cdr(l)){ -// cvar_type *c = (cvar_type *)car(l); -// transp(*(c->pvar)); // GC global, not the pvar -// } -// } -// while (scanpelt1); -// scanp += sizeof(closure1_type); break; -// case closure2_tag: -//#if DEBUG_GC -// printf("DEBUG transport closure2 \n"); -//#endif -// transp(((closure2) scanp)->elt1); transp(((closure2) scanp)->elt2); -// scanp += sizeof(closure2_type); break; -// case closure3_tag: -//#if DEBUG_GC -// printf("DEBUG transport closure3 \n"); -//#endif -// transp(((closure3) scanp)->elt1); transp(((closure3) scanp)->elt2); -// transp(((closure3) scanp)->elt3); -// scanp += sizeof(closure3_type); break; -// case closure4_tag: -//#if DEBUG_GC -// printf("DEBUG transport closure4 \n"); -//#endif -// transp(((closure4) scanp)->elt1); transp(((closure4) scanp)->elt2); -// transp(((closure4) scanp)->elt3); transp(((closure4) scanp)->elt4); -// scanp += sizeof(closure4_type); break; -// case closureN_tag: -//#if DEBUG_GC -// printf("DEBUG transport closureN \n"); -//#endif -// {int i; int n = ((closureN) scanp)->num_elt; -// for (i = 0; i < n; i++) { -// transp(((closureN) scanp)->elts[i]); -// } -// scanp += sizeof(closureN_type) + sizeof(object) * n; -// } -// break; -// case vector_tag: -//#if DEBUG_GC -// printf("DEBUG transport vector \n"); -//#endif -// {int i; int n = ((vector) scanp)->num_elt; -// for (i = 0; i < n; i++) { -// transp(((vector) scanp)->elts[i]); -// } -// scanp += sizeof(vector_type) + sizeof(object) * n; -// } -// break; -// case string_tag: { -//#if DEBUG_GC -// printf("DEBUG transport string \n"); -//#endif -// string_type *x = (string_type *)scanp; -// scanp += sizeof(string_type); -// scanp += gc_word_align(x->len + 1); -// break; -// } -////TODO: cstring is now after string_type, so need to skip that, too. -////stack allocations should be OK since we are only scanning the newspace here, -////but should double-check that... (though we are not able to even scan the -////stack so should be fine) -// case integer_tag: -//#if DEBUG_GC -// printf("DEBUG transport integer \n"); -//#endif -// scanp += sizeof(integer_type); break; -// case double_tag: -//#if DEBUG_GC -// printf("DEBUG transport double \n"); -//#endif -// scanp += sizeof(double_type); break; -// case port_tag: -//#if DEBUG_GC -// printf("DEBUG transport port \n"); -//#endif -// scanp += sizeof(port_type); break; -// case cvar_tag: -//#if DEBUG_GC -// printf("DEBUG transport cvar \n"); -//#endif -// scanp += sizeof(cvar_type); break; -// case eof_tag: -// case primitive_tag: -// case symbol_tag: -// case boolean_tag: -// default: -// printf("GC: bad tag scanp=%p scanp.tag=%ld\n",(void *)scanp,type_of(scanp)); -// exit(0);} -// -// if (major) { -// free(tmp_bottom); -// free(tmp_dhbottom); -// } -//} -// -//void GC(cont,ans,num_ans) closure cont; object *ans; int num_ans; -//{ -// /* Only room for one more minor-GC, so do a major one. -// * Not sure this is the best strategy, it may be better to do major -// * ones sooner, perhaps after every x minor GC's. -// * -// * Also may need to consider dynamically increasing heap size, but -// * by how much (1.3x, 1.5x, etc) and when? I suppose when heap usage -// * after a collection is above a certain percentage, then it would be -// * necessary to increase heap size the next time. -// */ -// if (allocp >= (bottom + (global_heap_size - global_stack_size))) { -// //printf("Possibly only room for one more minor GC. no_gcs = %ld\n", no_gcs); -// no_major_gcs++; -// GC_loop(1, cont, ans, num_ans); -// } else { -// no_gcs++; /* Count the number of minor GC's. */ -// GC_loop(0, cont, ans, num_ans); -// } -// -// /* You have to let it all go, Neo. Fear, doubt, and disbelief. Free your mind... */ -// longjmp(jmp_main,1); /* Return globals gc_cont, gc_ans. */ -//} - /** * Start a thread's trampoline From c41e80a6ae71fe12eab86ae084205d3fa1765f81 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 21 Dec 2015 22:30:25 -0500 Subject: [PATCH 278/339] Prove GC is cooperating w/blocked thread --- runtime.c | 3 +++ test.scm | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/runtime.c b/runtime.c index 1086258c..5bfcb6f6 100644 --- a/runtime.c +++ b/runtime.c @@ -2795,6 +2795,9 @@ to look at the lock-free structures provided by ck? */ void Cyc_end_thread(gc_thread_data *thd) { + // TODO: should we consider passing the current continuation (and args) + // as an argument? if we don't, will objects be collected that are still + // being used by active threads?? mclosure0(clo, Cyc_exit_thread); GC(thd, &clo, thd->gc_args, 0); } diff --git a/test.scm b/test.scm index 1dcb3314..27d05fc2 100644 --- a/test.scm +++ b/test.scm @@ -1,13 +1,37 @@ (import (scheme base) + (scheme read) (scheme write)) ;; Spawn off a thread -(let ((t (thread-start! (make-thread (lambda () (write 'a)))))) - ;; Busy wait - (letrec ((foo (lambda () (bar))) - (bar (lambda () (foo)))) - (foo)) -) +;(let ((t (thread-start! (make-thread (lambda () (write 'a)))))) +; ;; Busy wait +; (letrec ((foo (lambda () (bar))) +; (bar (lambda () (foo)))) +; (foo)) +;) + +;; A program to prove if cooperation is working, or if it +;; is blocked by another thread. The (read) causes the main +;; thread to block. The collector should be notified prior +;; to the blocking call being made, and the collector should +;; be able to cooperate on the main thread's behalf: +(define tmp '()) +(thread-start! + (make-thread + (lambda () + ;(write 'a) + (letrec ((loop (lambda () + (set! tmp (cons "cons" tmp)) + ;(write tmp) + (cond + ((> (length tmp) 1000) + (write "resetting tmp") + (set! tmp '())) + (else #f)) + (loop)))) + (loop)) + ))) +(read) ;;;; A temporary file to attempt to repro crashing / data corruption ;;(import (scheme base) (scheme write)) From be13df2abbb323791c4d04c75a98c5df7a92c9ab Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 21 Dec 2015 22:57:36 -0500 Subject: [PATCH 279/339] Perform deferred free of thread data Mark a mutator's thread as old when a thread is terminated, and free it at a later time. This is done to prevent race conditions with the collector thread, which could be in the middle of working with a thread's data. --- gc.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- runtime.c | 7 ++----- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index 34d27d03..42ff0c0a 100644 --- a/gc.c +++ b/gc.c @@ -42,7 +42,7 @@ static int cached_heap_free_size = 0; static int cached_heap_total_size = 0; // Data for each individual mutator thread -ck_array_t Cyc_mutators; +ck_array_t Cyc_mutators, old_mutators; static pthread_mutex_t mutators_lock; static void my_free(void *p, size_t m, bool d) @@ -78,6 +78,11 @@ void gc_initialize() exit(1); } + if (ck_array_init(&old_mutators, CK_ARRAY_MODE_SPMC, &my_allocator, 10) == 0){ + fprintf(stderr, "Unable to initialize mutator array\n"); + exit(1); + } + // Initialize collector's mark stack mark_stack_len = 128; mark_stack = vpbuffer_realloc(mark_stack, &(mark_stack_len)); @@ -105,6 +110,10 @@ void gc_add_mutator(gc_thread_data *thd) pthread_mutex_unlock(&mutators_lock); } +// Remove selected mutator from the mutator list. +// This is done for terminated threads. Note data is queued to be +// freed, to prevent accidentally freeing it while the collector +// thread is potentially accessing it. void gc_remove_mutator(gc_thread_data *thd) { pthread_mutex_lock(&mutators_lock); @@ -113,6 +122,36 @@ void gc_remove_mutator(gc_thread_data *thd) exit(1); } ck_array_commit(&Cyc_mutators); + // Place on list of old mutators to cleanup + if (ck_array_put_unique(&old_mutators, (void *)thd) < 0) { + fprintf(stderr, "Unable to add thread data to GC list, existing\n"); + exit(1); + } + ck_array_commit(&old_mutators); + pthread_mutex_unlock(&mutators_lock); +} + +void gc_free_old_thread_data() +{ + ck_array_iterator_t iterator; + gc_thread_data *m; + int freed = 0; + + pthread_mutex_lock(&mutators_lock); + CK_ARRAY_FOREACH(&old_mutators, &iterator, &m){ +printf("JAE DEBUG - freeing old thread data..."); + gc_thread_data_free(m); + if (!ck_array_remove(&old_mutators, (void *)m)) { + fprintf(stderr, "Error removing old mutator data\n"); + exit(1); + } + freed = 1; +printf(" done\n"); + } + if (freed) { + ck_array_commit(&old_mutators); +printf("commited old mutator data deletions\n"); + } pthread_mutex_unlock(&mutators_lock); } @@ -1195,6 +1234,11 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); total_size, total_free, freed, max_freed, time(NULL) - sweep_start); #endif +#if GC_DEBUG_TRACE + fprintf(stderr, "cleaning up any old thread data\n"); +#endif + gc_free_old_thread_data(); + // Idle the GC thread ATOMIC_SET_IF_EQ(&gc_stage, STAGE_SWEEPING, STAGE_RESTING); } diff --git a/runtime.c b/runtime.c index 5bfcb6f6..82db23c9 100644 --- a/runtime.c +++ b/runtime.c @@ -2811,13 +2811,10 @@ void Cyc_exit_thread(gc_thread_data *thd) // referenced? might want to do one more minor GC to clear the stack before // terminating the thread -printf("DEBUG - exiting thread\n"); -// TODO: race condition, cannot free thread data if the collector is using it +//printf("DEBUG - exiting thread\n"); + // Remove thread from the list of mutators, and mark its data to be freed gc_remove_mutator(thd); ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); -// TODO: could maintain a dedicated list of old thread data to clean up... -// collector could do it at a time that is safe -// gc_thread_data_free(thd); pthread_exit(NULL); // For now, just a proof of concept } From 9de27c2f9824b086405a1a05a13b861106a664d7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 21 Dec 2015 23:06:10 -0500 Subject: [PATCH 280/339] Use a lock to synchronize writes to symbol table --- gc-notes.txt | 2 -- runtime.c | 10 ++++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 98014d9c..65a31003 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -12,8 +12,6 @@ TODO: - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc - TODO items: - - lock writes to symbol table - need to cooperate when a mutator is blocked might be able to stop a thread and do a minor GC on it, but no longjmp until after major GC. diff --git a/runtime.c b/runtime.c index 82db23c9..2f084fa9 100644 --- a/runtime.c +++ b/runtime.c @@ -102,6 +102,7 @@ static symbol_type __EOF = {{0}, eof_tag, "", nil}; // symbol_type in lieu of cu const object Cyc_EOF = &__EOF; static ck_hs_t symbol_table; static int symbol_table_size = 65536; +static pthread_mutex_t symbol_table_lock; // Functions to support concurrency kit hashset // These are specifically for a table of symbols @@ -168,6 +169,10 @@ void gc_init_heap(long heap_size) fprintf(stderr, "Unable to initialize symbol table\n"); exit(1); } + if (pthread_mutex_init(&(symbol_table_lock), NULL) != 0) { + fprintf(stderr, "Unable to initialize symbol_table_lock mutex\n"); + exit(1); + } } gc_heap *gc_get_heap() @@ -245,13 +250,14 @@ object find_symbol_by_name(const char *name) { object add_symbol(symbol_type *psym) { //printf("Adding symbol %s, table size = %ld\n", symbol_pname(psym), ck_hs_count(&symbol_table)); - // TODO: lock table here, only allow one writer at a time - // TODO: grow table if it is not big enough + pthread_mutex_lock(&symbol_table_lock); // Only 1 "writer" allowed if (ck_hs_count(&symbol_table) == symbol_table_size) { + // TODO: grow table if it is not big enough fprintf(stderr, "Ran out of symbol table entries\n"); exit(1); } set_insert(&symbol_table, psym); + pthread_mutex_unlock(&symbol_table_lock); return psym; } From 66ef2e2646deb0281974070829b0c5be853cc40a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 03:09:11 -0500 Subject: [PATCH 281/339] Added thread state helpers, avoid races during coop --- gc.c | 22 +++++++++++++++++----- include/cyclone/types.h | 3 +++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 42ff0c0a..e73cadcb 100644 --- a/gc.c +++ b/gc.c @@ -836,8 +836,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) // TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { - int i, status = ATOMIC_GET(&gc_status_col), - stage = ATOMIC_GET(&gc_stage); + int i; #if GC_DEBUG_VERBOSE int debug_print = 0; #endif @@ -848,7 +847,8 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); - if (thd->gc_status != status) { + if (thd->gc_status != ATOMIC_GET(&gc_status_col)) { + thd->gc_status = ATOMIC_GET(&gc_status_col); if (thd->gc_status == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); @@ -876,7 +876,6 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) pthread_mutex_unlock(&(thd->lock)); thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } - thd->gc_status = status; } #if GC_DEBUG_VERBOSE if (debug_print) { @@ -893,7 +892,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) // Initiate collection cycle if free space is too low. // Threshold is intentially low because we have to go through an // entire handshake/trace/sweep cycle, ideally without growing heap. - if (stage == STAGE_RESTING && + if (ATOMIC_GET(&gc_stage) == STAGE_RESTING && (cached_heap_free_size < (cached_heap_total_size * 0.50))){ #if GC_DEBUG_TRACE fprintf(stdout, "Less than 50%% of the heap is free, initiating collector\n"); @@ -1336,6 +1335,19 @@ void gc_thread_data_free(gc_thread_data *thd) } } +void gc_set_thread_state_blocked(gc_thread_data *thd) +{ + ATOMIC_SET_IF_EQ(&(thd->thread_state), + CYC_THREAD_STATE_RUNNABLE, + CYC_THREAD_STATE_BLOCKED); +} +void gc_set_thread_state_runnable(gc_thread_data *thd) +{ + ATOMIC_SET_IF_EQ(&(thd->thread_state), + CYC_THREAD_STATE_BLOCKED, + CYC_THREAD_STATE_RUNNABLE); +} + //// Unit testing: //int main(int argc, char **argv) { // int a = 1, b = 2, c = 3, i; diff --git a/include/cyclone/types.h b/include/cyclone/types.h index b2c23252..0c2d6bb6 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -52,6 +52,7 @@ typedef void *object; /* Threading */ typedef enum { CYC_THREAD_STATE_NEW , CYC_THREAD_STATE_RUNNABLE + , CYC_THREAD_STATE_BLOCKED , CYC_THREAD_STATE_TERMINATED } cyc_thread_state_type; @@ -203,6 +204,8 @@ void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); void gc_start_collector(); +void gc_set_thread_state_blocked(gc_thread_data *thd); +void gc_set_thread_state_runnable(gc_thread_data *thd); gc_heap *gc_get_heap(); ///////////////////////////////////////////// From 6693b4533a06f6ef9efc4ab9ae2cd513c371b64f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 03:15:45 -0500 Subject: [PATCH 282/339] Fixed bug with previous change Do not change mutator status prior to checking it --- gc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gc.c b/gc.c index e73cadcb..243cc3fe 100644 --- a/gc.c +++ b/gc.c @@ -836,7 +836,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) // TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { - int i; + int i, status; #if GC_DEBUG_VERBOSE int debug_print = 0; #endif @@ -847,8 +847,8 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); - if (thd->gc_status != ATOMIC_GET(&gc_status_col)) { - thd->gc_status = ATOMIC_GET(&gc_status_col); + status = ATOMIC_GET(&gc_status_col); + if (thd->gc_status != status) { if (thd->gc_status == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); @@ -876,6 +876,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) pthread_mutex_unlock(&(thd->lock)); thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } + thd->gc_status = status; } #if GC_DEBUG_VERBOSE if (debug_print) { From 9a9b3cc640e1b46e82170e644ff242c13a3c70eb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:24:11 -0500 Subject: [PATCH 283/339] Let GC know a thread is (potentially) blocking --- runtime.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/runtime.c b/runtime.c index 2f084fa9..81399c4c 100644 --- a/runtime.c +++ b/runtime.c @@ -1487,9 +1487,12 @@ object Cyc_io_file_exists(void *data, object filename) { // TODO: port arg is optional! (maybe handle that in expansion section??) object Cyc_io_read_char(void *data, object port) { + int c; Cyc_check_port(data, port); { - int c = fgetc(((port_type *) port)->fp); + gc_set_thread_state_blocked((gc_thread_data *)data); + c = fgetc(((port_type *) port)->fp); + gc_set_thread_state_runnable((gc_thread_data *)data); if (c != EOF) { return obj_char2obj(c); } @@ -1503,14 +1506,17 @@ object Cyc_io_read_line(void *data, object cont, object port) { char buf[1024]; int i = 0, c; + gc_set_thread_state_blocked((gc_thread_data *)data); while (1) { c = fgetc(stream); if (c == EOF && i == 0) { + gc_set_thread_state_runnable((gc_thread_data *)data); return_closcall1(data, cont, Cyc_EOF); } else if (c == EOF || i == 1023 || c == '\n') { buf[i] = '\0'; { make_string(s, buf); + gc_set_thread_state_runnable((gc_thread_data *)data); return_closcall1(data, cont, &s); } } @@ -1527,8 +1533,10 @@ object Cyc_io_peek_char(void *data, object port) { Cyc_check_port(data, port); { stream = ((port_type *) port)->fp; + gc_set_thread_state_blocked((gc_thread_data *)data); c = fgetc(stream); ungetc(c, stream); + gc_set_thread_state_runnable((gc_thread_data *)data); if (c != EOF) { return obj_char2obj(c); } From ec8821b9efed8157a00639d35410c1e5e6cd2c35 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:57:28 -0500 Subject: [PATCH 284/339] Use atomics to access thd->gc_status --- gc.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/gc.c b/gc.c index 243cc3fe..f4c86af1 100644 --- a/gc.c +++ b/gc.c @@ -771,7 +771,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) { int status = ATOMIC_GET(&gc_status_col), stage = ATOMIC_GET(&gc_stage); - if (thd->gc_status != STATUS_ASYNC) { + if (ATOMIC_GET(&(thd->gc_status)) != STATUS_ASYNC) { //fprintf(stderr, "DEBUG - GC sync marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); //fprintf(stderr, " and new value %p ", value); @@ -836,7 +836,7 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) // TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { - int i, status; + int i, status_c, status_m; #if GC_DEBUG_VERBOSE int debug_print = 0; #endif @@ -847,9 +847,16 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); - status = ATOMIC_GET(&gc_status_col); - if (thd->gc_status != status) { - if (thd->gc_status == STATUS_ASYNC) { + // TODO: I think below is thread safe, but this code is tricky. + // worst case should be that some work is done twice if there is + // a race condition + // + // TODO: should use an atomic comparison here + status_c = ATOMIC_GET(&gc_status_col); + status_m = ATOMIC_GET(&(thd->gc_status)); + if (status_m != status_c) { + ATOMIC_SET_IF_EQ(&(thd->gc_status), status_m, status_c); + if (status_m == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); thd->last_write = 0; @@ -857,7 +864,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); } - else if (thd->gc_status == STATUS_SYNC2) { + else if (status_m == STATUS_SYNC2) { #if GC_DEBUG_VERBOSE debug_print = 1; #endif @@ -876,7 +883,6 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) pthread_mutex_unlock(&(thd->lock)); thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); } - thd->gc_status = status; } #if GC_DEBUG_VERBOSE if (debug_print) { @@ -1141,15 +1147,18 @@ void gc_wait_handshake() CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) { while (1) { + // TODO: use an atomic comparison statusc = ATOMIC_GET(&gc_status_col); statusm = ATOMIC_GET(&(m->gc_status)); - thread_status = ATOMIC_GET(&(m->thread_state)); if (statusc == statusm) { // Handshake succeeded, check next mutator break; } - if (thread_status == CYC_THREAD_STATE_TERMINATED) { + thread_status = ATOMIC_GET(&(m->thread_state)); + if (thread_status == CYC_THREAD_STATE_BLOCKED) { + // CAS + } else if (thread_status == CYC_THREAD_STATE_TERMINATED) { // Thread is no longer running break; } From 785923f9556922354ace8c0080e6c8111bf0654c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 23:07:35 -0500 Subject: [PATCH 285/339] Partial GC coop for blocked mutator --- gc.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index f4c86af1..87b1c105 100644 --- a/gc.c +++ b/gc.c @@ -1157,7 +1157,19 @@ void gc_wait_handshake() thread_status = ATOMIC_GET(&(m->thread_state)); if (thread_status == CYC_THREAD_STATE_BLOCKED) { - // CAS + // Cooperate for the blocked mutator + if (statusc != STATUS_ASYNC) { // TODO: need code to handle this + ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); + if (statusc == STATUS_SYNC1) { + // Async is done, so clean up old mark data from the last collection + pthread_mutex_lock(&(m->lock)); + m->last_write = 0; + m->last_read = 0; + m->pending_writes = 0; + pthread_mutex_unlock(&(m->lock)); + } + // TODO: else if (statusc == STATUS_ASYNC) + } } else if (thread_status == CYC_THREAD_STATE_TERMINATED) { // Thread is no longer running break; From 9fd4929bb04bbaa62b0c1d66869db3772d1653e4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 02:25:52 -0500 Subject: [PATCH 286/339] Added notes --- gc-notes.txt | 47 +++++++++++++++++++++++++++++++++++++++++++++++ gc.c | 3 +++ 2 files changed, 50 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 65a31003..236ae53e 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -14,6 +14,53 @@ TODO: part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc - need to cooperate when a mutator is blocked + IMPLEMENTATION NOTES: + + these become gc_cont and gc_args, so we need them for the wrapper: + GC(td,cfn,buf,1); return; + also need the result of the primitive, although that obviously is not + available until after it finishes blocking. will just have to live with that + constraint. + + requirements: + - collector detects initiates async transition + - collector will need to perform a minor GC instead of this mutator + will need to pass in top of stack then, since collector won't have that. + can use address of continuation, if we can guarantee it will always be + allocated on the stack prior to wrapper call. or can just let the wrapper + do it, and stash it somewhere collector can get to it + - collector must set flag immediately to let mutator know what happened + - mutator must know when the transition occurs, and wait for it to finish + - can use mutator lock + + will cont always be called via closcall1? + maybe we need to require prim accepts cont as an arg. might simplify + calling the wrapper. + + then instead of a wrapper, the prim can call functions to set initial state and cleanup. it already does this to set thread state, so this isn't that big of a change (just call 2 other functions): + + before_blocking { + set thread state ==> BLOCKING + set thd->gc_cont to cont, in case collector needs to use it + set stack_top to new field in "thd", again in case collector needs it + OR NOT, I think we can use stack_limit for this, to define the + range of stack addresses + } + + after_blocking { + set thread state ==> RUNNABLE + check async flag + if set: + wait for thd->lock + unset async flag + transport result to heap, if necessary (not a value type) + set gc_args[0] to result + longjmp. assumes gc_cont already set by collector + else: + call into cont with result, just like today (see Cyc_io_read_line) + } + + OLDER NOTES: might be able to stop a thread and do a minor GC on it, but no longjmp until after major GC. would need to figure out how to repack gc_cont and args optionally, some primitives can accept a cont, how to handle? I guess we would have to diff --git a/gc.c b/gc.c index 87b1c105..ac716d75 100644 --- a/gc.c +++ b/gc.c @@ -1169,6 +1169,9 @@ void gc_wait_handshake() pthread_mutex_unlock(&(m->lock)); } // TODO: else if (statusc == STATUS_ASYNC) + /* + take m->lock (also have to handle on mutator, maybe just lock/unlock after exiting prim? but then how to know if async transition happened? does the collector need to set a flag? + */ } } else if (thread_status == CYC_THREAD_STATE_TERMINATED) { // Thread is no longer running From f0b992335e246b4243a299e748c5db57b0705de9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 03:02:52 -0500 Subject: [PATCH 287/339] Separate cooperation/longjmp from core minor GC --- include/cyclone/types.h | 95 +++++++++++++++++++---------------------- runtime.c | 20 ++++++--- 2 files changed, 60 insertions(+), 55 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 0c2d6bb6..cffa9309 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -164,56 +164,6 @@ typedef enum { STAGE_CLEAR_OR_MARKING #define gc_color_red 0 // Memory not to be GC'd, such as on the stack #define gc_color_blue 2 // Unallocated memory -/* Utility functions */ -void **vpbuffer_realloc(void **buf, int *len); -void **vpbuffer_add(void **buf, int *len, int i, void *obj); -void vpbuffer_free(void **buf); - -/* GC prototypes */ -void gc_initialize(); -void gc_add_mutator(gc_thread_data *thd); -void gc_remove_mutator(gc_thread_data *thd); -gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); -int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); -char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); -void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd); -void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown); -size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r); -gc_heap *gc_heap_last(gc_heap *h); -size_t gc_heap_total_size(gc_heap *h); -//size_t gc_heap_total_free_size(gc_heap *h); -//size_t gc_collect(gc_heap *h, size_t *sum_freed); -//void gc_mark(gc_heap *h, object obj); -void gc_mark_globals(void); -size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); -void gc_thr_grow_move_buffer(gc_thread_data *d); -void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); -void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); -void gc_thread_data_free(gc_thread_data *thd); -// Prototypes for mutator/collector: -int gc_is_stack_obj(gc_thread_data *thd, object obj); -void gc_mut_update(gc_thread_data *thd, object old_obj, object value); -void gc_mut_cooperate(gc_thread_data *thd, int buf_len); -void gc_mark_gray(gc_thread_data *thd, object obj); -void gc_mark_gray2(gc_thread_data *thd, object obj); -void gc_collector_trace(); -void gc_mark_black(object obj); -void gc_collector_mark_gray(object parent, object obj); -void gc_empty_collector_stack(); -void gc_handshake(gc_status_type s); -void gc_post_handshake(gc_status_type s); -void gc_wait_handshake(); -void gc_start_collector(); -void gc_set_thread_state_blocked(gc_thread_data *thd); -void gc_set_thread_state_runnable(gc_thread_data *thd); -gc_heap *gc_get_heap(); - -///////////////////////////////////////////// -// GC Collection cycle - -// TODO: -//void gc_collector() - /* Show diagnostic information for the GC when program terminates */ #define DEBUG_SHOW_DIAG 0 @@ -451,6 +401,51 @@ typedef union { double_type double_t; } common_type; +/* Utility functions */ +void **vpbuffer_realloc(void **buf, int *len); +void **vpbuffer_add(void **buf, int *len, int i, void *obj); +void vpbuffer_free(void **buf); + +/* GC prototypes */ +void gc_initialize(); +void gc_add_mutator(gc_thread_data *thd); +void gc_remove_mutator(gc_thread_data *thd); +gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); +int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); +char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); +void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd); +void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown); +size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r); +gc_heap *gc_heap_last(gc_heap *h); +size_t gc_heap_total_size(gc_heap *h); +//size_t gc_heap_total_free_size(gc_heap *h); +//size_t gc_collect(gc_heap *h, size_t *sum_freed); +//void gc_mark(gc_heap *h, object obj); +void gc_mark_globals(void); +size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr); +void gc_thr_grow_move_buffer(gc_thread_data *d); +void gc_thr_add_to_move_buffer(gc_thread_data *d, int *alloci, object obj); +void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, long stack_size); +void gc_thread_data_free(gc_thread_data *thd); +// Prototypes for mutator/collector: +int gc_is_stack_obj(gc_thread_data *thd, object obj); +void gc_mut_update(gc_thread_data *thd, object old_obj, object value); +void gc_mut_cooperate(gc_thread_data *thd, int buf_len); +void gc_mark_gray(gc_thread_data *thd, object obj); +void gc_mark_gray2(gc_thread_data *thd, object obj); +void gc_collector_trace(); +void gc_mark_black(object obj); +void gc_collector_mark_gray(object parent, object obj); +void gc_empty_collector_stack(); +void gc_handshake(gc_status_type s); +void gc_post_handshake(gc_status_type s); +void gc_wait_handshake(); +void gc_start_collector(); +void gc_set_thread_state_blocked(gc_thread_data *thd); +void gc_set_thread_state_runnable(gc_thread_data *thd); +gc_heap *gc_get_heap(); +int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args); + // Atomics section // TODO: this is all compiler dependent, need to use different macros depending // upon the compiler (and arch) diff --git a/runtime.c b/runtime.c index 81399c4c..5726e7a4 100644 --- a/runtime.c +++ b/runtime.c @@ -2254,12 +2254,10 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } \ } -void GC(void *data, closure cont, object *args, int num_args) +// Do a minor GC +int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args) { - char tmp; object temp; - object low_limit = &tmp; // This is one end of the stack... - object high_limit = ((gc_thread_data *)data)->stack_start; int i; int scani = 0, alloci = 0; int heap_grown = 0; @@ -2374,10 +2372,22 @@ void GC(void *data, closure cont, object *args, int num_args) } scani++; } + return alloci; +} +/** + * Run a minor GC from a mutator thread. + * This function runs the core GC algorithm, cooperates with + * the collector, and then calls its continuation. + */ +void GC(void *data, closure cont, object *args, int num_args) +{ + char tmp; + object low_limit = &tmp; // This is one end of the stack... + object high_limit = ((gc_thread_data *)data)->stack_start; + int alloci = gc_minor(data, low_limit, high_limit, cont, args, num_args); // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data, alloci); - #if GC_DEBUG_TRACE fprintf(stderr, "done with minor GC\n"); #endif From 309e35c69bddc44b6b640d3c0ce5c2786e43745d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 21:57:00 -0500 Subject: [PATCH 288/339] Added cont argument to blocking I/O functions --- include/cyclone/runtime.h | 4 ++-- runtime.c | 8 ++++---- scheme/cyclone/cgen.sld | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 088e2024..2e92bdf4 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -150,8 +150,8 @@ object Cyc_io_close_output_port(void *data, object port); object Cyc_io_flush_output_port(void *data, object port); object Cyc_io_delete_file(void *data, object filename); object Cyc_io_file_exists(void *data, object filename); -object Cyc_io_read_char(void *data, object port); -object Cyc_io_peek_char(void *data, object port); +object Cyc_io_read_char(void *data, object cont, object port); +object Cyc_io_peek_char(void *data, object cont, object port); object Cyc_io_read_line(void *data, object cont, object port); object Cyc_is_boolean(object o); diff --git a/runtime.c b/runtime.c index 5726e7a4..25332bad 100644 --- a/runtime.c +++ b/runtime.c @@ -1486,7 +1486,7 @@ object Cyc_io_file_exists(void *data, object filename) { } // TODO: port arg is optional! (maybe handle that in expansion section??) -object Cyc_io_read_char(void *data, object port) { +object Cyc_io_read_char(void *data, object cont, object port) { int c; Cyc_check_port(data, port); { @@ -1526,7 +1526,7 @@ object Cyc_io_read_line(void *data, object cont, object port) { return nil; } -object Cyc_io_peek_char(void *data, object port) { +object Cyc_io_peek_char(void *data, object cont, object port) { FILE *stream; int c; @@ -1952,10 +1952,10 @@ void _delete_91file(void *data, object cont, object args) { return_closcall1(data, cont, Cyc_io_delete_file(data, car(args)));} void _read_91char(void *data, object cont, object args) { Cyc_check_num_args(data, "read-char", 1, args); - return_closcall1(data, cont, Cyc_io_read_char(data, car(args)));} + return_closcall1(data, cont, Cyc_io_read_char(data, cont, car(args)));} void _peek_91char(void *data, object cont, object args) { Cyc_check_num_args(data, "peek-char", 1, args); - return_closcall1(data, cont, Cyc_io_peek_char(data, car(args)));} + return_closcall1(data, cont, Cyc_io_peek_char(data, cont, car(args)));} void _Cyc_91read_91line(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-read-line", 1, args); Cyc_io_read_line(data, cont, car(args));} diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index f6cdc891..c700f525 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -651,6 +651,8 @@ ((eq? p 'string-length) "integer_type") ((eq? p 'apply) "object") ((eq? p 'Cyc-read-line) "object") + ((eq? p 'read-char) "object") + ((eq? p 'peek-char) "object") ((eq? p 'command-line-arguments) "object") ((eq? p 'number->string) "object") ((eq? p 'symbol->string) "object") @@ -681,12 +683,14 @@ + - * / apply command-line-arguments Cyc-read-line + read-char peek-char cons length vector-length cell)))) ;; Pass continuation as the function's first parameter? (define (prim:cont? exp) (and (prim? exp) (member exp '(Cyc-read-line apply command-line-arguments number->string + read-char peek-char symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) From 247b09fc88d6c116a7ec66ecad559282ad41a9cd Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:19:04 -0500 Subject: [PATCH 289/339] Store cont before mutator is blocked --- gc.c | 5 +++-- include/cyclone/types.h | 4 ++-- runtime.c | 14 +++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/gc.c b/gc.c index ac716d75..b8689d33 100644 --- a/gc.c +++ b/gc.c @@ -1360,13 +1360,14 @@ void gc_thread_data_free(gc_thread_data *thd) } } -void gc_set_thread_state_blocked(gc_thread_data *thd) +void gc_set_thread_blocked(gc_thread_data *thd, object cont) { ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED); + thd->gc_cont = cont; } -void gc_set_thread_state_runnable(gc_thread_data *thd) +void gc_set_thread_runnable(gc_thread_data *thd) { ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_BLOCKED, diff --git a/include/cyclone/types.h b/include/cyclone/types.h index cffa9309..467670f1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -441,8 +441,8 @@ void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); void gc_start_collector(); -void gc_set_thread_state_blocked(gc_thread_data *thd); -void gc_set_thread_state_runnable(gc_thread_data *thd); +void gc_set_thread_blocked(gc_thread_data *thd, object cont); +void gc_set_thread_runnable(gc_thread_data *thd); gc_heap *gc_get_heap(); int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args); diff --git a/runtime.c b/runtime.c index 25332bad..596a3fba 100644 --- a/runtime.c +++ b/runtime.c @@ -1490,9 +1490,9 @@ object Cyc_io_read_char(void *data, object cont, object port) { int c; Cyc_check_port(data, port); { - gc_set_thread_state_blocked((gc_thread_data *)data); + gc_set_thread_blocked((gc_thread_data *)data, cont); c = fgetc(((port_type *) port)->fp); - gc_set_thread_state_runnable((gc_thread_data *)data); + gc_set_thread_runnable((gc_thread_data *)data); if (c != EOF) { return obj_char2obj(c); } @@ -1506,17 +1506,17 @@ object Cyc_io_read_line(void *data, object cont, object port) { char buf[1024]; int i = 0, c; - gc_set_thread_state_blocked((gc_thread_data *)data); + gc_set_thread_blocked((gc_thread_data *)data, cont); while (1) { c = fgetc(stream); if (c == EOF && i == 0) { - gc_set_thread_state_runnable((gc_thread_data *)data); + gc_set_thread_runnable((gc_thread_data *)data); return_closcall1(data, cont, Cyc_EOF); } else if (c == EOF || i == 1023 || c == '\n') { buf[i] = '\0'; { make_string(s, buf); - gc_set_thread_state_runnable((gc_thread_data *)data); + gc_set_thread_runnable((gc_thread_data *)data); return_closcall1(data, cont, &s); } } @@ -1533,10 +1533,10 @@ object Cyc_io_peek_char(void *data, object cont, object port) { Cyc_check_port(data, port); { stream = ((port_type *) port)->fp; - gc_set_thread_state_blocked((gc_thread_data *)data); + gc_set_thread_blocked((gc_thread_data *)data, cont); c = fgetc(stream); ungetc(c, stream); - gc_set_thread_state_runnable((gc_thread_data *)data); + gc_set_thread_runnable((gc_thread_data *)data); if (c != EOF) { return obj_char2obj(c); } From 8aefcbfd13bc6031484b67decc95f3619ba9b1f4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:39:51 -0500 Subject: [PATCH 290/339] New mutator signatures --- gc.c | 6 ++++-- runtime.c | 18 +++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/gc.c b/gc.c index b8689d33..636368a6 100644 --- a/gc.c +++ b/gc.c @@ -1360,18 +1360,20 @@ void gc_thread_data_free(gc_thread_data *thd) } } -void gc_set_thread_blocked(gc_thread_data *thd, object cont) +void gc_mutator_thread_blocked(gc_thread_data *thd, object cont) { ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED); thd->gc_cont = cont; } -void gc_set_thread_runnable(gc_thread_data *thd) + +void gc_mutator_thread_runnable(gc_thread_data *thd, object result) { ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_RUNNABLE); + (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); } //// Unit testing: diff --git a/runtime.c b/runtime.c index 596a3fba..50135e5a 100644 --- a/runtime.c +++ b/runtime.c @@ -1490,9 +1490,11 @@ object Cyc_io_read_char(void *data, object cont, object port) { int c; Cyc_check_port(data, port); { - gc_set_thread_blocked((gc_thread_data *)data, cont); + gc_mutator_thread_blocked((gc_thread_data *)data, cont); c = fgetc(((port_type *) port)->fp); - gc_set_thread_runnable((gc_thread_data *)data); + gc_mutator_thread_runnable( + (gc_thread_data *)data, + (c != EOF) ? obj_char2obj(c) : Cyc_EOF); if (c != EOF) { return obj_char2obj(c); } @@ -1506,17 +1508,17 @@ object Cyc_io_read_line(void *data, object cont, object port) { char buf[1024]; int i = 0, c; - gc_set_thread_blocked((gc_thread_data *)data, cont); + gc_mutator_thread_blocked((gc_thread_data *)data, cont); while (1) { c = fgetc(stream); if (c == EOF && i == 0) { - gc_set_thread_runnable((gc_thread_data *)data); + gc_mutator_thread_runnable((gc_thread_data *)data, Cyc_EOF); return_closcall1(data, cont, Cyc_EOF); } else if (c == EOF || i == 1023 || c == '\n') { buf[i] = '\0'; { make_string(s, buf); - gc_set_thread_runnable((gc_thread_data *)data); + gc_mutator_thread_runnable((gc_thread_data *)data, &s); return_closcall1(data, cont, &s); } } @@ -1533,10 +1535,12 @@ object Cyc_io_peek_char(void *data, object cont, object port) { Cyc_check_port(data, port); { stream = ((port_type *) port)->fp; - gc_set_thread_blocked((gc_thread_data *)data, cont); + gc_mutator_thread_blocked((gc_thread_data *)data, cont); c = fgetc(stream); ungetc(c, stream); - gc_set_thread_runnable((gc_thread_data *)data); + gc_mutator_thread_runnable( + (gc_thread_data *)data, + (c != EOF) ? obj_char2obj(c) : Cyc_EOF); if (c != EOF) { return obj_char2obj(c); } From 6a2ed8ff232b452257b3d7699a451550e29da8e2 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:41:25 -0500 Subject: [PATCH 291/339] Updated header file --- include/cyclone/types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 467670f1..64d0f9a1 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -441,8 +441,8 @@ void gc_handshake(gc_status_type s); void gc_post_handshake(gc_status_type s); void gc_wait_handshake(); void gc_start_collector(); -void gc_set_thread_blocked(gc_thread_data *thd, object cont); -void gc_set_thread_runnable(gc_thread_data *thd); +void gc_mutator_thread_blocked(gc_thread_data *thd, object cont); +void gc_mutator_thread_runnable(gc_thread_data *thd, object result); gc_heap *gc_get_heap(); int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args); From cc36d6459d104b54937427b63831c253fd09a6ec Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 22 Dec 2015 22:49:55 -0500 Subject: [PATCH 292/339] Added collector_cooperated flag --- gc.c | 12 +++++++++++- include/cyclone/types.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 636368a6..d038794f 100644 --- a/gc.c +++ b/gc.c @@ -1335,6 +1335,7 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->last_read = 0; thd->mark_buffer_len = 128; thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); + thd->collector_cooperated = 0; if (pthread_mutex_init(&(thd->lock), NULL) != 0) { fprintf(stderr, "Unable to initialize thread mutex\n"); exit(1); @@ -1373,7 +1374,16 @@ void gc_mutator_thread_runnable(gc_thread_data *thd, object result) ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_RUNNABLE); - (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); + if (ATOMIC_GET(&(thd->collector_cooperated))) { + // TODO: + // wait for thd->lock + // unset async flag + // transport result to heap, if necessary (IE, is not a value type) + // set gc_args[0] to result + // longjmp. assumes gc_cont already set by collector + } else { + (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); + } } //// Unit testing: diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 64d0f9a1..5a13bec3 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -85,6 +85,7 @@ struct gc_thread_data_t { void **mark_buffer; int mark_buffer_len; pthread_mutex_t lock; + int collector_cooperated; // Data needed for call history char **stack_traces; int stack_trace_idx; From c09dc43dde3f48b99239021bdf8b897d2caa812c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 22:34:11 -0500 Subject: [PATCH 293/339] First crack at gc_mutator_thread_runnable --- gc.c | 24 ++++++++++++++++++------ runtime.c | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index d038794f..858911f9 100644 --- a/gc.c +++ b/gc.c @@ -1375,13 +1375,25 @@ void gc_mutator_thread_runnable(gc_thread_data *thd, object result) CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_RUNNABLE); if (ATOMIC_GET(&(thd->collector_cooperated))) { - // TODO: - // wait for thd->lock - // unset async flag - // transport result to heap, if necessary (IE, is not a value type) - // set gc_args[0] to result - // longjmp. assumes gc_cont already set by collector +printf("DEBUG - Collector cooperated, wait for it to finish\n"); + // wait for the collector to finish + pthread_mutex_lock(&(thd->lock)); + pthread_mutex_unlock(&(thd->lock)); + // unset async flag + while(!ATOMIC_SET_IF_EQ(&(thd->collector_cooperated), 1, 0)){} + // transport result to heap, if necessary (IE, is not a value type) + if (is_object_type(result)) { + fprintf(stderr, "Unhandled object type result, TODO: implement\n"); + exit(1); + } + // Setup value to send to continuation + thd->gc_args[0] = result; + thd->gc_num_args = 1; + // Whoa. +printf("DEBUG - Call into gc_cont setup by collector\n"); + longjmp(*(thd->jmp_start), 1); } else { + // Collector didn't do anything; make a normal continuation call (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); } } diff --git a/runtime.c b/runtime.c index 50135e5a..5aefa20d 100644 --- a/runtime.c +++ b/runtime.c @@ -2112,7 +2112,7 @@ TODO: should rename this function to make it more clear what is really going on */ void Cyc_start_thread(gc_thread_data *thd) { - /* Tank, load the jump program... */ + // Tank, load the jump program setjmp(*(thd->jmp_start)); #if DEBUG_GC From 2e9c5addd58a4aac363990182cce1dde08ba5d62 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 00:50:37 -0500 Subject: [PATCH 294/339] WIP --- gc.c | 105 +++++++++++++++++++++++++--------------- include/cyclone/types.h | 2 +- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/gc.c b/gc.c index 858911f9..7fab30a2 100644 --- a/gc.c +++ b/gc.c @@ -1140,7 +1140,7 @@ void gc_wait_handshake() { ck_array_iterator_t iterator; gc_thread_data *m; - int statusm, statusc, thread_status; + int statusm, statusc, thread_status, i, buf_len; struct timespec tim; tim.tv_sec = 0; tim.tv_nsec = 1000000; // 1 millisecond @@ -1157,22 +1157,42 @@ void gc_wait_handshake() thread_status = ATOMIC_GET(&(m->thread_state)); if (thread_status == CYC_THREAD_STATE_BLOCKED) { - // Cooperate for the blocked mutator - if (statusc != STATUS_ASYNC) { // TODO: need code to handle this + if (statusc == STATUS_SYNC1) { ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); - if (statusc == STATUS_SYNC1) { - // Async is done, so clean up old mark data from the last collection - pthread_mutex_lock(&(m->lock)); - m->last_write = 0; - m->last_read = 0; - m->pending_writes = 0; - pthread_mutex_unlock(&(m->lock)); - } - // TODO: else if (statusc == STATUS_ASYNC) - /* - take m->lock (also have to handle on mutator, maybe just lock/unlock after exiting prim? but then how to know if async transition happened? does the collector need to set a flag? - */ - } + // Async is done, so clean up old mark data from the last collection + pthread_mutex_lock(&(m->lock)); + m->last_write = 0; + m->last_read = 0; + m->pending_writes = 0; + pthread_mutex_unlock(&(m->lock)); + }else if (statusc == STATUS_SYNC2) { + ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); + } +// TODO: allow collector to cooperate on behalf of a mutator for the async phase +// else if (statusc == STATUS_ASYNC) { +//printf("DEBUG - is mutator still blocked?\n"); +// // Check again, if thread is still blocked we need to cooperate +// if (ATOMIC_SET_IF_EQ(&(m->thread_state), +// CYC_THREAD_STATE_BLOCKED, +// CYC_THREAD_STATE_BLOCKED_COOPERATING)) { +//printf("DEBUG - update mutator GC status\n"); +// ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); +// pthread_mutex_lock(&(m->lock)); +//printf("DEBUG - collector is cooperating for blocked mutator\n"); +// buf_len = gc_minor(m, m->stack_limit, m->stack_start, m->gc_cont, NULL, 0); +// // Mark thread "roots", based on code from mutator's cooperator +// gc_mark_gray(m, m->gc_cont); +// //for (i = 0; i < m->gc_num_args; i++) { +// // gc_mark_gray(m, m->gc_args[i]); +// //} +// // Also, mark everything the collector moved to the heap +// for (i = 0; i < buf_len; i++) { +// gc_mark_gray(m, m->moveBuf[i]); +// } +// m->gc_alloc_color = ATOMIC_GET(&gc_color_mark); +// pthread_mutex_unlock(&(m->lock)); +// } +// } } else if (thread_status == CYC_THREAD_STATE_TERMINATED) { // Thread is no longer running break; @@ -1335,7 +1355,6 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->last_read = 0; thd->mark_buffer_len = 128; thd->mark_buffer = vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len)); - thd->collector_cooperated = 0; if (pthread_mutex_init(&(thd->lock), NULL) != 0) { fprintf(stderr, "Unable to initialize thread mutex\n"); exit(1); @@ -1367,35 +1386,45 @@ void gc_mutator_thread_blocked(gc_thread_data *thd, object cont) CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED); thd->gc_cont = cont; + thd->gc_num_args = 0; // Will be set later, after collection } void gc_mutator_thread_runnable(gc_thread_data *thd, object result) { ATOMIC_SET_IF_EQ(&(thd->thread_state), - CYC_THREAD_STATE_BLOCKED, + CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_RUNNABLE); - if (ATOMIC_GET(&(thd->collector_cooperated))) { -printf("DEBUG - Collector cooperated, wait for it to finish\n"); - // wait for the collector to finish - pthread_mutex_lock(&(thd->lock)); - pthread_mutex_unlock(&(thd->lock)); - // unset async flag - while(!ATOMIC_SET_IF_EQ(&(thd->collector_cooperated), 1, 0)){} - // transport result to heap, if necessary (IE, is not a value type) - if (is_object_type(result)) { - fprintf(stderr, "Unhandled object type result, TODO: implement\n"); - exit(1); - } - // Setup value to send to continuation - thd->gc_args[0] = result; - thd->gc_num_args = 1; - // Whoa. -printf("DEBUG - Call into gc_cont setup by collector\n"); - longjmp(*(thd->jmp_start), 1); - } else { +// // Transition from blocked back to runnable using CAS. +// // If we are unable to transition back, assume collector +// // has cooperated on behalf of this mutator thread. +// if (!ATOMIC_SET_IF_EQ(&(thd->thread_state), +// CYC_THREAD_STATE_BLOCKED, +// CYC_THREAD_STATE_RUNNABLE)){ +//printf("DEBUG - Collector cooperated, wait for it to finish\n"); +// // wait for the collector to finish +// pthread_mutex_lock(&(thd->lock)); +// pthread_mutex_unlock(&(thd->lock)); +// // update thread status +// while(!ATOMIC_SET_IF_EQ(&(thd->thread_state), +// CYC_THREAD_STATE_BLOCKED_COOPERATING, +// CYC_THREAD_STATE_RUNNABLE)){} +// // transport result to heap, if necessary (IE, is not a value type) +// if (is_object_type(result)) { +// // TODO: need to move object to heap +// // TODO: also, then need to gc_mark_gray heap obj +// fprintf(stderr, "Unhandled object type result, TODO: implement\n"); +// exit(1); +// } +// // Setup value to send to continuation +// thd->gc_args[0] = result; +// thd->gc_num_args = 1; +// // Whoa. +//printf("DEBUG - Call into gc_cont after collector coop\n"); +// longjmp(*(thd->jmp_start), 1); +// } else { // Collector didn't do anything; make a normal continuation call (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); - } +// } } //// Unit testing: diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 5a13bec3..44fffc0b 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -53,6 +53,7 @@ typedef void *object; typedef enum { CYC_THREAD_STATE_NEW , CYC_THREAD_STATE_RUNNABLE , CYC_THREAD_STATE_BLOCKED + , CYC_THREAD_STATE_BLOCKED_COOPERATING , CYC_THREAD_STATE_TERMINATED } cyc_thread_state_type; @@ -85,7 +86,6 @@ struct gc_thread_data_t { void **mark_buffer; int mark_buffer_len; pthread_mutex_t lock; - int collector_cooperated; // Data needed for call history char **stack_traces; int stack_trace_idx; From b31c6181c846e3074d8eec463f7e5689266022a4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 01:32:29 -0500 Subject: [PATCH 295/339] Set main thread runnable --- scheme/cyclone/cgen.sld | 1 + 1 file changed, 1 insertion(+) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index c700f525..1e856fbc 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -89,6 +89,7 @@ thd->gc_num_args = 1; gc_add_mutator(thd); Cyc_heap_init(heap_size); + thd->thread_state = CYC_THREAD_STATE_RUNNABLE; Cyc_start_thread(thd); return 0;}") From 43ff5c5454705c91cccf337d642695dac70faa2c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 01:32:40 -0500 Subject: [PATCH 296/339] Re-enable cooperation code --- gc.c | 118 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/gc.c b/gc.c index 7fab30a2..6785fecf 100644 --- a/gc.c +++ b/gc.c @@ -1167,32 +1167,30 @@ void gc_wait_handshake() pthread_mutex_unlock(&(m->lock)); }else if (statusc == STATUS_SYNC2) { ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); - } -// TODO: allow collector to cooperate on behalf of a mutator for the async phase -// else if (statusc == STATUS_ASYNC) { -//printf("DEBUG - is mutator still blocked?\n"); -// // Check again, if thread is still blocked we need to cooperate -// if (ATOMIC_SET_IF_EQ(&(m->thread_state), -// CYC_THREAD_STATE_BLOCKED, -// CYC_THREAD_STATE_BLOCKED_COOPERATING)) { -//printf("DEBUG - update mutator GC status\n"); -// ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); -// pthread_mutex_lock(&(m->lock)); -//printf("DEBUG - collector is cooperating for blocked mutator\n"); -// buf_len = gc_minor(m, m->stack_limit, m->stack_start, m->gc_cont, NULL, 0); -// // Mark thread "roots", based on code from mutator's cooperator -// gc_mark_gray(m, m->gc_cont); -// //for (i = 0; i < m->gc_num_args; i++) { -// // gc_mark_gray(m, m->gc_args[i]); -// //} -// // Also, mark everything the collector moved to the heap -// for (i = 0; i < buf_len; i++) { -// gc_mark_gray(m, m->moveBuf[i]); -// } -// m->gc_alloc_color = ATOMIC_GET(&gc_color_mark); -// pthread_mutex_unlock(&(m->lock)); -// } -// } + } else if (statusc == STATUS_ASYNC) { +printf("DEBUG - is mutator still blocked?\n"); + // Check again, if thread is still blocked we need to cooperate + if (ATOMIC_SET_IF_EQ(&(m->thread_state), + CYC_THREAD_STATE_BLOCKED, + CYC_THREAD_STATE_BLOCKED_COOPERATING)) { +printf("DEBUG - update mutator GC status\n"); + ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); + pthread_mutex_lock(&(m->lock)); +printf("DEBUG - collector is cooperating for blocked mutator\n"); + buf_len = gc_minor(m, m->stack_limit, m->stack_start, m->gc_cont, NULL, 0); + // Mark thread "roots", based on code from mutator's cooperator + gc_mark_gray(m, m->gc_cont); + //for (i = 0; i < m->gc_num_args; i++) { + // gc_mark_gray(m, m->gc_args[i]); + //} + // Also, mark everything the collector moved to the heap + for (i = 0; i < buf_len; i++) { + gc_mark_gray(m, m->moveBuf[i]); + } + m->gc_alloc_color = ATOMIC_GET(&gc_color_mark); + pthread_mutex_unlock(&(m->lock)); + } + } } else if (thread_status == CYC_THREAD_STATE_TERMINATED) { // Thread is no longer running break; @@ -1382,49 +1380,49 @@ void gc_thread_data_free(gc_thread_data *thd) void gc_mutator_thread_blocked(gc_thread_data *thd, object cont) { - ATOMIC_SET_IF_EQ(&(thd->thread_state), + if(!ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, - CYC_THREAD_STATE_BLOCKED); + CYC_THREAD_STATE_BLOCKED)){ + fprintf(stderr, "Unable to change thread from runnable to blocked. status = %d\n", thd->thread_state); + exit(1); + } thd->gc_cont = cont; thd->gc_num_args = 0; // Will be set later, after collection } void gc_mutator_thread_runnable(gc_thread_data *thd, object result) { - ATOMIC_SET_IF_EQ(&(thd->thread_state), - CYC_THREAD_STATE_BLOCKED, - CYC_THREAD_STATE_RUNNABLE); -// // Transition from blocked back to runnable using CAS. -// // If we are unable to transition back, assume collector -// // has cooperated on behalf of this mutator thread. -// if (!ATOMIC_SET_IF_EQ(&(thd->thread_state), -// CYC_THREAD_STATE_BLOCKED, -// CYC_THREAD_STATE_RUNNABLE)){ -//printf("DEBUG - Collector cooperated, wait for it to finish\n"); -// // wait for the collector to finish -// pthread_mutex_lock(&(thd->lock)); -// pthread_mutex_unlock(&(thd->lock)); -// // update thread status -// while(!ATOMIC_SET_IF_EQ(&(thd->thread_state), -// CYC_THREAD_STATE_BLOCKED_COOPERATING, -// CYC_THREAD_STATE_RUNNABLE)){} -// // transport result to heap, if necessary (IE, is not a value type) -// if (is_object_type(result)) { -// // TODO: need to move object to heap -// // TODO: also, then need to gc_mark_gray heap obj -// fprintf(stderr, "Unhandled object type result, TODO: implement\n"); -// exit(1); -// } -// // Setup value to send to continuation -// thd->gc_args[0] = result; -// thd->gc_num_args = 1; -// // Whoa. -//printf("DEBUG - Call into gc_cont after collector coop\n"); -// longjmp(*(thd->jmp_start), 1); -// } else { + // Transition from blocked back to runnable using CAS. + // If we are unable to transition back, assume collector + // has cooperated on behalf of this mutator thread. + if (!ATOMIC_SET_IF_EQ(&(thd->thread_state), + CYC_THREAD_STATE_BLOCKED, + CYC_THREAD_STATE_RUNNABLE)){ +printf("DEBUG - Collector cooperated, wait for it to finish. status is %d\n", thd->thread_state); + // wait for the collector to finish + pthread_mutex_lock(&(thd->lock)); + pthread_mutex_unlock(&(thd->lock)); + // update thread status + while(!ATOMIC_SET_IF_EQ(&(thd->thread_state), + CYC_THREAD_STATE_BLOCKED_COOPERATING, + CYC_THREAD_STATE_RUNNABLE)){} + // transport result to heap, if necessary (IE, is not a value type) + if (is_object_type(result)) { + // TODO: need to move object to heap + // TODO: also, then need to gc_mark_gray heap obj + fprintf(stderr, "Unhandled object type result, TODO: implement\n"); + exit(1); + } + // Setup value to send to continuation + thd->gc_args[0] = result; + thd->gc_num_args = 1; + // Whoa. +printf("DEBUG - Call into gc_cont after collector coop\n"); + longjmp(*(thd->jmp_start), 1); + } else { // Collector didn't do anything; make a normal continuation call (((closure)(thd->gc_cont))->fn)(thd, 1, thd->gc_cont, result); -// } + } } //// Unit testing: From 6ae7a88e53c33a9b12e994c43eb51f59bd2b8fca Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 01:56:00 -0500 Subject: [PATCH 297/339] Bugfix --- gc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gc.c b/gc.c index 6785fecf..e7873a96 100644 --- a/gc.c +++ b/gc.c @@ -1157,24 +1157,24 @@ void gc_wait_handshake() thread_status = ATOMIC_GET(&(m->thread_state)); if (thread_status == CYC_THREAD_STATE_BLOCKED) { - if (statusc == STATUS_SYNC1) { - ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); + if (statusm == STATUS_ASYNC) { // Prev state + ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(m->lock)); m->last_write = 0; m->last_read = 0; m->pending_writes = 0; pthread_mutex_unlock(&(m->lock)); - }else if (statusc == STATUS_SYNC2) { - ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); - } else if (statusc == STATUS_ASYNC) { + }else if (statusm == STATUS_SYNC1) { + ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); + } else if (statusm == STATUS_SYNC2) { printf("DEBUG - is mutator still blocked?\n"); // Check again, if thread is still blocked we need to cooperate if (ATOMIC_SET_IF_EQ(&(m->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING)) { printf("DEBUG - update mutator GC status\n"); - ATOMIC_SET_IF_EQ(&(m->gc_status), statusc, statusm); + ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); pthread_mutex_lock(&(m->lock)); printf("DEBUG - collector is cooperating for blocked mutator\n"); buf_len = gc_minor(m, m->stack_limit, m->stack_start, m->gc_cont, NULL, 0); From 1f21b4688ac243cc919a2b8fdcd7ac4ef8a47ed2 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 02:20:18 -0500 Subject: [PATCH 298/339] WIP --- gc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index e7873a96..2f35151c 100644 --- a/gc.c +++ b/gc.c @@ -1172,7 +1172,14 @@ printf("DEBUG - is mutator still blocked?\n"); // Check again, if thread is still blocked we need to cooperate if (ATOMIC_SET_IF_EQ(&(m->thread_state), CYC_THREAD_STATE_BLOCKED, - CYC_THREAD_STATE_BLOCKED_COOPERATING)) { + CYC_THREAD_STATE_BLOCKED_COOPERATING) +// TODO: seems to work OK for first collection, but then gc is blocked +// again. tried this but there must be another issue... +// || +// ATOMIC_SET_IF_EQ(&(m->thread_state), +// CYC_THREAD_STATE_BLOCKED_COOPERATING, +// CYC_THREAD_STATE_BLOCKED_COOPERATING) + ) { printf("DEBUG - update mutator GC status\n"); ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); pthread_mutex_lock(&(m->lock)); From 680149a066deef7263260d68a9bc6c4b183d5731 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 02:21:16 -0500 Subject: [PATCH 299/339] Suppress unneeded write --- test.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.scm b/test.scm index 27d05fc2..d8a947be 100644 --- a/test.scm +++ b/test.scm @@ -25,7 +25,7 @@ ;(write tmp) (cond ((> (length tmp) 1000) - (write "resetting tmp") + ;(write "resetting tmp") (set! tmp '())) (else #f)) (loop)))) From e7e8cbd744610dea5e3bdb88f0532f8a86403dd9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 24 Dec 2015 02:21:48 -0500 Subject: [PATCH 300/339] Prevent being overwritten by test.scm compilation --- test.c => test-ck.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test.c => test-ck.c (100%) diff --git a/test.c b/test-ck.c similarity index 100% rename from test.c rename to test-ck.c From eaac66ab37a92ef5111018dcabeed6e69b2c969c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 22:09:10 -0500 Subject: [PATCH 301/339] WIP --- gc.c | 13 ++++++------- runtime.c | 11 +++++++++-- test.scm | 1 + 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/gc.c b/gc.c index 2f35151c..9b7a3544 100644 --- a/gc.c +++ b/gc.c @@ -1156,7 +1156,8 @@ void gc_wait_handshake() } thread_status = ATOMIC_GET(&(m->thread_state)); - if (thread_status == CYC_THREAD_STATE_BLOCKED) { + if (thread_status == CYC_THREAD_STATE_BLOCKED || + thread_status == CYC_THREAD_STATE_BLOCKED_COOPERATING) { if (statusm == STATUS_ASYNC) { // Prev state ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); // Async is done, so clean up old mark data from the last collection @@ -1173,12 +1174,10 @@ printf("DEBUG - is mutator still blocked?\n"); if (ATOMIC_SET_IF_EQ(&(m->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING) -// TODO: seems to work OK for first collection, but then gc is blocked -// again. tried this but there must be another issue... -// || -// ATOMIC_SET_IF_EQ(&(m->thread_state), -// CYC_THREAD_STATE_BLOCKED_COOPERATING, -// CYC_THREAD_STATE_BLOCKED_COOPERATING) + || + ATOMIC_SET_IF_EQ(&(m->thread_state), + CYC_THREAD_STATE_BLOCKED_COOPERATING, + CYC_THREAD_STATE_BLOCKED_COOPERATING) ) { printf("DEBUG - update mutator GC status\n"); ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); diff --git a/runtime.c b/runtime.c index 5aefa20d..f76bfe83 100644 --- a/runtime.c +++ b/runtime.c @@ -2157,10 +2157,17 @@ void gc_mark_globals() char *gc_fixup_moved_obj(gc_thread_data *thd, int *alloci, char *obj, object hp) { + int acquired_lock = 0; if (grayed(obj)) { - pthread_mutex_lock(&(thd->lock)); + // Try to acquire the lock, because we are already locked if + // the collector is cooperating on behalf of the mutator + if (pthread_mutex_trylock(&(thd->lock)) == 0) { + acquired_lock = 1; + } gc_mark_gray2(thd, hp); - pthread_mutex_unlock(&(thd->lock)); + if (acquired_lock){ + pthread_mutex_unlock(&(thd->lock)); + } } // hp ==> new heap object, point to it from old stack object diff --git a/test.scm b/test.scm index d8a947be..5a606379 100644 --- a/test.scm +++ b/test.scm @@ -32,6 +32,7 @@ (loop)) ))) (read) +(write "main thread is done") ;;;; A temporary file to attempt to repro crashing / data corruption ;;(import (scheme base) (scheme write)) From e24da010bd7829680651a9b71d40d618be45ef47 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 22:35:03 -0500 Subject: [PATCH 302/339] Added notes --- gc-notes.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 236ae53e..ad2de7a3 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -12,7 +12,15 @@ TODO: - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc + next steps: + - add mutex type, and associated functions from SRFI-18 + - break out srfi 18 stuff into a (scheme srfi 18) module, or such + - start making core stuff thread safe. for example, test.scm sometimes + crashes, I think printing out result from (read) + - assume I/O and eval both have threading issues + +DONE: - need to cooperate when a mutator is blocked IMPLEMENTATION NOTES: From deae1693d597a88694776fa9720f804c60932707 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 23 Dec 2015 23:02:38 -0500 Subject: [PATCH 303/339] Updated header comments --- gc.c | 12 ++++++++---- runtime.c | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index 9b7a3544..d8a8fbc1 100644 --- a/gc.c +++ b/gc.c @@ -1,13 +1,17 @@ /** * Cyclone Scheme - * Copyright (c) 2015, Justin Ethier + * Copyright (c) 2015-2016, Justin Ethier * All rights reserved. * - * Primary garbage collector used by the Cyclone runtime. - * Based on the tracing GC algorithm from: - * "Implementing an on-the-fly garbage collector for Java", by Domani et al. + * Heap garbage collector used by the Cyclone runtime for major collections. + * + * Tracing GC algorithm is based on the one from "Implementing an on-the-fly + * garbage collector for Java", by Domani et al. * * The heap implementation (alloc / sweep, etc) is based on code from Chibi Scheme. + * + * Note there is also a minor GC (in runtime.c) that collects objects allocated + * on the stack, based on "Cheney on the MTA" (but without the copying collector). */ #include diff --git a/runtime.c b/runtime.c index f76bfe83..4c75f091 100644 --- a/runtime.c +++ b/runtime.c @@ -1,6 +1,6 @@ /** * Cyclone Scheme - * Copyright (c) 2014, Justin Ethier + * Copyright (c) 2014-2016, Justin Ethier * All rights reserved. * * This file contains the C runtime used by compiled programs. From 7db26c7d8c2d6db3e0b1b7b527f6f3b0bee3c872 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 26 Dec 2015 23:26:07 -0500 Subject: [PATCH 304/339] Relocated threading functions --- scheme/base.sld | 41 ----------------------------------------- srfi/18.sld | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 41 deletions(-) create mode 100644 srfi/18.sld diff --git a/scheme/base.sld b/scheme/base.sld index e3e06797..2f5d1b6f 100644 --- a/scheme/base.sld +++ b/scheme/base.sld @@ -1,16 +1,5 @@ (define-library (scheme base) (export - ;; Thread functions. these are not standard, and may be relocated - ;; TODO: relocate to (scheme srfi 18) or such - thread? - make-thread - thread-name - thread-specific - thread-specific-set! - thread-start! - thread-yield! -; thread-terminate! - ;; END threads ; TODO: need filter for the next two. also, they really belong in SRFI-1, not here ;delete ;delete-duplicates @@ -657,34 +646,4 @@ (else #f)))) - ;; Threading - (define (thread? obj) - (and (vector? obj) - (> (vector-length obj) 0) - (equal? 'cyc-thread-obj (vector-ref obj 0)))) - - (define (make-thread thunk . name) - (let ((name-str (if (pair? name) - (car name) - ""))) - ;; Fields supported so far: - ;; - type marker (implementation-specific) - ;; - thunk - ;; - internal thread id (implementation-specific) - ;; - name - ;; - specific - (vector 'cyc-thread-obj thunk #f name-str #f))) - - (define (thread-name t) (vector-ref t 3)) - (define (thread-specific t) (vector-ref t 4)) - (define (thread-specific-set! t obj) (vector-set! t 4 obj)) -; TODO: -; current-thread - not sure how to look this up yet... may need a global list of running threads - (define (thread-start! t) - (let* ((thunk (vector-ref t 1)) - (mutator-id (Cyc-spawn-thread! thunk))) - (vector-set! t 2 mutator-id))) - (define (thread-yield!) (thread-sleep! 1)) -; (define (thread-terminate!) (Cyc-end-thread!)) - ;; TODO: thread-join! )) diff --git a/srfi/18.sld b/srfi/18.sld new file mode 100644 index 00000000..5fc18bf1 --- /dev/null +++ b/srfi/18.sld @@ -0,0 +1,43 @@ +(define-library (srfi 18) + (export + thread? + make-thread + thread-name + thread-specific + thread-specific-set! + thread-start! + thread-yield! +; thread-terminate! + ) + (begin + ;; Threading + (define (thread? obj) + (and (vector? obj) + (> (vector-length obj) 0) + (equal? 'cyc-thread-obj (vector-ref obj 0)))) + + (define (make-thread thunk . name) + (let ((name-str (if (pair? name) + (car name) + ""))) + ;; Fields supported so far: + ;; - type marker (implementation-specific) + ;; - thunk + ;; - internal thread id (implementation-specific) + ;; - name + ;; - specific + (vector 'cyc-thread-obj thunk #f name-str #f))) + + (define (thread-name t) (vector-ref t 3)) + (define (thread-specific t) (vector-ref t 4)) + (define (thread-specific-set! t obj) (vector-set! t 4 obj)) +; TODO: +; current-thread - not sure how to look this up yet... may need a global list of running threads + (define (thread-start! t) + (let* ((thunk (vector-ref t 1)) + (mutator-id (Cyc-spawn-thread! thunk))) + (vector-set! t 2 mutator-id))) + (define (thread-yield!) (thread-sleep! 1)) +; (define (thread-terminate!) (Cyc-end-thread!)) + ;; TODO: thread-join! +)) From 40ba493ac32e8ef9f61b7651fe702778c53505a5 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 26 Dec 2015 23:37:28 -0500 Subject: [PATCH 305/339] Integrating with new module --- Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2651d8bc..709679ad 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ SMODULES = \ scheme/cyclone/libraries \ scheme/cyclone/macros \ scheme/cyclone/transforms \ - scheme/cyclone/util + scheme/cyclone/util \ + srfi/18 SLDFILES = $(addsuffix .sld, $(SMODULES)) COBJECTS=$(SLDFILES:.sld=.o) @@ -60,6 +61,7 @@ libcyclone.a: runtime.c include/cyclone/runtime.h include/cyclone/types.h gc.c d bootstrap: icyc # rm -rf $(BOOTSTRAP_DIR) mkdir -p $(BOOTSTRAP_DIR)/scheme/cyclone + mkdir -p $(BOOTSTRAP_DIR)/srfi mkdir -p $(BOOTSTRAP_DIR)/include/cyclone cp include/cyclone/types.h $(BOOTSTRAP_DIR)/include/cyclone cp include/cyclone/runtime-main.h $(BOOTSTRAP_DIR)/include/cyclone @@ -67,6 +69,7 @@ bootstrap: icyc cp include/cyclone/ck_ht_hash.h $(BOOTSTRAP_DIR)/include/cyclone cp scheme/*.sld $(BOOTSTRAP_DIR)/scheme cp scheme/cyclone/*.sld $(BOOTSTRAP_DIR)/scheme/cyclone + cp srfi/*.sld $(BOOTSTRAP_DIR)/srfi cp runtime.c $(BOOTSTRAP_DIR) cp gc.c $(BOOTSTRAP_DIR) cp dispatch.c $(BOOTSTRAP_DIR) @@ -84,6 +87,7 @@ bootstrap: icyc cp scheme/cyclone/transforms.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/cgen.c $(BOOTSTRAP_DIR)/scheme/cyclone cp scheme/cyclone/util.c $(BOOTSTRAP_DIR)/scheme/cyclone + cp srfi/18.c $(BOOTSTRAP_DIR)/srfi cp cyclone.c $(BOOTSTRAP_DIR)/cyclone.c cp Makefile.config $(BOOTSTRAP_DIR)/Makefile.config @@ -98,7 +102,7 @@ tags: .PHONY: clean clean: - rm -rf a.out *.o *.so *.a *.out tags cyclone icyc scheme/*.o scheme/*.c scheme/*.meta scheme/cyclone/*.o scheme/cyclone/*.c scheme/cyclone/*.meta cyclone.c dispatch.c icyc.c generate-c.c generate-c + rm -rf a.out *.o *.so *.a *.out tags cyclone icyc scheme/*.o scheme/*.c scheme/*.meta srfi/*.o scheme/cyclone/*.o scheme/cyclone/*.c scheme/cyclone/*.meta cyclone.c dispatch.c icyc.c generate-c.c generate-c $(foreach f,$(TESTSCM), rm -rf $(f) $(f).c tests/$(f).c;) install-includes: @@ -122,12 +126,15 @@ install: $(MKDIR) $(DESTDIR)$(INCDIR) $(MKDIR) $(DESTDIR)$(DATADIR) $(MKDIR) $(DESTDIR)$(DATADIR)/scheme/cyclone + $(MKDIR) $(DESTDIR)$(DATADIR)/srfi $(INSTALL) -m0644 libcyclone.a $(DESTDIR)$(LIBDIR)/ $(INSTALL) -m0644 include/cyclone/*.h $(DESTDIR)$(INCDIR)/ $(INSTALL) -m0644 scheme/*.sld $(DESTDIR)$(DATADIR)/scheme $(INSTALL) -m0644 scheme/*.o $(DESTDIR)$(DATADIR)/scheme $(INSTALL) -m0644 scheme/cyclone/*.sld $(DESTDIR)$(DATADIR)/scheme/cyclone $(INSTALL) -m0644 scheme/cyclone/*.o $(DESTDIR)$(DATADIR)/scheme/cyclone + $(INSTALL) -m0644 srfi/*.sld $(DESTDIR)$(DATADIR)/srfi + $(INSTALL) -m0644 srfi/*.o $(DESTDIR)$(DATADIR)/srfi $(INSTALL) -m0755 cyclone $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 icyc $(DESTDIR)$(BINDIR)/ @@ -139,6 +146,8 @@ uninstall: $(RMDIR) $(DESTDIR)$(INCDIR) $(RM) $(DESTDIR)$(DATADIR)/scheme/cyclone/*.* $(RMDIR) $(DESTDIR)$(DATADIR)/scheme/cyclone + $(RM) $(DESTDIR)$(DATADIR)/srfi/*.* + $(RMDIR) $(DESTDIR)$(DATADIR)/srfi $(RM) $(DESTDIR)$(DATADIR)/scheme/*.* $(RMDIR) $(DESTDIR)$(DATADIR)/scheme $(RMDIR) $(DESTDIR)$(DATADIR) From 167d26adbb2a24df38230acc3b1eebdee28ea31a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 26 Dec 2015 23:48:45 -0500 Subject: [PATCH 306/339] Handle lib names with numbers in them --- scheme/cyclone/libraries.sld | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scheme/cyclone/libraries.sld b/scheme/cyclone/libraries.sld index 5992af23..047b98a6 100644 --- a/scheme/cyclone/libraries.sld +++ b/scheme/cyclone/libraries.sld @@ -43,7 +43,14 @@ (define (library? ast) (tagged-list? 'define-library ast)) -(define (lib:name ast) (cadr ast)) +(define (lib:name ast) + (map + (lambda (atom) + (cond + ((number? atom) + (string->symbol (number->string atom))) + (else atom))) + (cadr ast))) ;; Convert name (as list of symbols) to a mangled string (define (lib:name->string name) From 151a09386e1d90e23787cc8f3c4421c3cb421e09 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 26 Dec 2015 23:49:41 -0500 Subject: [PATCH 307/339] Added import base --- srfi/18.sld | 1 + 1 file changed, 1 insertion(+) diff --git a/srfi/18.sld b/srfi/18.sld index 5fc18bf1..2ea957c9 100644 --- a/srfi/18.sld +++ b/srfi/18.sld @@ -1,4 +1,5 @@ (define-library (srfi 18) + (import (scheme base)) (export thread? make-thread From 11b479f3799bf0ceae15f29ae7ffa7a2881a834c Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 26 Dec 2015 23:55:16 -0500 Subject: [PATCH 308/339] Use new import. But there is another number/symbol issue --- test.scm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test.scm b/test.scm index 5a606379..a7b84bd9 100644 --- a/test.scm +++ b/test.scm @@ -1,6 +1,7 @@ (import (scheme base) (scheme read) - (scheme write)) + (scheme write) + (srfi 18)) ;; Spawn off a thread ;(let ((t (thread-start! (make-thread (lambda () (write 'a)))))) From e8186fb6fe3ca8983225ec8f4456267e2aa6b784 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 27 Dec 2015 22:04:51 -0500 Subject: [PATCH 309/339] Added function to normalize import set lists --- scheme/cyclone/libraries.sld | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scheme/cyclone/libraries.sld b/scheme/cyclone/libraries.sld index 047b98a6..a2a80968 100644 --- a/scheme/cyclone/libraries.sld +++ b/scheme/cyclone/libraries.sld @@ -19,6 +19,7 @@ ) (export library? + lib:list->import-set lib:name lib:name->string lib:name->symbol @@ -43,14 +44,19 @@ (define (library? ast) (tagged-list? 'define-library ast)) -(define (lib:name ast) +;; Convert a raw list to an import set. For example, a list might be +;; (srfi 18) containing the number 18. An import set contains only symbols. +(define (lib:list->import-set lis) (map (lambda (atom) (cond ((number? atom) (string->symbol (number->string atom))) (else atom))) - (cadr ast))) + lis)) + +(define (lib:name ast) + (lib:list->import-set (cadr ast))) ;; Convert name (as list of symbols) to a mangled string (define (lib:name->string name) @@ -210,7 +216,7 @@ (find-deps! deps) )))) import-set)))) - (find-deps! imports) + (find-deps! (lib:list->import-set imports)) ;`((deps ,libraries/deps) ; DEBUG ; (result ,(lib:get-dep-list libraries/deps))) (lib:get-dep-list libraries/deps) From 3f0306c404b037683b994a2593a99f678eca7799 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 27 Dec 2015 22:41:52 -0500 Subject: [PATCH 310/339] Handle import-sets that contain numbers --- scheme/cyclone/libraries.sld | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/scheme/cyclone/libraries.sld b/scheme/cyclone/libraries.sld index a2a80968..394a850e 100644 --- a/scheme/cyclone/libraries.sld +++ b/scheme/cyclone/libraries.sld @@ -83,7 +83,7 @@ (define (lib:imports ast) (lib:result (let ((code (assoc 'import (cddr ast)))) - (if code (cdr code) #f)))) + (if code (lib:list->import-set (cdr code)) #f)))) (define (lib:body ast) (lib:result (let ((code (assoc 'begin (cddr ast)))) @@ -99,6 +99,15 @@ ;; TODO: include-ci, cond-expand +(define (lib:atom->string atom) + (cond + ((symbol? atom) + (symbol->string atom)) + ((number? atom) + (number->string atom)) + (else + (error "Unexpected type in import set")))) + ;; Resolve library filename given an import. ;; Assumes ".sld" file extension if one is not specified. (define (lib:import->filename import . ext) @@ -112,7 +121,7 @@ string-append (map (lambda (i) - (string-append "/" (symbol->string i))) + (string-append "/" (lib:atom->string i))) import)) file-ext)) (filename @@ -129,7 +138,7 @@ string-append (map (lambda (i) - (string-append (symbol->string i) "/")) + (string-append (lib:atom->string i) "/")) import-path)))) (if (tagged-list? 'scheme import) (string-append (Cyc-installation-dir 'sld) "/" path) ;; Built-in library @@ -177,7 +186,7 @@ (map (lambda (import) (lib:import->export-list import)) - imports))) + (lib:list->import-set imports)))) (define (lib:import->metalist import) (let ((file (lib:import->filename import ".meta")) @@ -204,19 +213,20 @@ (define (lib:get-all-import-deps imports) (letrec ((libraries/deps '()) (find-deps! - (lambda (import-set) + (lambda (import-sets) (for-each (lambda (i) - (cond - ;; Prevent cycles by only processing new libraries - ((not (assoc i libraries/deps)) - ;; Find all dependencies of i (IE, libraries it imports) - (let ((deps (lib:read-imports i))) - (set! libraries/deps (cons (cons i deps) libraries/deps)) - (find-deps! deps) - )))) - import-set)))) - (find-deps! (lib:list->import-set imports)) + (let ((import-set (lib:list->import-set i))) + (cond + ;; Prevent cycles by only processing new libraries + ((not (assoc import-set libraries/deps)) + ;; Find all dependencies of i (IE, libraries it imports) + (let ((deps (lib:read-imports import-set))) + (set! libraries/deps (cons (cons import-set deps) libraries/deps)) + (find-deps! deps) + ))))) + import-sets)))) + (find-deps! imports) ;`((deps ,libraries/deps) ; DEBUG ; (result ,(lib:get-dep-list libraries/deps))) (lib:get-dep-list libraries/deps) From eaa0481f4083d57d544da5751673ae36ff395541 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 27 Dec 2015 23:16:58 -0500 Subject: [PATCH 311/339] Added Cyc-minor-gc --- include/cyclone/runtime.h | 2 ++ runtime.c | 15 +++++++++++++-- scheme/cyclone/cgen.sld | 8 ++++++-- scheme/cyclone/transforms.sld | 2 ++ scheme/eval.sld | 1 + 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 2e92bdf4..ae602353 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -192,6 +192,7 @@ void Cyc_end_thread(gc_thread_data *thd); void Cyc_exit_thread(gc_thread_data *thd); object Cyc_thread_sleep(void *data, object timeout); void GC(void *,closure,object*,int); +object Cyc_trigger_minor_gc(void *data, object cont); void Cyc_st_add(void *data, char *frame); void Cyc_st_print(void *data, FILE *out); @@ -231,6 +232,7 @@ extern const object primitive_Cyc_91has_91cycle_127; extern const object primitive_Cyc_91spawn_91thread_67; extern const object primitive_Cyc_91end_91thread_67; extern const object primitive_thread_91sleep_67; +extern const object primitive_Cyc_91minor_91gc; extern const object primitive__87; extern const object primitive__91; extern const object primitive__85; diff --git a/runtime.c b/runtime.c index 4c75f091..241cec09 100644 --- a/runtime.c +++ b/runtime.c @@ -1730,6 +1730,8 @@ void _Cyc_91end_91thread_67(void *data, object cont, object args) { void _thread_91sleep_67(void *data, object cont, object args) { Cyc_check_num_args(data, "thread-sleep!", 1, args); return_closcall1(data, cont, Cyc_thread_sleep(data, car(args))); } +void _Cyc_91minor_91gc_primitive(void *data, object cont, object args){ + Cyc_trigger_minor_gc(data, cont); } void __87(void *data, object cont, object args) { integer_type argc = Cyc_length(data, args); dispatch(data, argc.value, (function_type)dispatch_sum, cont, cont, args); } @@ -2265,6 +2267,13 @@ char *gc_move(char *obj, gc_thread_data *thd, int *alloci, int *heap_grown) { } \ } +object Cyc_trigger_minor_gc(void *data, object cont) { + gc_thread_data* thd = (gc_thread_data *)data; + thd->gc_args = boolean_t; + GC(data, cont, thd->gc_args, 1); + return nil; +} + // Do a minor GC int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args) { @@ -2399,9 +2408,9 @@ void GC(void *data, closure cont, object *args, int num_args) int alloci = gc_minor(data, low_limit, high_limit, cont, args, num_args); // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data, alloci); -#if GC_DEBUG_TRACE +//#if GC_DEBUG_TRACE fprintf(stderr, "done with minor GC\n"); -#endif +//#endif // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } @@ -2537,6 +2546,7 @@ static primitive_type Cyc_91has_91cycle_127_primitive = {{0}, primitive_tag, "Cy static primitive_type Cyc_91spawn_91thread_67_primitive = {{0}, primitive_tag, "Cyc-spawn-thread!", &_Cyc_91spawn_91thread_67}; static primitive_type Cyc_91end_91thread_67_primitive = {{0}, primitive_tag, "Cyc-end-thread!", &_Cyc_91end_91thread_67}; static primitive_type thread_91sleep_67_primitive = {{0}, primitive_tag, "thread-sleep!", &_thread_91sleep_67}; +static primitive_type Cyc_91minor_91gc_primitive = {{0}, primitive_tag, "Cyc-minor-gc", &_Cyc_91minor_91gc_primitive}; static primitive_type _87_primitive = {{0}, primitive_tag, "+", &__87}; static primitive_type _91_primitive = {{0}, primitive_tag, "-", &__91}; static primitive_type _85_primitive = {{0}, primitive_tag, "*", &__85}; @@ -2657,6 +2667,7 @@ const object primitive_Cyc_91has_91cycle_127 = &Cyc_91has_91cycle_127_primitive; const object primitive_Cyc_91spawn_91thread_67 = &Cyc_91spawn_91thread_67_primitive; const object primitive_Cyc_91end_91thread_67 = &Cyc_91end_91thread_67_primitive; const object primitive_thread_91sleep_67 = &thread_91sleep_67_primitive; +const object primitive_Cyc_91minor_91gc = &Cyc_91minor_91gc_primitive; const object primitive__87 = &_87_primitive; const object primitive__91 = &_91_primitive; const object primitive__85 = &_85_primitive; diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 1e856fbc..c700f468 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -535,6 +535,7 @@ ((eq? p 'substring) "Cyc_substring") ((eq? p 'Cyc-installation-dir) "Cyc_installation_dir") ((eq? p 'command-line-arguments) "Cyc_command_line_arguments") + ((eq? p 'Cyc-minor-gc) "Cyc_trigger_minor_gc") ((eq? p 'system) "Cyc_system") ((eq? p 'assq) "assq") ((eq? p 'assv) "assq") @@ -617,6 +618,7 @@ substring Cyc-installation-dir command-line-arguments + Cyc-minor-gc assq assv assoc @@ -655,6 +657,7 @@ ((eq? p 'read-char) "object") ((eq? p 'peek-char) "object") ((eq? p 'command-line-arguments) "object") + ((eq? p 'Cyc-minor-gc) "object") ((eq? p 'number->string) "object") ((eq? p 'symbol->string) "object") ((eq? p 'substring) "object") @@ -683,6 +686,7 @@ string-length substring + - * / apply command-line-arguments + Cyc-minor-gc Cyc-read-line read-char peek-char cons length vector-length cell)))) @@ -690,7 +694,7 @@ ;; Pass continuation as the function's first parameter? (define (prim:cont? exp) (and (prim? exp) - (member exp '(Cyc-read-line apply command-line-arguments number->string + (member exp '(Cyc-read-line apply command-line-arguments Cyc-minor-gc number->string read-char peek-char symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) @@ -698,7 +702,7 @@ ;; Primitive functions that pass a continuation but have no other arguments (define (prim:cont/no-args? exp) (and (prim? exp) - (member exp '(command-line-arguments)))) + (member exp '(command-line-arguments Cyc-minor-gc)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index 290630e3..d8219d7c 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -454,6 +454,7 @@ Cyc-spawn-thread! Cyc-end-thread! thread-sleep! + Cyc-minor-gc Cyc-stdout Cyc-stdin Cyc-stderr @@ -560,6 +561,7 @@ Cyc-spawn-thread! Cyc-end-thread! thread-sleep! + Cyc-minor-gc apply %halt exit diff --git a/scheme/eval.sld b/scheme/eval.sld index 2171b490..9c3f64e3 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -156,6 +156,7 @@ (list 'Cyc-installation-dir Cyc-installation-dir) (list 'system system) (list 'command-line-arguments command-line-arguments) + (list 'Cyc-minor-gc Cyc-minor-gc) (list 'error error) (list 'cons cons) (list 'cell-get cell-get) From a15f7057b96dc1e836b72f1ec4843b00d2074b1f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 27 Dec 2015 23:21:28 -0500 Subject: [PATCH 312/339] Added notes --- gc-notes.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index ad2de7a3..638af854 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -14,7 +14,8 @@ TODO: part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc next steps: - add mutex type, and associated functions from SRFI-18 - - break out srfi 18 stuff into a (scheme srfi 18) module, or such + when allocating a mutex, probably should do it on thread since by definition these are + shared among multiple threads - start making core stuff thread safe. for example, test.scm sometimes crashes, I think printing out result from (read) - assume I/O and eval both have threading issues From ccc7c2dcd3b3add75fd8026622983962a3e9855f Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 04:49:58 +0000 Subject: [PATCH 313/339] Added notes on ARM support --- gc-notes.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 638af854..764b7a51 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -7,6 +7,14 @@ Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) TODO: +- create a branch and try to use CK atomics. goals: + - make sure this is stable on x86 (first priority) + - see if this will build/work on ARM + - rename SET to CAS (compare and swap) + - anything else? + - This is higher priority than mutexes (though not by much), because we want cyclone to work on both ARM and x86. + + - bring exceptions into local thread data? anything else? also, will probably need to lock shared resources such as I/O... From fa72a604fb3a4466061c94605672cb4718a8fb15 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 04:51:20 +0000 Subject: [PATCH 314/339] Test --- gc-notes.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index 764b7a51..7b8d10cb 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -14,7 +14,6 @@ TODO: - anything else? - This is higher priority than mutexes (though not by much), because we want cyclone to work on both ARM and x86. - - bring exceptions into local thread data? anything else? also, will probably need to lock shared resources such as I/O... From 71af17d7e728ab51374c8e248da3367e04cf3968 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 22:05:07 -0500 Subject: [PATCH 315/339] Use atomic operations from libck --- gc.c | 71 +++++++++++++++++++++-------------------- include/cyclone/types.h | 9 ------ runtime.c | 9 +++--- 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/gc.c b/gc.c index d8a8fbc1..cc6532ea 100644 --- a/gc.c +++ b/gc.c @@ -15,6 +15,7 @@ */ #include +#include #include "cyclone/types.h" #include @@ -773,9 +774,9 @@ heap references, so they can be marked to avoid collection. */ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) { - int status = ATOMIC_GET(&gc_status_col), - stage = ATOMIC_GET(&gc_stage); - if (ATOMIC_GET(&(thd->gc_status)) != STATUS_ASYNC) { + int status = ck_pr_load_int(&gc_status_col), + stage = ck_pr_load_int(&gc_stage); + if (ck_pr_load_int(&(thd->gc_status)) != STATUS_ASYNC) { //fprintf(stderr, "DEBUG - GC sync marking heap obj %p ", old_obj); //Cyc_display(old_obj, stderr); //fprintf(stderr, " and new value %p ", value); @@ -856,10 +857,10 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) // a race condition // // TODO: should use an atomic comparison here - status_c = ATOMIC_GET(&gc_status_col); - status_m = ATOMIC_GET(&(thd->gc_status)); + status_c = ck_pr_load_int(&gc_status_col); + status_m = ck_pr_load_int(&(thd->gc_status)); if (status_m != status_c) { - ATOMIC_SET_IF_EQ(&(thd->gc_status), status_m, status_c); + ck_pr_cas_int(&(thd->gc_status), status_m, status_c); if (status_m == STATUS_ASYNC) { // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(thd->lock)); @@ -885,7 +886,7 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) gc_mark_gray(thd, thd->moveBuf[i]); } pthread_mutex_unlock(&(thd->lock)); - thd->gc_alloc_color = ATOMIC_GET(&gc_color_mark); + thd->gc_alloc_color = ck_pr_load_int(&gc_color_mark); } } #if GC_DEBUG_VERBOSE @@ -903,12 +904,12 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) // Initiate collection cycle if free space is too low. // Threshold is intentially low because we have to go through an // entire handshake/trace/sweep cycle, ideally without growing heap. - if (ATOMIC_GET(&gc_stage) == STAGE_RESTING && + if (ck_pr_load_int(&gc_stage) == STAGE_RESTING && (cached_heap_free_size < (cached_heap_total_size * 0.50))){ #if GC_DEBUG_TRACE fprintf(stdout, "Less than 50%% of the heap is free, initiating collector\n"); #endif - ATOMIC_SET_IF_EQ(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); + ck_pr_cas_int(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); } } @@ -1034,7 +1035,7 @@ void gc_mark_black(object obj) // TODO: is sync required to get colors? probably not on the collector // thread (at least) since colors are only changed once during the clear // phase and before the first handshake. - int markColor = ATOMIC_GET(&gc_color_mark); + int markColor = ck_pr_load_int(&gc_color_mark); if (is_object_type(obj) && mark(obj) != markColor) { // Gray any child objects // Note we probably should use some form of atomics/synchronization @@ -1136,8 +1137,8 @@ void gc_handshake(gc_status_type s) void gc_post_handshake(gc_status_type s) { - int status = ATOMIC_GET(&gc_status_col); - while (!ATOMIC_SET_IF_EQ(&gc_status_col, status, s)){} + int status = ck_pr_load_int(&gc_status_col); + while (!ck_pr_cas_int(&gc_status_col, status, s)){} } void gc_wait_handshake() @@ -1152,18 +1153,18 @@ void gc_wait_handshake() CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) { while (1) { // TODO: use an atomic comparison - statusc = ATOMIC_GET(&gc_status_col); - statusm = ATOMIC_GET(&(m->gc_status)); + statusc = ck_pr_load_int(&gc_status_col); + statusm = ck_pr_load_int(&(m->gc_status)); if (statusc == statusm) { // Handshake succeeded, check next mutator break; } - thread_status = ATOMIC_GET(&(m->thread_state)); + thread_status = ck_pr_load_int((int *)&(m->thread_state)); if (thread_status == CYC_THREAD_STATE_BLOCKED || thread_status == CYC_THREAD_STATE_BLOCKED_COOPERATING) { if (statusm == STATUS_ASYNC) { // Prev state - ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); + ck_pr_cas_int(&(m->gc_status), statusm, statusc); // Async is done, so clean up old mark data from the last collection pthread_mutex_lock(&(m->lock)); m->last_write = 0; @@ -1171,20 +1172,20 @@ void gc_wait_handshake() m->pending_writes = 0; pthread_mutex_unlock(&(m->lock)); }else if (statusm == STATUS_SYNC1) { - ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); + ck_pr_cas_int(&(m->gc_status), statusm, statusc); } else if (statusm == STATUS_SYNC2) { printf("DEBUG - is mutator still blocked?\n"); // Check again, if thread is still blocked we need to cooperate - if (ATOMIC_SET_IF_EQ(&(m->thread_state), + if (ck_pr_cas_int((int *)&(m->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING) || - ATOMIC_SET_IF_EQ(&(m->thread_state), + ck_pr_cas_int((int *)&(m->thread_state), CYC_THREAD_STATE_BLOCKED_COOPERATING, CYC_THREAD_STATE_BLOCKED_COOPERATING) ) { printf("DEBUG - update mutator GC status\n"); - ATOMIC_SET_IF_EQ(&(m->gc_status), statusm, statusc); + ck_pr_cas_int(&(m->gc_status), statusm, statusc); pthread_mutex_lock(&(m->lock)); printf("DEBUG - collector is cooperating for blocked mutator\n"); buf_len = gc_minor(m, m->stack_limit, m->stack_start, m->gc_cont, NULL, 0); @@ -1197,7 +1198,7 @@ printf("DEBUG - collector is cooperating for blocked mutator\n"); for (i = 0; i < buf_len; i++) { gc_mark_gray(m, m->moveBuf[i]); } - m->gc_alloc_color = ATOMIC_GET(&gc_color_mark); + m->gc_alloc_color = ck_pr_load_int(&gc_color_mark); pthread_mutex_unlock(&(m->lock)); } } @@ -1233,12 +1234,12 @@ void gc_collector() time_t sweep_start = time(NULL); #endif //clear : - ATOMIC_SET_IF_EQ(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); + ck_pr_cas_int(&gc_stage, STAGE_RESTING, STAGE_CLEAR_OR_MARKING); // exchange values of markColor and clearColor - old_clear = ATOMIC_GET(&gc_color_clear); - old_mark = ATOMIC_GET(&gc_color_mark); - while(!ATOMIC_SET_IF_EQ(&gc_color_clear, old_clear, old_mark)){} - while(!ATOMIC_SET_IF_EQ(&gc_color_mark, old_mark, old_clear)){} + old_clear = ck_pr_load_int(&gc_color_clear); + old_mark = ck_pr_load_int(&gc_color_mark); + while(!ck_pr_cas_int(&gc_color_clear, old_clear, old_mark)){} + while(!ck_pr_cas_int(&gc_color_mark, old_mark, old_clear)){} #if GC_DEBUG_TRACE fprintf(stderr, "DEBUG - swap clear %d / mark %d\n", gc_color_clear, gc_color_mark); #endif @@ -1251,7 +1252,7 @@ fprintf(stderr, "DEBUG - after handshake sync 1\n"); #if GC_DEBUG_TRACE fprintf(stderr, "DEBUG - after handshake sync 2\n"); #endif - ATOMIC_SET_IF_EQ(&gc_stage, STAGE_CLEAR_OR_MARKING, STAGE_TRACING); + ck_pr_cas_int(&gc_stage, STAGE_CLEAR_OR_MARKING, STAGE_TRACING); gc_post_handshake(STATUS_ASYNC); #if GC_DEBUG_TRACE fprintf(stderr, "DEBUG - after post_handshake async\n"); @@ -1267,7 +1268,7 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); fprintf(stderr, "DEBUG - after trace\n"); //debug_dump_globals(); #endif - ATOMIC_SET_IF_EQ(&gc_stage, STAGE_TRACING, STAGE_SWEEPING); + ck_pr_cas_int(&gc_stage, STAGE_TRACING, STAGE_SWEEPING); // //sweep : max_freed = gc_sweep(gc_get_heap(), &freed); @@ -1291,7 +1292,7 @@ fprintf(stderr, "DEBUG - after wait_handshake async\n"); #endif gc_free_old_thread_data(); // Idle the GC thread - ATOMIC_SET_IF_EQ(&gc_stage, STAGE_SWEEPING, STAGE_RESTING); + ck_pr_cas_int(&gc_stage, STAGE_SWEEPING, STAGE_RESTING); } void *collector_main(void *arg) @@ -1304,7 +1305,7 @@ void *collector_main(void *arg) //sparse enough (would be difficult to do without relocations, though tim.tv_nsec = 100 * NANOSECONDS_PER_MILLISECOND; while (1) { - stage = ATOMIC_GET(&gc_stage); + stage = ck_pr_load_int(&gc_stage); if (stage != STAGE_RESTING) { gc_collector(); } @@ -1357,8 +1358,8 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->gc_num_args = 0; thd->moveBufLen = 0; gc_thr_grow_move_buffer(thd); - thd->gc_alloc_color = ATOMIC_GET(&gc_color_clear); - thd->gc_status = ATOMIC_GET(&gc_status_col); + thd->gc_alloc_color = ck_pr_load_int(&gc_color_clear); + thd->gc_status = ck_pr_load_int(&gc_status_col); thd->last_write = 0; thd->last_read = 0; thd->mark_buffer_len = 128; @@ -1390,7 +1391,7 @@ void gc_thread_data_free(gc_thread_data *thd) void gc_mutator_thread_blocked(gc_thread_data *thd, object cont) { - if(!ATOMIC_SET_IF_EQ(&(thd->thread_state), + if(!ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_BLOCKED)){ fprintf(stderr, "Unable to change thread from runnable to blocked. status = %d\n", thd->thread_state); @@ -1405,7 +1406,7 @@ void gc_mutator_thread_runnable(gc_thread_data *thd, object result) // Transition from blocked back to runnable using CAS. // If we are unable to transition back, assume collector // has cooperated on behalf of this mutator thread. - if (!ATOMIC_SET_IF_EQ(&(thd->thread_state), + if (!ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_RUNNABLE)){ printf("DEBUG - Collector cooperated, wait for it to finish. status is %d\n", thd->thread_state); @@ -1413,7 +1414,7 @@ printf("DEBUG - Collector cooperated, wait for it to finish. status is %d\n", th pthread_mutex_lock(&(thd->lock)); pthread_mutex_unlock(&(thd->lock)); // update thread status - while(!ATOMIC_SET_IF_EQ(&(thd->thread_state), + while(!ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_BLOCKED_COOPERATING, CYC_THREAD_STATE_RUNNABLE)){} // transport result to heap, if necessary (IE, is not a value type) diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 44fffc0b..edadf27f 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -447,13 +447,4 @@ void gc_mutator_thread_runnable(gc_thread_data *thd, object result); gc_heap *gc_get_heap(); int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args); -// Atomics section -// TODO: this is all compiler dependent, need to use different macros depending -// upon the compiler (and arch) -// TODO: relocate this to its own header? -#define ATOMIC_INC(ptr) __sync_fetch_and_add((ptr),1) -#define ATOMIC_DEC(ptr) __sync_fetch_and_sub((ptr),1) -#define ATOMIC_GET(ptr) __sync_fetch_and_add((ptr),0) -#define ATOMIC_SET_IF_EQ(ptr, oldv, newv) __sync_bool_compare_and_swap(ptr, oldv, newv) - #endif /* CYCLONE_TYPES_H */ diff --git a/runtime.c b/runtime.c index 241cec09..dd9c6cec 100644 --- a/runtime.c +++ b/runtime.c @@ -7,6 +7,7 @@ */ #include +#include #include "cyclone/types.h" #include "cyclone/runtime.h" #include "cyclone/ck_ht_hash.h" @@ -2408,9 +2409,9 @@ void GC(void *data, closure cont, object *args, int num_args) int alloci = gc_minor(data, low_limit, high_limit, cont, args, num_args); // Cooperate with the collector thread gc_mut_cooperate((gc_thread_data *)data, alloci); -//#if GC_DEBUG_TRACE +#if GC_DEBUG_TRACE fprintf(stderr, "done with minor GC\n"); -//#endif +#endif // Let it all go, Neo... longjmp(*(((gc_thread_data *)data)->jmp_start), 1); } @@ -2796,7 +2797,7 @@ void *Cyc_init_thread(object thunk) // returns instance so would need to malloc here // would also need to update termination code to free that memory gc_add_mutator(thd); - ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE); + ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE); Cyc_start_thread(thd); return NULL; } @@ -2860,7 +2861,7 @@ void Cyc_exit_thread(gc_thread_data *thd) //printf("DEBUG - exiting thread\n"); // Remove thread from the list of mutators, and mark its data to be freed gc_remove_mutator(thd); - ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); + ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); pthread_exit(NULL); // For now, just a proof of concept } From 1aa04f75b6867ed182115325893fc6b2d5116dc9 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 30 Dec 2015 03:54:31 +0000 Subject: [PATCH 316/339] Added cflags for building on raspberry pi --- Makefile | 8 ++++---- Makefile.config | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 709679ad..212221d8 100644 --- a/Makefile +++ b/Makefile @@ -43,13 +43,13 @@ dispatch.c: generate-c.scm ./generate-c libcyclone.so.1: runtime.c include/cyclone/runtime.h - gcc -g -c -fPIC runtime.c -o runtime.o + gcc $(CFLAGS) -c -fPIC runtime.c -o runtime.o gcc -shared -Wl,-soname,libcyclone.so.1 -o libcyclone.so.1.0.1 runtime.o libcyclone.a: runtime.c include/cyclone/runtime.h include/cyclone/types.h gc.c dispatch.c - $(CC) -g -c -Iinclude dispatch.c -o dispatch.o - $(CC) -g -std=gnu99 -c -Iinclude gc.c -o gc.o - $(CC) -g -c -Iinclude -DCYC_INSTALL_DIR=\"$(PREFIX)\" -DCYC_INSTALL_LIB=\"$(LIBDIR)\" -DCYC_INSTALL_INC=\"$(INCDIR)\" -DCYC_INSTALL_SLD=\"$(DATADIR)\" runtime.c -o runtime.o + $(CC) $(CFLAGS) -c -Iinclude dispatch.c -o dispatch.o + $(CC) $(CFLAGS) -std=gnu99 -c -Iinclude gc.c -o gc.o + $(CC) $(CFLAGS) -c -Iinclude -DCYC_INSTALL_DIR=\"$(PREFIX)\" -DCYC_INSTALL_LIB=\"$(LIBDIR)\" -DCYC_INSTALL_INC=\"$(INCDIR)\" -DCYC_INSTALL_SLD=\"$(DATADIR)\" runtime.c -o runtime.o $(AR) rcs libcyclone.a runtime.o gc.o dispatch.o # Instructions from: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html # Note compiler will have to link to this, eg: diff --git a/Makefile.config b/Makefile.config index 26339936..a9a8d28c 100644 --- a/Makefile.config +++ b/Makefile.config @@ -1,6 +1,7 @@ # install configuration +CFLAGS ?= -g -march=armv6k CC ?= cc AR ?= ar #CD ?= cd From 8f1ad554d98e2ae7704561b993812a39fc058f59 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 23:14:09 -0500 Subject: [PATCH 317/339] Use separate configs for X86 / ARM (pi 2) --- Makefile.config | 2 +- Makefile.config.raspberry-pi-2 | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Makefile.config.raspberry-pi-2 diff --git a/Makefile.config b/Makefile.config index a9a8d28c..1829a5a2 100644 --- a/Makefile.config +++ b/Makefile.config @@ -1,7 +1,7 @@ # install configuration -CFLAGS ?= -g -march=armv6k +CFLAGS ?= -g CC ?= cc AR ?= ar #CD ?= cd diff --git a/Makefile.config.raspberry-pi-2 b/Makefile.config.raspberry-pi-2 new file mode 100644 index 00000000..a9a8d28c --- /dev/null +++ b/Makefile.config.raspberry-pi-2 @@ -0,0 +1,22 @@ + +# install configuration + +CFLAGS ?= -g -march=armv6k +CC ?= cc +AR ?= ar +#CD ?= cd +RM ?= rm -f +#LS ?= ls +#CP ?= cp +#LN ?= ln +INSTALL ?= install +MKDIR ?= $(INSTALL) -d +RMDIR ?= rmdir + +PREFIX ?= /usr/local +BINDIR ?= $(PREFIX)/bin +LIBDIR ?= $(PREFIX)/lib +INCDIR ?= $(PREFIX)/include/cyclone +DATADIR ?= $(PREFIX)/share/cyclone + +DESTDIR ?= From 727d606928de3deda5b4ec6bc929f6abdd8aeb4d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 23:21:59 -0500 Subject: [PATCH 318/339] Bump version number and copyright info --- scheme/cyclone/common.sld | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scheme/cyclone/common.sld b/scheme/cyclone/common.sld index 980ab676..57bf60e5 100644 --- a/scheme/cyclone/common.sld +++ b/scheme/cyclone/common.sld @@ -5,7 +5,7 @@ *version-banner* *c-file-header-comment*) (begin -(define *version* "0.0.3 (Pre-release)") +(define *version* "0.0.4 (Pre-release)") (define *version-banner* (string-append " @@ -18,7 +18,7 @@ ,@ https://github.com/justinethier/cyclone '@ .@ - @@ #@ (c) 2014 Justin Ethier + @@ #@ (c) 2014-2016 Justin Ethier `@@@#@@@. Version " *version* " #@@@@@ +@@@+ @@ -33,7 +33,7 @@ (string-append "/** ** This file was automatically generated by the Cyclone scheme compiler ** - ** (c) 2014 Justin Ethier + ** (c) 2014-2016 Justin Ethier ** Version " *version* " ** **/ From c7dd60bf06284c0ab260066d215966fdcce3bc60 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 29 Dec 2015 23:27:09 -0500 Subject: [PATCH 319/339] Updated notes --- gc-notes.txt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 7b8d10cb..6a96ca5d 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -7,15 +7,7 @@ Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) TODO: -- create a branch and try to use CK atomics. goals: - - make sure this is stable on x86 (first priority) - - see if this will build/work on ARM - - rename SET to CAS (compare and swap) - - anything else? - - This is higher priority than mutexes (though not by much), because we want cyclone to work on both ARM and x86. - -- bring exceptions into local thread data? anything else? - also, will probably need to lock shared resources such as I/O... +- create a branch and try to use CK atomics. - seems done, just keep an eye on this - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc @@ -27,6 +19,9 @@ TODO: crashes, I think printing out result from (read) - assume I/O and eval both have threading issues +- bring exceptions into local thread data? anything else? + also, will probably need to lock shared resources such as I/O... + DONE: - need to cooperate when a mutator is blocked From c0ac60ba8711da64ee0e8b7fe3f7bed82ebd09ba Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 30 Dec 2015 21:59:37 -0500 Subject: [PATCH 320/339] Beginnings of a mutex type --- gc-notes.txt | 3 +++ include/cyclone/types.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/gc-notes.txt b/gc-notes.txt index 6a96ca5d..6649d245 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -15,6 +15,9 @@ TODO: - add mutex type, and associated functions from SRFI-18 when allocating a mutex, probably should do it on thread since by definition these are shared among multiple threads + - may be able to free mutex using mutex_destroy from within gc_sweep. + unfortunately it requires type checking each object before free, which is not ideal + - start making core stuff thread safe. for example, test.scm sometimes crashes, I think printing out result from (read) - assume I/O and eval both have threading issues diff --git a/include/cyclone/types.h b/include/cyclone/types.h index edadf27f..66ba61b0 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -206,6 +206,7 @@ typedef long tag_type; #define cvar_tag 16 #define vector_tag 17 #define macro_tag 18 +#define mutex_tag 19 #define nil NULL #define eq(x,y) (x == y) @@ -238,6 +239,11 @@ typedef struct {gc_header_type hdr; tag_type tag; object *pvar;} cvar_type; typedef cvar_type *cvar; #define make_cvar(n,v) cvar_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = cvar_tag; n.pvar = v; +// TODO: mutex type +// thinking about maybe using cvar_type with a mutex tag +// add an alloc_mutex macro/function, because these will only go on the heap + + /* Define boolean type. */ typedef struct {gc_header_type hdr; const tag_type tag; const char *pname;} boolean_type; typedef boolean_type *boolean; From 36752be311f4ac839a75363f55064bb9d6c54382 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 2 Jan 2016 21:56:36 -0500 Subject: [PATCH 321/339] Stubs for mutex functions --- gc.c | 7 +++++++ include/cyclone/runtime.h | 5 +++++ include/cyclone/types.h | 7 +++---- runtime.c | 40 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/gc.c b/gc.c index cc6532ea..98334da6 100644 --- a/gc.c +++ b/gc.c @@ -333,6 +333,13 @@ char *gc_copy_obj(object dest, char *obj, gc_thread_data *thd) hp->pvar = ((cvar_type *) obj)->pvar; return (char *)hp; } + case mutex_tag: { + mutex_type *hp = dest; + mark(hp) = thd->gc_alloc_color; + type_of(hp) = mutex_tag; + // NOTE: don't copy mutex itself, caller will do that (this is a special case) + return (char *)hp; + } case forward_tag: return (char *)forward(obj); case eof_tag: diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index ae602353..ed3e62f7 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -30,6 +30,7 @@ #define Cyc_check_sym(d,obj) Cyc_check_type(d,Cyc_is_symbol, symbol_tag, obj); #define Cyc_check_vec(d,obj) Cyc_check_type(d,Cyc_is_vector, vector_tag, obj); #define Cyc_check_port(d,obj) Cyc_check_type(d,Cyc_is_port, port_tag, obj); +#define Cyc_check_mutex(d,obj) Cyc_check_type(d,Cyc_is_mutex, mutex_tag, obj); void Cyc_invalid_type_error(void *data, int tag, object found); void Cyc_check_obj(void *data, int tag, object obj); void Cyc_check_bounds(void *data, const char *label, int len, int index); @@ -122,6 +123,9 @@ object Cyc_vector_ref(void *d, object v, object k); object Cyc_vector_set(void *d, object v, object k, object obj); object Cyc_make_vector(void *data, object cont, object len, object fill); object Cyc_list2vector(void *data, object cont, object l); +object Cyc_make_mutex(void *data); +object Cyc_lock_mutex(void *data, object obj); +object Cyc_unlock_mutex(void *data, object obj); object Cyc_number2string(void *d, object cont, object n); object Cyc_symbol2string(void *d, object cont, object sym) ; object Cyc_string2symbol(void *d, object str); @@ -162,6 +166,7 @@ object Cyc_is_real(object o); object Cyc_is_integer(object o); object Cyc_is_vector(object o); object Cyc_is_port(object o); +object Cyc_is_mutex(object o); object Cyc_is_symbol(object o); object Cyc_is_string(object o); object Cyc_is_char(object o); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 66ba61b0..40b9721c 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -239,10 +239,9 @@ typedef struct {gc_header_type hdr; tag_type tag; object *pvar;} cvar_type; typedef cvar_type *cvar; #define make_cvar(n,v) cvar_type n; n.hdr.mark = gc_color_red; n.hdr.grayed = 0; n.tag = cvar_tag; n.pvar = v; -// TODO: mutex type -// thinking about maybe using cvar_type with a mutex tag -// add an alloc_mutex macro/function, because these will only go on the heap - +/* Define mutex type */ +typedef struct {gc_header_type hdr; tag_type tag; pthread_mutex_t lock;} mutex_type; +typedef mutex_type *mutex; /* Define boolean type. */ typedef struct {gc_header_type hdr; const tag_type tag; const char *pname;} boolean_type; diff --git a/runtime.c b/runtime.c index dd9c6cec..dc79c206 100644 --- a/runtime.c +++ b/runtime.c @@ -45,7 +45,7 @@ const char *tag_names[21] = { \ , "C primitive" \ , "vector" \ , "macro" \ - , "Reserved for future use" \ + , "mutex" \ , "Reserved for future use" }; void Cyc_invalid_type_error(void *data, int tag, object found) { @@ -542,6 +542,9 @@ object Cyc_display(object x, FILE *port) case cvar_tag: Cyc_display(Cyc_get_cvar(x), port); break; + case mutex_tag: + fprintf(port, "", x); + break; case boolean_tag: fprintf(port, "#%s",((boolean_type *) x)->pname); break; @@ -823,6 +826,11 @@ object Cyc_is_port(object o){ return boolean_t; return boolean_f;} +object Cyc_is_mutex(object o){ + if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == mutex_tag) + return boolean_t; + return boolean_f;} + object Cyc_is_string(object o){ if (!nullp(o) && !is_value_type(o) && ((list)o)->tag == string_tag) return boolean_t; @@ -1215,6 +1223,36 @@ object Cyc_command_line_arguments(void *data, object cont) { return_closcall1(data, cont, lis); } +/** + * Create a new mutex by allocating it on the heap. This is different than + * other types of objects because by definition a mutex will be used by + * multiple threads, so no need to risk having the non-creating thread pick + * up a stack object ref by mistake. + */ +object Cyc_make_mutex(void *data) { +//typedef struct {gc_header_type hdr; tag_type tag; pthread_mutex_t lock;} mutex_type; +//typedef mutex_type *mutex; + int heap_grown; + mutex lock; + mutex_type tmp; + tmp.hdr.mark = gc_color_red; + tmp.hdr.grayed = 0; + tmp.tag = mutex_tag; + lock = gc_alloc(Cyc_heap, sizeof(mutex_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown); + if (pthread_mutex_init(&(lock->lock), NULL) != 0) { + fprintf(stderr, "Unable to make mutex\n"); + exit(1); + } +} + +object Cyc_lock_mutex(void *data, object obj) { + return boolean_t; +} + +object Cyc_unlock_mutex(void *data, object obj) { + return boolean_t; +} + object Cyc_make_vector(void *data, object cont, object len, object fill) { object v = nil; int i; From 9402805af35e131f12d0263581d3de69f9a47dc4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 2 Jan 2016 22:13:45 -0500 Subject: [PATCH 322/339] Mutex stubs --- include/cyclone/runtime.h | 8 ++++++-- runtime.c | 32 ++++++++++++++++++++++++++++---- srfi/18.sld | 1 + 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index ed3e62f7..91a6c00a 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -124,8 +124,8 @@ object Cyc_vector_set(void *d, object v, object k, object obj); object Cyc_make_vector(void *data, object cont, object len, object fill); object Cyc_list2vector(void *data, object cont, object l); object Cyc_make_mutex(void *data); -object Cyc_lock_mutex(void *data, object obj); -object Cyc_unlock_mutex(void *data, object obj); +object Cyc_mutex_lock(void *data, object obj); +object Cyc_mutex_unlock(void *data, object obj); object Cyc_number2string(void *d, object cont, object n); object Cyc_symbol2string(void *d, object cont, object sym) ; object Cyc_string2symbol(void *d, object str); @@ -317,6 +317,10 @@ extern const object primitive_vector_91ref; extern const object primitive_vector_91set_67; extern const object primitive_string_91ref; extern const object primitive_string_91set_67; +extern const object primitive_make_91mutex; +extern const object primitive_mutex_91lock_67; +extern const object primitive_mutex_91unlock_67; +extern const object primitive_mutex_127; extern const object primitive_Cyc_91installation_91dir; extern const object primitive_command_91line_91arguments; extern const object primitive_system; diff --git a/runtime.c b/runtime.c index dc79c206..7d57f678 100644 --- a/runtime.c +++ b/runtime.c @@ -1230,8 +1230,6 @@ object Cyc_command_line_arguments(void *data, object cont) { * up a stack object ref by mistake. */ object Cyc_make_mutex(void *data) { -//typedef struct {gc_header_type hdr; tag_type tag; pthread_mutex_t lock;} mutex_type; -//typedef mutex_type *mutex; int heap_grown; mutex lock; mutex_type tmp; @@ -1243,13 +1241,17 @@ object Cyc_make_mutex(void *data) { fprintf(stderr, "Unable to make mutex\n"); exit(1); } + return lock; } -object Cyc_lock_mutex(void *data, object obj) { +object Cyc_mutex_lock(void *data, object obj) { + // TODO: set for cooperation + // TODO: actually lock return boolean_t; } -object Cyc_unlock_mutex(void *data, object obj) { +object Cyc_mutex_unlock(void *data, object obj) { + // TODO: actually unlock return boolean_t; } @@ -1912,6 +1914,20 @@ void _cyc_string_91ref(void *data, object cont, object args) { Cyc_check_num_args(data, "string-ref", 2, args); { object c = Cyc_string_ref(data, car(args), cadr(args)); return_closcall1(data, cont, c); }} +void _Cyc_make_mutex(void *data, object cont, object args) { + { object c = Cyc_make_mutex(data); + return_closcall1(data, cont, c); }} +void _Cyc_mutex_lock(void *data, object cont, object args) { + Cyc_check_num_args(data, "mutex-lock!", 1, args); + { object c = Cyc_mutex_lock(data, car(args)); + return_closcall1(data, cont, c); }} +void _Cyc_mutex_unlock(void *data, object cont, object args) { + Cyc_check_num_args(data, "mutex-unlock!", 1, args); + { object c = Cyc_mutex_unlock(data, car(args)); + return_closcall1(data, cont, c); }} +void _mutex_127(void *data, object cont, object args) { + Cyc_check_num_args(data, "mutex?", 1, args); + return_closcall1(data, cont, Cyc_is_mutex(car(args))); } void _Cyc_91installation_91dir(void *data, object cont, object args) { Cyc_check_num_args(data, "Cyc-installation-dir", 1, args); Cyc_installation_dir(data, cont, car(args));} @@ -2655,6 +2671,10 @@ static primitive_type string_91length_primitive = {{0}, primitive_tag, "string-l static primitive_type substring_primitive = {{0}, primitive_tag, "substring", &_cyc_substring}; static primitive_type string_91ref_primitive = {{0}, primitive_tag, "string-ref", &_cyc_string_91ref}; static primitive_type string_91set_67_primitive = {{0}, primitive_tag, "string-set!", &_cyc_string_91set_67}; +static primitive_type make_91mutex_primitive = {{0}, primitive_tag, "make-mutex", &_Cyc_make_mutex}; +static primitive_type mutex_91lock_67_primitive = {{0}, primitive_tag, "mutex-lock!", &_Cyc_mutex_lock}; +static primitive_type mutex_91unlock_67_primitive = {{0}, primitive_tag, "mutex-unlock!", &_Cyc_mutex_unlock}; +static primitive_type mutex_127_primitive = {{0}, primitive_tag, "mutex?", &_mutex_127}; static primitive_type Cyc_91installation_91dir_primitive = {{0}, primitive_tag, "Cyc-installation-dir", &_Cyc_91installation_91dir}; static primitive_type command_91line_91arguments_primitive = {{0}, primitive_tag, "command-line-arguments", &_command_91line_91arguments}; static primitive_type system_primitive = {{0}, primitive_tag, "system", &_cyc_system}; @@ -2778,6 +2798,10 @@ const object primitive_string_91length = &string_91length_primitive; const object primitive_substring = &substring_primitive; const object primitive_string_91ref = &string_91ref_primitive; const object primitive_string_91set_67 = &string_91set_67_primitive; +const object primitive_make_91mutex = &make_91mutex_primitive; +const object primitive_mutex_91lock_67 = &mutex_91lock_67_primitive; +const object primitive_mutex_91unlock_67 = &mutex_91unlock_67_primitive; +const object primitive_mutex_127 = &mutex_127_primitive; const object primitive_Cyc_91installation_91dir = &Cyc_91installation_91dir_primitive; const object primitive_command_91line_91arguments = &command_91line_91arguments_primitive; const object primitive_system = &system_primitive; diff --git a/srfi/18.sld b/srfi/18.sld index 2ea957c9..32676df0 100644 --- a/srfi/18.sld +++ b/srfi/18.sld @@ -9,6 +9,7 @@ thread-start! thread-yield! ; thread-terminate! + ; For now, these are built-ins. No need for them here: make-mutex mutex-lock! mutex-unlock! ) (begin ;; Threading From 309fc3dc13c2dac931ce7726a1a257f3d576988d Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 2 Jan 2016 22:41:50 -0500 Subject: [PATCH 323/339] Added mutex functions --- scheme/cyclone/cgen.sld | 10 ++++++++++ scheme/cyclone/transforms.sld | 8 ++++++++ scheme/eval.sld | 3 +++ 3 files changed, 21 insertions(+) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index c700f468..616c4a69 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -533,6 +533,10 @@ ((eq? p 'string-ref) "Cyc_string_ref") ((eq? p 'string-set!) "Cyc_string_set") ((eq? p 'substring) "Cyc_substring") + ((eq? p 'make-mutex) "Cyc_make_mutex") + ((eq? p 'mutex-lock) "Cyc_mutex_lock") + ((eq? p 'mutex-unlock) "Cyc_mutex_unlock") + ((eq? p 'mutex?) "Cyc_is_mutex") ((eq? p 'Cyc-installation-dir) "Cyc_installation_dir") ((eq? p 'command-line-arguments) "Cyc_command_line_arguments") ((eq? p 'Cyc-minor-gc) "Cyc_trigger_minor_gc") @@ -616,6 +620,9 @@ string-ref string-set! substring + make-mutex + mutex-lock + mutex-unlock Cyc-installation-dir command-line-arguments Cyc-minor-gc @@ -664,6 +671,9 @@ ((eq? p 'make-vector) "object") ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") + ((eq? p 'make-mutex) "object") + ((eq? p 'mutex-lock) "object") + ((eq? p 'mutex-unlock) "object") ((eq? p 'Cyc-installation-dir) "object") (else #f))) diff --git a/scheme/cyclone/transforms.sld b/scheme/cyclone/transforms.sld index d8219d7c..5fc724dc 100644 --- a/scheme/cyclone/transforms.sld +++ b/scheme/cyclone/transforms.sld @@ -516,6 +516,10 @@ vector-length vector-ref vector-set! + make-mutex + mutex-lock! + mutex-unlock! + mutex? boolean? char? eof-object? @@ -579,6 +583,10 @@ string-set! string->symbol ;; Could be mistaken for an identifier make-vector + make-mutex + mutex-lock! + mutex-unlock! + mutex? ;; I/O must be done at runtime for side effects: Cyc-stdout Cyc-stdin diff --git a/scheme/eval.sld b/scheme/eval.sld index 9c3f64e3..e16442e7 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -223,6 +223,9 @@ (list 'vector-length vector-length) (list 'vector-ref vector-ref) (list 'vector-set! vector-set!) + (list 'make-mutex make-mutex) + (list 'mutex-lock! mutex-lock!) + (list 'mutex-unlock! mutex-unlock!) (list 'boolean? boolean?) (list 'char? char?) (list 'eof-object? eof-object?) From de33b567a3b525317e3bb0116c5203d7adeefa85 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sat, 2 Jan 2016 22:49:57 -0500 Subject: [PATCH 324/339] Missed a couple things... --- gc.c | 1 + scheme/eval.sld | 1 + 2 files changed, 2 insertions(+) diff --git a/gc.c b/gc.c index 98334da6..37de0fd2 100644 --- a/gc.c +++ b/gc.c @@ -480,6 +480,7 @@ size_t gc_allocated_bytes(object obj, gc_free_list *q, gc_free_list *r) if (t == double_tag) return gc_heap_align(sizeof(double_type)); if (t == port_tag) return gc_heap_align(sizeof(port_type)); if (t == cvar_tag) return gc_heap_align(sizeof(cvar_type)); + if (t == mutex_tag) return gc_heap_align(sizeof(mutex_type)); fprintf(stderr, "gc_allocated_bytes: unexpected object %p of type %ld\n", obj, t); exit(1); diff --git a/scheme/eval.sld b/scheme/eval.sld index e16442e7..bd7deab7 100644 --- a/scheme/eval.sld +++ b/scheme/eval.sld @@ -226,6 +226,7 @@ (list 'make-mutex make-mutex) (list 'mutex-lock! mutex-lock!) (list 'mutex-unlock! mutex-unlock!) + (list 'mutex? mutex?) (list 'boolean? boolean?) (list 'char? char?) (list 'eof-object? eof-object?) From ef61c578c5f73b62d5a22d633ae56db0fe5f5a7e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 00:02:19 -0500 Subject: [PATCH 325/339] Build-out of mutex lock/unlock --- include/cyclone/runtime.h | 2 +- runtime.c | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 91a6c00a..42826130 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -124,7 +124,7 @@ object Cyc_vector_set(void *d, object v, object k, object obj); object Cyc_make_vector(void *data, object cont, object len, object fill); object Cyc_list2vector(void *data, object cont, object l); object Cyc_make_mutex(void *data); -object Cyc_mutex_lock(void *data, object obj); +object Cyc_mutex_lock(void *data, object cont, object obj); object Cyc_mutex_unlock(void *data, object obj); object Cyc_number2string(void *d, object cont, object n); object Cyc_symbol2string(void *d, object cont, object sym) ; diff --git a/runtime.c b/runtime.c index 7d57f678..b0bf3d48 100644 --- a/runtime.c +++ b/runtime.c @@ -1244,14 +1244,27 @@ object Cyc_make_mutex(void *data) { return lock; } -object Cyc_mutex_lock(void *data, object obj) { - // TODO: set for cooperation - // TODO: actually lock +object Cyc_mutex_lock(void *data, object cont, object obj) { + mutex m = (mutex) obj; + Cyc_check_mutex(data, obj); + gc_mutator_thread_blocked((gc_thread_data *)data, cont); + if (pthread_mutex_lock(&(m->lock)) != 0) { + fprintf(stderr, "Error locking mutex\n"); + exit(1); + } + gc_mutator_thread_runnable( + (gc_thread_data *)data, + boolean_t); return boolean_t; } object Cyc_mutex_unlock(void *data, object obj) { - // TODO: actually unlock + mutex m = (mutex) obj; + Cyc_check_mutex(data, obj); + if (pthread_mutex_unlock(&(m->lock)) != 0) { + fprintf(stderr, "Error unlocking mutex\n"); + exit(1); + } return boolean_t; } @@ -1919,7 +1932,7 @@ void _Cyc_make_mutex(void *data, object cont, object args) { return_closcall1(data, cont, c); }} void _Cyc_mutex_lock(void *data, object cont, object args) { Cyc_check_num_args(data, "mutex-lock!", 1, args); - { object c = Cyc_mutex_lock(data, car(args)); + { object c = Cyc_mutex_lock(data, cont, car(args)); return_closcall1(data, cont, c); }} void _Cyc_mutex_unlock(void *data, object cont, object args) { Cyc_check_num_args(data, "mutex-unlock!", 1, args); From 6b96c00b57c2214a5f55c8046ff893274275562a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 00:09:41 -0500 Subject: [PATCH 326/339] Mutex fixes --- scheme/cyclone/cgen.sld | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 616c4a69..327fcd0e 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -534,8 +534,8 @@ ((eq? p 'string-set!) "Cyc_string_set") ((eq? p 'substring) "Cyc_substring") ((eq? p 'make-mutex) "Cyc_make_mutex") - ((eq? p 'mutex-lock) "Cyc_mutex_lock") - ((eq? p 'mutex-unlock) "Cyc_mutex_unlock") + ((eq? p 'mutex-lock!) "Cyc_mutex_lock") + ((eq? p 'mutex-unlock!) "Cyc_mutex_unlock") ((eq? p 'mutex?) "Cyc_is_mutex") ((eq? p 'Cyc-installation-dir) "Cyc_installation_dir") ((eq? p 'command-line-arguments) "Cyc_command_line_arguments") @@ -621,8 +621,8 @@ string-set! substring make-mutex - mutex-lock - mutex-unlock + mutex-lock! + mutex-unlock! Cyc-installation-dir command-line-arguments Cyc-minor-gc @@ -672,8 +672,8 @@ ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") ((eq? p 'make-mutex) "object") - ((eq? p 'mutex-lock) "object") - ((eq? p 'mutex-unlock) "object") + ((eq? p 'mutex-lock!) "object") + ((eq? p 'mutex-unlock!) "object") ((eq? p 'Cyc-installation-dir) "object") (else #f))) @@ -705,14 +705,14 @@ (define (prim:cont? exp) (and (prim? exp) (member exp '(Cyc-read-line apply command-line-arguments Cyc-minor-gc number->string - read-char peek-char + read-char peek-char mutex-lock! symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) ;; Primitive functions that pass a continuation but have no other arguments (define (prim:cont/no-args? exp) (and (prim? exp) - (member exp '(command-line-arguments Cyc-minor-gc)))) + (member exp '(command-line-arguments make-mutex Cyc-minor-gc)))) ;; Pass an integer arg count as the function's first parameter? (define (prim:arg-count? exp) From b5704446e6b8fa6318d8353cd4707d2d92a8031e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 00:11:44 -0500 Subject: [PATCH 327/339] WIP --- gc-notes.txt | 12 ++++++------ test.scm | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index 6649d245..b6b3de44 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -6,18 +6,18 @@ Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) -TODO: -- create a branch and try to use CK atomics. - seems done, just keep an eye on this - -- multiple mutators, and threading functions/types. probably want this on a new branch, when ready - part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc - next steps: +Mutex TODO: - add mutex type, and associated functions from SRFI-18 when allocating a mutex, probably should do it on thread since by definition these are shared among multiple threads - may be able to free mutex using mutex_destroy from within gc_sweep. unfortunately it requires type checking each object before free, which is not ideal +TODO: +- multiple mutators, and threading functions/types. probably want this on a new branch, when ready + part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc + next steps: + - start making core stuff thread safe. for example, test.scm sometimes crashes, I think printing out result from (read) - assume I/O and eval both have threading issues diff --git a/test.scm b/test.scm index a7b84bd9..203994f1 100644 --- a/test.scm +++ b/test.scm @@ -11,6 +11,10 @@ ; (foo)) ;) +(define tmp2 (make-mutex)) +(mutex-lock! tmp2) +(mutex-unlock! tmp2) + ;; A program to prove if cooperation is working, or if it ;; is blocked by another thread. The (read) causes the main ;; thread to block. The collector should be notified prior From f3a78bc15aed827b79458703856b4a67397f64b4 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 20:39:53 -0500 Subject: [PATCH 328/339] Fixed compilation issues with mutex primitives --- scheme/cyclone/cgen.sld | 1 + 1 file changed, 1 insertion(+) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 327fcd0e..9020f8a1 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -696,6 +696,7 @@ string-length substring + - * / apply command-line-arguments + make-mutex mutex-lock! mutex-unlock! Cyc-minor-gc Cyc-read-line read-char peek-char From 9b7e9106f155d25482672aac50b424fa221641aa Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 20:49:47 -0500 Subject: [PATCH 329/339] Treat (srfi) includes as built-in libraries --- scheme/cyclone/libraries.sld | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scheme/cyclone/libraries.sld b/scheme/cyclone/libraries.sld index 394a850e..fe37069b 100644 --- a/scheme/cyclone/libraries.sld +++ b/scheme/cyclone/libraries.sld @@ -126,7 +126,8 @@ file-ext)) (filename (substring filename* 1 (string-length filename*)))) - (if (tagged-list? 'scheme import) + (if (or (tagged-list? 'scheme import) + (tagged-list? 'srfi import)) (string-append (Cyc-installation-dir 'sld) "/" filename) ;; Built-in library filename))) From 4a940918ee9f2555dc0492419fff24205b94b6bb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 21:34:16 -0500 Subject: [PATCH 330/339] Fix compilation of make-mutex Issue was that this takes no application-level arguments but does take a 'data' argument. So this required some modifications since we never had a function with those specific needs before. --- scheme/cyclone/cgen.sld | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index 9020f8a1..e99d5644 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -671,7 +671,7 @@ ((eq? p 'make-vector) "object") ((eq? p 'list->string) "object") ((eq? p 'list->vector) "object") - ((eq? p 'make-mutex) "object") + ;((eq? p 'make-mutex) "object") ((eq? p 'mutex-lock!) "object") ((eq? p 'mutex-unlock!) "object") ((eq? p 'Cyc-installation-dir) "object") @@ -696,7 +696,8 @@ string-length substring + - * / apply command-line-arguments - make-mutex mutex-lock! mutex-unlock! + ;make-mutex + mutex-lock! mutex-unlock! Cyc-minor-gc Cyc-read-line read-char peek-char @@ -710,7 +711,7 @@ symbol->string list->string substring string-append make-vector list->vector Cyc-installation-dir)))) -;; Primitive functions that pass a continuation but have no other arguments +;; Primitive functions that pass a continuation or thread data but have no other arguments (define (prim:cont/no-args? exp) (and (prim? exp) (member exp '(command-line-arguments make-mutex Cyc-minor-gc)))) @@ -897,7 +898,8 @@ (c:append (let () ;; Add a comma if necessary - (if (str-ending? (c:body c-fun) "(") + (if (or (str-ending? (c:body c-fun) "(") + (prim:cont/no-args? fun)) c-fun (c:append c-fun (c-code ", ")))) c-args*) From ac7fec70a065fb5967783888878f96bcc96f8e77 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 21:59:09 -0500 Subject: [PATCH 331/339] Finalize mutex prior to sweeping --- gc.c | 9 +++++++++ test.scm | 1 + 2 files changed, 10 insertions(+) diff --git a/gc.c b/gc.c index 37de0fd2..f79a554a 100644 --- a/gc.c +++ b/gc.c @@ -573,6 +573,15 @@ size_t gc_sweep(gc_heap *h, size_t *sum_freed_ptr) fprintf(stderr, "sweep is freeing unmarked obj: %p with tag %ld\n", p, type_of(p)); #endif mark(p) = gc_color_blue; // Needed? + if (type_of(p) == mutex_tag) { +#if GC_DEBUG_VERBOSE + fprintf(stderr, "pthread_mutex_destroy from sweep\n"); +#endif + if (pthread_mutex_destroy(&(((mutex)p)->lock)) != 0) { + fprintf(stderr, "Error destroying mutex\n"); + exit(1); + } + } // free p heap_freed += size; if (((((char *)q) + q->size) == (char *)p) && (q != h->free_list)) { diff --git a/test.scm b/test.scm index 203994f1..f67c442b 100644 --- a/test.scm +++ b/test.scm @@ -14,6 +14,7 @@ (define tmp2 (make-mutex)) (mutex-lock! tmp2) (mutex-unlock! tmp2) +(set! tmp2 #f) ;; A program to prove if cooperation is working, or if it ;; is blocked by another thread. The (read) causes the main From 4d7cd020ccfaeaf9972243f717a8d5ec7b714532 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 22:17:47 -0500 Subject: [PATCH 332/339] Cleanup --- gc-notes.txt | 87 +++++++++++++++++++++++-- gc.c | 180 ++++----------------------------------------------- 2 files changed, 91 insertions(+), 176 deletions(-) diff --git a/gc-notes.txt b/gc-notes.txt index b6b3de44..ecdeb774 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -6,13 +6,6 @@ Phase 5 (gc-dev5) - Require pthreads library, stand cyclone back up using new GC Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) -Mutex TODO: - - add mutex type, and associated functions from SRFI-18 - when allocating a mutex, probably should do it on thread since by definition these are - shared among multiple threads - - may be able to free mutex using mutex_destroy from within gc_sweep. - unfortunately it requires type checking each object before free, which is not ideal - TODO: - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc @@ -119,3 +112,83 @@ DONE: this feature might end up being gc-dev7 (possibly the final phase) +ORIGINAL notes migrated here from gc.c: +/* +Rough plan for how to implement new GC algorithm. We need to do this in +phases in order to have any hope of getting everything working. Let's prove +the algorithm out, then extend support to multiple mutators if everything +looks good. + +PHASE 1 - separation of mutator and collector into separate threads + +need to syncronize access (preferably via atomics) for anything shared between the +collector and mutator threads. + +can cooperate be part of a minor gc? in that case, the +marking could be done as part of allocation + +but then what exactly does that mean, to mark gray? because +objects moved to the heap will be set to mark color at that +point (until collector thread finishes). but would want +objects on the heap referenced by them to be traced, so +I suppose that is the purpose of the gray, to indicate +those still need to be traced. but need to think this through, +do we need the markbuffer and last read/write? do those make + sense with mta approach (assume so)??? + +ONLY CONCERN - what happens if an object on the stack +has a reference to an object on the heap that is collected? +but how would this happen? collector marks global roots before +telling mutators to go to async, and once mutators go async +any allocations will not be collected. also once collectors go +async they have a chance to markgray, which will include the write +barrier. so given that, is it still possible for an old heap ref to +sneak into a stack object during the async phase? + +more questions on above point: +- figure out how/if after cooperation/async, can a stack object pick + up a reference to a heap object that will be collected during that GC cycle? + need to be able to prevent this somehow... + +- need to figure out real world use case(s) where this could happen, to try and + figure out how to address this problem + +from my understanding of the paper, the write barrier prevents this. consider, at the +start of async, the mutator's roots, global roots, and anything on the write barrier +have been marked. any new objects will be allocated as marked. that way, anything the +mutator could later access is either marked or will be after tracing. the only exception +is if the mutator changes a reference such that tracing will no longer find an object. +but the write barrier prevents this - during tracing a heap update causes the old +object to be marked as well. so it will eventually be traced, and there should be no +dangling objects after GC completes. + +PHASE 2 - multi-threaded mutator (IE, more than one stack thread): + +- how does the collector handle stack objects that reference objects from + another thread's stack? + * minor GC will only relocate that thread's objects, so another thread's would not + be moved. however, if another thread references one of the GC'd thread's + stack objects, it will now get a forwarding pointer. even worse, what if the + other thread is blocked and the reference becomes corrupt due to the stack + longjmp? there are major issues with one thread referencing another thread's + objects. + * had considered adding a stack bit to the object header. if we do this and + initialize it during object creation, a thread could in theory detect + if an object belongs to another thread. but it might be expensive because + a read barrier would have to be used to check the object's stack bit and + address (to see if it is on this heap). + * alternatively, how would one thread pick up a reference to another one's + objects? are there any ways to detect these events and deal with them? + it might be possible to detect such a case and allocate the object on the heap, + replacing it with a fwd pointer. unfortunately that means we need a read + barrier (ick) to handle forwarding pointers in arbitrary places + * but does that mean we need a fwd pointer to be live for awhile? do we need + a read barrier to get this to work? obviously we want to avoid a read barrier + at all costs. +- what are the real costs of allowing forwarding pointers to exist outside of just + minor GC? assume each runtime primitive would need to be updated to handle the + case where the obj is a fwd pointer - is it just a matter of each function + detecting this and (possibly) calling itself again with the 'real' address? + obviously that makes the runtime slower due to more checks, but maybe it is + not *so* bad? +*/ diff --git a/gc.c b/gc.c index f79a554a..38d19b13 100644 --- a/gc.c +++ b/gc.c @@ -26,7 +26,6 @@ // variables shared between threads static int gc_color_mark = 1; // Black, is swapped during GC static int gc_color_clear = 3; // White, is swapped during GC -//static const int gc_color_grey = 4; // TODO: appears unused, clean up // unfortunately this had to be split up; const colors are located in types.h static int gc_status_col = STATUS_SYNC1; @@ -403,11 +402,6 @@ void *gc_try_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd) return NULL; } -//TODO: need a heap lock. -//lock during - alloc, sweep? but now sweep becomes a stop the world... -// maybe only lock during each individual operation, not for a whole -// sweep or alloc - void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *heap_grown) { void *result = NULL; @@ -678,95 +672,9 @@ void vpbuffer_free(void **buf) { free(buf); } - - -// void gc_init() -// { -// } // END heap definitions - -/* -Rough plan for how to implement new GC algorithm. We need to do this in -phases in order to have any hope of getting everything working. Let's prove -the algorithm out, then extend support to multiple mutators if everything -looks good. - -PHASE 1 - separation of mutator and collector into separate threads - -need to syncronize access (preferably via atomics) for anything shared between the -collector and mutator threads. - -can cooperate be part of a minor gc? in that case, the -marking could be done as part of allocation - -but then what exactly does that mean, to mark gray? because -objects moved to the heap will be set to mark color at that -point (until collector thread finishes). but would want -objects on the heap referenced by them to be traced, so -I suppose that is the purpose of the gray, to indicate -those still need to be traced. but need to think this through, -do we need the markbuffer and last read/write? do those make - sense with mta approach (assume so)??? - -ONLY CONCERN - what happens if an object on the stack -has a reference to an object on the heap that is collected? -but how would this happen? collector marks global roots before -telling mutators to go to async, and once mutators go async -any allocations will not be collected. also once collectors go -async they have a chance to markgray, which will include the write -barrier. so given that, is it still possible for an old heap ref to -sneak into a stack object during the async phase? - -more questions on above point: -- figure out how/if after cooperation/async, can a stack object pick - up a reference to a heap object that will be collected during that GC cycle? - need to be able to prevent this somehow... - -- need to figure out real world use case(s) where this could happen, to try and - figure out how to address this problem - -from my understanding of the paper, the write barrier prevents this. consider, at the -start of async, the mutator's roots, global roots, and anything on the write barrier -have been marked. any new objects will be allocated as marked. that way, anything the -mutator could later access is either marked or will be after tracing. the only exception -is if the mutator changes a reference such that tracing will no longer find an object. -but the write barrier prevents this - during tracing a heap update causes the old -object to be marked as well. so it will eventually be traced, and there should be no -dangling objects after GC completes. - -PHASE 2 - multi-threaded mutator (IE, more than one stack thread): - -- how does the collector handle stack objects that reference objects from - another thread's stack? - * minor GC will only relocate that thread's objects, so another thread's would not - be moved. however, if another thread references one of the GC'd thread's - stack objects, it will now get a forwarding pointer. even worse, what if the - other thread is blocked and the reference becomes corrupt due to the stack - longjmp? there are major issues with one thread referencing another thread's - objects. - * had considered adding a stack bit to the object header. if we do this and - initialize it during object creation, a thread could in theory detect - if an object belongs to another thread. but it might be expensive because - a read barrier would have to be used to check the object's stack bit and - address (to see if it is on this heap). - * alternatively, how would one thread pick up a reference to another one's - objects? are there any ways to detect these events and deal with them? - it might be possible to detect such a case and allocate the object on the heap, - replacing it with a fwd pointer. unfortunately that means we need a read - barrier (ick) to handle forwarding pointers in arbitrary places - * but does that mean we need a fwd pointer to be live for awhile? do we need - a read barrier to get this to work? obviously we want to avoid a read barrier - at all costs. -- what are the real costs of allowing forwarding pointers to exist outside of just - minor GC? assume each runtime primitive would need to be updated to handle the - case where the obj is a fwd pointer - is it just a matter of each function - detecting this and (possibly) calling itself again with the 'real' address? - obviously that makes the runtime slower due to more checks, but maybe it is - not *so* bad? -*/ - -// tri-color GC section, WIP +// Tri-color GC section ///////////////////////////////////////////// // GC functions called by the Mutator threads @@ -784,29 +692,24 @@ int gc_is_stack_obj(gc_thread_data *thd, object obj) } /** -Write barrier for updates to heap-allocated objects -Plans: -The key for this barrier is to identify stack objects that contain -heap references, so they can be marked to avoid collection. + * Write barrier for updates to heap-allocated objects + * The key for this barrier is to identify stack objects that contain + * heap references, so they can be marked to avoid collection. */ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) { int status = ck_pr_load_int(&gc_status_col), stage = ck_pr_load_int(&gc_stage); if (ck_pr_load_int(&(thd->gc_status)) != STATUS_ASYNC) { -//fprintf(stderr, "DEBUG - GC sync marking heap obj %p ", old_obj); -//Cyc_display(old_obj, stderr); -//fprintf(stderr, " and new value %p ", value); -//Cyc_display(value, stderr); -////fprintf(stderr, " for heap object "); -//fprintf(stderr, "\n"); pthread_mutex_lock(&(thd->lock)); gc_mark_gray(thd, old_obj); - // Check if value is on the heap. If so, mark gray right now, - // otherwise set it to be marked after moved to heap by next GC if (gc_is_stack_obj(thd, value)) { + // Set object to be marked after moved to heap by next GC. + // This avoids having to recursively examine the stack now, + // which we have to do anyway during minor GC. grayed(value) = 1; } else { + // Value is on the heap, mark gray right now gc_mark_gray(thd, value); } pthread_mutex_unlock(&(thd->lock)); @@ -825,37 +728,8 @@ void gc_mut_update(gc_thread_data *thd, object old_obj, object value) } #endif } -// TODO: concerned there may be an issue here with a stack object -// having a 'tree' of references that contains heap objects. these -// objects would be skipped and would never be grayed by the current -// code: -// -// the paper marks both the heap location being written to and the -// value being written. not sure it makes sense to mark the value -// as it will always be on the stack - issue is if any obj's it is -// referencing are on the heap. this is where that stack bit might -// come in handy. -// -// do we want to mark gray immediately during add mutator, or wait -// until minor GC? YES - I think for mutators we need to mark the -// object gray immediately. otherwise if we delay until GC, a sweep -// may have already finished up and freed such an obj that would -// otherwise not have been freed if we had waited. -// -// again, only potential issue seems to be if a stack obj could ref -// something else on the heap - can that happen? I think this can only -// happen if the heap obj it refs is linked to a root, because stack -// objs are so short lived?? -// -// also we already know if objects are on the stack due to their color (RED). -// so can use this to not mark red values. otherwise probably do want -// to mark the 'y' as well (per paper) to prevent timing issues when we wait -// -// do have some concern though that mark_gray will stop when a stack obj -// is detected, and the code will not examine any refs held by the stack obj. } -// TODO: still need to handle case where a mutator is blocked void gc_mut_cooperate(gc_thread_data *thd, int buf_len) { int i, status_c, status_m; @@ -869,9 +743,9 @@ void gc_mut_cooperate(gc_thread_data *thd, int buf_len) thd->pending_writes = 0; pthread_mutex_unlock(&(thd->lock)); - // TODO: I think below is thread safe, but this code is tricky. - // worst case should be that some work is done twice if there is - // a race condition + // I think below is thread safe, but this code is tricky. + // Worst case should be that some work is done twice if there is + // a race condition // // TODO: should use an atomic comparison here status_c = ck_pr_load_int(&gc_status_col); @@ -971,27 +845,6 @@ void gc_mark_gray2(gc_thread_data *thd, object obj) } } -// TODO: before doing this, may want to debug a bit and see what is -// being passed to gc_mut_update. see if those objects tend to have -// any heap refs. may need to add debug code to do that... -// -// -//// This is called from the heap write barrier. The issue here is that -//// this is not called during GC, so obj and some of its refs may be -//// on the stack. So scan all refs and mark the ones that are on the heap -//void gc_mark_gray_rec(gc_thread_data *thd, object obj) -//{ -// int mark; -// -// if (is_object_type(obj)) { -// mark = mark(obj); -// -//// TODO: if we leave red as red and keep going, this could hang -//// if there is a cycle!! -// }&& mark(obj) == gc_color_clear) { // TODO: sync?? -// -//} - void gc_collector_trace() { ck_array_iterator_t iterator; @@ -1003,14 +856,6 @@ void gc_collector_trace() CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m){ // TODO: ideally, want to use a lock-free data structure to prevent // having to use a mutex here. see corresponding code in gc_mark_gray - -//TODO: I think this locking is too coarse. observing immediate failures with the recent change to g_mark_gray locking and -//wonder if the problem is that this locking will prevent a batch of changes from being seen. -//you know, do we really need locking here? the last read/write can be made atomic, and any reads/writes to mark buffer can -//be made atomic as well. I think we may need a dirty flag to let the collector know something is happening when the mark buffer -//needs to be resized, but other than that it this good enough? -//on the other hand, a central issue with this collector is when can we be sure that we are existing tracing at the right time, and -//not too early? because an early exit here will surely mean that objects are incorrectly freed pthread_mutex_lock(&(m->lock)); while (m->last_read < m->last_write) { clean = 0; @@ -1237,9 +1082,6 @@ printf("DEBUG - collector is cooperating for blocked mutator\n"); ///////////////////////////////////////////// // GC Collection cycle -//TODO: create function to print globals, ideally want names and the mark flag. -//then call before/after tracing to see if we can catch a global not being marked. -//want to rule out an issue here, since we have seen globals that were corrupted (IE, appears they were collected) void debug_dump_globals(); // Main collector function From d89a81eca6ee4f2b36a3b075aac6d73f9d9e0a34 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 22:30:30 -0500 Subject: [PATCH 333/339] More cleanup --- gc.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/gc.c b/gc.c index 38d19b13..480dacc7 100644 --- a/gc.c +++ b/gc.c @@ -413,28 +413,20 @@ void *gc_alloc(gc_heap *h, size_t size, char *obj, gc_thread_data *thd, int *hea size = gc_heap_align(size); result = gc_try_alloc(h, size, obj, thd); if (!result) { - // TODO: may want to consider not doing this now, and implementing gc_collect as - // part of the runtime, since we would have all of the roots, stack args, - // etc available there. -// max_freed = gc_collect(h); TODO: this does not work yet! -// -// total_size = gc_heap_total_size(h); -// if (((max_freed < size) || -// ((total_size > sum_freed) && -// (total_size - sum_freed) > (total_size * 0.75))) // Grow ratio -// && ((!h->max_size) || (total_size < h->max_size))) { - gc_grow_heap(h, size, 0); - *heap_grown = 1; -// } + // A vanilla mark&sweep collector would collect now, but unfortunately + // we can't do that because we have to go through multiple stages, some + // of which are asynchronous. So... no choice but to grow the heap. + gc_grow_heap(h, size, 0); + *heap_grown = 1; result = gc_try_alloc(h, size, obj, thd); if (!result) { fprintf(stderr, "out of memory error allocating %d bytes\n", size); - exit(1); // TODO: throw error??? + exit(1); // could throw error, but OOM is a major issue, so... } } #if GC_DEBUG_TRACE fprintf(stderr, "alloc %p size = %d, obj=%p, tag=%ld, mark=%d\n", result, size, obj, type_of(obj), mark(((object)result))); - //// TODO: Debug check, remove (ifdef it) once GC is stabilized + // Debug check, should no longer be necessary //if (is_value_type(result)) { // printf("Invalid allocated address - is a value type %p\n", result); //} @@ -1072,8 +1064,6 @@ printf("DEBUG - collector is cooperating for blocked mutator\n"); // At least for now, just give up quantum and come back to // this quickly to test again. This probably could be more // efficient. - // TODO: also need to consider mutators that are blocked and - // not cooperating. nanosleep(&tim, NULL); } } From a889d6fb6f0eb9c27b1723d72d2ae2247bac8db7 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 22:56:34 -0500 Subject: [PATCH 334/339] Refactoring Renamed cyc_start_thread to cyc_start_trampoline to be more clear about what the function actually does. --- include/cyclone/runtime.h | 2 +- runtime.c | 4 ++-- scheme/cyclone/cgen.sld | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 42826130..4f35bcd7 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -192,7 +192,7 @@ object memberp(void *,object,list); object memqp(void *,object,list); object Cyc_spawn_thread(object thunk); -void Cyc_start_thread(gc_thread_data *thd); +void Cyc_start_trampoline(gc_thread_data *thd); void Cyc_end_thread(gc_thread_data *thd); void Cyc_exit_thread(gc_thread_data *thd); object Cyc_thread_sleep(void *data, object timeout); diff --git a/runtime.c b/runtime.c index b0bf3d48..e8aecbe7 100644 --- a/runtime.c +++ b/runtime.c @@ -2180,7 +2180,7 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { TODO: should rename this function to make it more clear what is really going on */ -void Cyc_start_thread(gc_thread_data *thd) +void Cyc_start_trampoline(gc_thread_data *thd) { // Tank, load the jump program setjmp(*(thd->jmp_start)); @@ -2873,7 +2873,7 @@ void *Cyc_init_thread(object thunk) // would also need to update termination code to free that memory gc_add_mutator(thd); ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE); - Cyc_start_thread(thd); + Cyc_start_trampoline(thd); return NULL; } diff --git a/scheme/cyclone/cgen.sld b/scheme/cyclone/cgen.sld index e99d5644..d5410753 100644 --- a/scheme/cyclone/cgen.sld +++ b/scheme/cyclone/cgen.sld @@ -90,7 +90,7 @@ gc_add_mutator(thd); Cyc_heap_init(heap_size); thd->thread_state = CYC_THREAD_STATE_RUNNABLE; - Cyc_start_thread(thd); + Cyc_start_trampoline(thd); return 0;}") ;;; Auto-generation of C macros From d2cbfaf217456e5d54b7e7dd097c02bcd4096fac Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 22:57:13 -0500 Subject: [PATCH 335/339] Cleanup TODO --- runtime.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime.c b/runtime.c index e8aecbe7..f14301cf 100644 --- a/runtime.c +++ b/runtime.c @@ -2176,9 +2176,6 @@ void Cyc_apply_from_buf(void *data, int argc, object prim, object *buf) { /** * Start a thread's trampoline - -TODO: should rename this function to make it more clear what is really going on - */ void Cyc_start_trampoline(gc_thread_data *thd) { From c32cbdad9a26d197f531cfa1f6a2ea57778ba065 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Sun, 3 Jan 2016 23:02:11 -0500 Subject: [PATCH 336/339] Added more notes --- gc-notes.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index ecdeb774..6bbd6f5e 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -7,6 +7,8 @@ Phase 6 (gc-dev6) - Multiple mutators (application threads) Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation, but that might not be realistic) TODO: +- merge everything back to master??? I think it's just about time +- move mutations into local thread data - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc next steps: @@ -17,7 +19,11 @@ TODO: - bring exceptions into local thread data? anything else? also, will probably need to lock shared resources such as I/O... - +- need a legitimate test program that uses mutexes. am worried that when lock calls into a cont, the program will crash because it returns a boolean object, which the runtime does not handle +- user manual + need to document everything, including: + - how to use cyclone (meta files, compiling modules, etc) + - what to be cognizant of when writing threading code. esp, how to deal with stack objects (initiating minor GC's, etc) DONE: - need to cooperate when a mutator is blocked From e28951a8d5019524b0babf8ef8ba8b184bd0773a Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 4 Jan 2016 22:54:23 -0500 Subject: [PATCH 337/339] Move the mutation table into thread data. --- gc.c | 4 ++++ include/cyclone/runtime.h | 4 ---- include/cyclone/types.h | 6 +++++- runtime.c | 27 +++++++++++++++------------ 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/gc.c b/gc.c index 480dacc7..cf5acd65 100644 --- a/gc.c +++ b/gc.c @@ -1199,6 +1199,7 @@ void gc_thread_data_init(gc_thread_data *thd, int mut_num, char *stack_base, lon thd->stack_traces = calloc(MAX_STACK_TRACES, sizeof(char *)); thd->stack_trace_idx = 0; thd->stack_prev_frame = NULL; + thd->mutations = NULL; // thd->thread = NULL; thd->thread_state = CYC_THREAD_STATE_NEW; //thd->mutator_num = mut_num; @@ -1234,6 +1235,9 @@ void gc_thread_data_free(gc_thread_data *thd) if (thd->moveBuf) free(thd->moveBuf); if (thd->mark_buffer) free(thd->mark_buffer); if (thd->stack_traces) free(thd->stack_traces); + if (thd->mutations) { + clear_mutations(thd); + } free(thd); } } diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 4f35bcd7..4d0dbf69 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -211,10 +211,6 @@ object find_or_add_symbol(const char *name); extern list global_table; void add_global(object *glo); -void add_mutation(object var, object value); -void clear_mutations(); -extern list mutation_table; - void dispatch(void *data, int argc, function_type func, object clo, object cont, object args); void dispatch_va(void *data, int argc, function_type_va func, object clo, object cont, object args); void do_dispatch(void *data, int argc, function_type func, object clo, object *buffer); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 40b9721c..8c482ebe 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -66,7 +66,8 @@ struct gc_thread_data_t { // Data needed to initiate stack-based minor GC char *stack_start; char *stack_limit; -//TODO: store stack traces per thread + // Minor GC write barrier + void *mutations; // List of objects moved to heap during minor GC void **moveBuf; int moveBufLen; @@ -452,4 +453,7 @@ void gc_mutator_thread_runnable(gc_thread_data *thd, object result); gc_heap *gc_get_heap(); int gc_minor(void *data, object low_limit, object high_limit, closure cont, object *args, int num_args); +void add_mutation(void *data, object var, object value); +void clear_mutations(void *data); + #endif /* CYCLONE_TYPES_H */ diff --git a/runtime.c b/runtime.c index f14301cf..266de942 100644 --- a/runtime.c +++ b/runtime.c @@ -312,30 +312,33 @@ void debug_dump_globals() /* END Global table */ -/* Mutation table +/* Mutation table functions * * Keep track of mutations (EG: set-car!) so that new * values are transported to the heap during GC. + * Note these functions and underlying data structure are only used by + * the calling thread, so locking is not required. */ -list mutation_table = nil; -void add_mutation(object var, object value){ +void add_mutation(void *data, object var, object value){ + gc_thread_data *thd = (gc_thread_data *)data; if (is_object_type(value)) { - mutation_table = mcons(var, mutation_table); + thd->mutations = mcons(var, thd->mutations); } } /* TODO: consider a more efficient implementation, such as reusing old nodes instead of reclaiming them each time */ -void clear_mutations() { - list l = mutation_table, next; +void clear_mutations(void *data) { + gc_thread_data *thd = (gc_thread_data *)data; + list l = thd->mutations, next; while (!nullp(l)) { next = cdr(l); free(l); l = next; } - mutation_table = nil; + thd->mutations = nil; } /* END mutation table */ @@ -897,7 +900,7 @@ object Cyc_set_car(void *data, object l, object val) { if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); gc_mut_update((gc_thread_data *)data, car(l), val); car(l) = val; - add_mutation(l, val); + add_mutation(data, l, val); return l; } @@ -905,7 +908,7 @@ object Cyc_set_cdr(void *data, object l, object val) { if (Cyc_is_cons(l) == boolean_f) Cyc_invalid_type_error(data, cons_tag, l); gc_mut_update((gc_thread_data *)data, cdr(l), val); cdr(l) = val; - add_mutation(l, val); + add_mutation(data, l, val); return l; } @@ -926,7 +929,7 @@ object Cyc_vector_set(void *data, object v, object k, object obj) { ((vector)v)->elts[idx] = obj; // TODO: probably could be more efficient here and also pass // index, so only that one entry needs GC. - add_mutation(v, obj); + add_mutation(data, v, obj); return v; } @@ -2366,7 +2369,7 @@ int gc_minor(void *data, object low_limit, object high_limit, closure cont, obje // Transport mutations { list l; - for (l = mutation_table; !nullp(l); l = cdr(l)) { + for (l = ((gc_thread_data *)data)->mutations; !nullp(l); l = cdr(l)) { object o = car(l); if (type_of(o) == cons_tag) { gc_move2heap(car(o)); @@ -2385,7 +2388,7 @@ int gc_minor(void *data, object low_limit, object high_limit, closure cont, obje } } } - clear_mutations(); // Reset for next time + clear_mutations(data); // Reset for next time // Transport globals gc_move2heap(Cyc_global_variables); // Internal global used by the runtime From 3031806bfa66ae5086bf461193fedecd1146397e Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Mon, 4 Jan 2016 22:55:14 -0500 Subject: [PATCH 338/339] Removed mutation table TODO --- gc-notes.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index 6bbd6f5e..fde6bdc4 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -8,7 +8,6 @@ Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation TODO: - merge everything back to master??? I think it's just about time -- move mutations into local thread data - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc next steps: From a014df38b3a6b7037a9ad5d28fd2e1bd72ee1f23 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Tue, 5 Jan 2016 02:21:50 -0500 Subject: [PATCH 339/339] Notes --- gc-notes.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gc-notes.txt b/gc-notes.txt index fde6bdc4..d7cdcc13 100644 --- a/gc-notes.txt +++ b/gc-notes.txt @@ -8,6 +8,9 @@ Phase 7 (TBD) - Sharing of variables between threads (ideally without limitation TODO: - merge everything back to master??? I think it's just about time +- need a legitimate test program that uses mutexes. am worried that when lock calls into a cont, the program will crash because it returns a boolean object, which the runtime does not handle + maybe just a simple producer/consumer type program + - multiple mutators, and threading functions/types. probably want this on a new branch, when ready part of this is implementing the beginnings of srfi-18, to create multiple threads, sync them, etc next steps: @@ -18,11 +21,12 @@ TODO: - bring exceptions into local thread data? anything else? also, will probably need to lock shared resources such as I/O... -- need a legitimate test program that uses mutexes. am worried that when lock calls into a cont, the program will crash because it returns a boolean object, which the runtime does not handle - user manual need to document everything, including: - how to use cyclone (meta files, compiling modules, etc) - what to be cognizant of when writing threading code. esp, how to deal with stack objects (initiating minor GC's, etc) +- revisit features list, issues list, etc +- FFI DONE: - need to cooperate when a mutator is blocked