diff --git a/include/gc.h b/include/gc.h index b951b44..c27f818 100644 --- a/include/gc.h +++ b/include/gc.h @@ -1,8 +1,8 @@ #ifndef LIBABACUS_GC_H #define LIBABACUS_GC_H -struct libab_ref_s; -struct libab_ref_count_s; +#include "refcount.h" +#include "gc_functions.h" /** * Struct used to create an interface @@ -10,18 +10,16 @@ struct libab_ref_count_s; */ struct libab_gc_list_s { /** - * The head of the linked list. + * The head sentinel node. */ - struct libab_ref_count_s* head; + struct libab_ref_count_s head_sentinel; /** - * The tail of the linked list. + * The tail sentinel node. */ - struct libab_ref_count_s* tail; + struct libab_ref_count_s tail_sentinel; }; typedef struct libab_gc_list_s libab_gc_list; -typedef void (*libab_visitor_function_ptr)(struct libab_ref_count_s* , void*); -typedef void (*libab_visit_function_ptr)(void*, libab_visitor_function_ptr, void*); /** * Initializes a garbage collection tracking list. @@ -34,7 +32,7 @@ void libab_gc_list_init(libab_gc_list* list); * @param visitor the function to call for each child. * @param data the data to pass to the visitor. */ -void libab_gc_visit_chilren(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data); +void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data); /** * Adds the given reference to the given garbage collection list, * and specifies a function used to reach its children. diff --git a/include/gc_functions.h b/include/gc_functions.h new file mode 100644 index 0000000..3108e85 --- /dev/null +++ b/include/gc_functions.h @@ -0,0 +1,10 @@ +#ifndef LIBABACUS_GC_FUNCTIONS_H +#define LIBABACUS_GC_FUNCTIONS_H + +struct libab_ref_count_s; +struct libab_ref_s; + +typedef void (*libab_visitor_function_ptr)(struct libab_ref_count_s* , void*); +typedef void (*libab_visit_function_ptr)(void*, libab_visitor_function_ptr, void*); + +#endif diff --git a/include/libabacus.h b/include/libabacus.h index 077add3..5b2f34c 100644 --- a/include/libabacus.h +++ b/include/libabacus.h @@ -9,6 +9,7 @@ #include "parser.h" #include "result.h" #include "table.h" +#include "gc.h" /** * The main struct of libabacus, @@ -59,6 +60,12 @@ struct libab_s { * The unit type instance. */ libab_ref type_unit; + /** + * List of containers references + * that should be tracked by the + * garbage collector for cycles. + */ + libab_gc_list containers; /** * Internal; the number basetype. This cannot be a static diff --git a/include/refcount.h b/include/refcount.h index 0c24ee2..9b9a42b 100644 --- a/include/refcount.h +++ b/include/refcount.h @@ -2,7 +2,7 @@ #define LIBABACUS_REFCOUNT_H #include "result.h" -#include "gc.h" +#include "gc_functions.h" /** * A struct for holding diff --git a/include/util.h b/include/util.h index 9a509fe..74db6fc 100644 --- a/include/util.h +++ b/include/util.h @@ -7,6 +7,7 @@ #include "parsetype.h" #include "result.h" #include "table.h" +#include "libabacus.h" #include /** @@ -78,11 +79,12 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate, libab_ref* into, size_t n, ...); /** * Creates a new libab_table, and stores it into the given reference. + * @param ab the libabacus instance in which the table is being created. * @param into the reference to store the table into. * @param parent the parent reference to store. * @return the result of the instantiation. */ -libab_result libab_create_table(libab_ref* into, libab_ref* parent); +libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent); /** * Allocates a new reference counted value with the given type and data. * @param into the reference to store the allocated data into. @@ -90,8 +92,8 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent); * @param type the type to give the value. * @return the result of necessary allocations. */ -libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, - libab_ref* type); +libab_result libab_create_value_ref(libab* ab, libab_ref* into, + libab_ref* data, libab_ref* type); /** * Allocates a new reference counted value with the given type and data. * @param into the reference to store the allocated data into. @@ -99,8 +101,8 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, * @param type the type to give the value. * @return the result of necessary allocations. */ -libab_result libab_create_value_raw(libab_ref* into, void* data, - libab_ref* type); +libab_result libab_create_value_raw(libab* ab, libab_ref* into, + void* data, libab_ref* type); /** * Allocates a function that uses internal code to run. * @param into the reference into which to store the new function. @@ -109,7 +111,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data, * @param scope the scope in which this function was declared. * @return libab_result the result of any necessary allocations. */ -libab_result libab_create_function_internal(libab_ref* into, +libab_result libab_create_function_internal(libab* ab, libab_ref* into, void (*free_function)(void*), libab_function_ptr fun, libab_ref* scope); @@ -121,7 +123,7 @@ libab_result libab_create_function_internal(libab_ref* into, * @param scope the scope in which this function was declared. * @return libab_result the result of any necessary allocations. */ -libab_result libab_create_function_tree(libab_ref* into, +libab_result libab_create_function_tree(libab* ab, libab_ref* into, void (*free_function)(void*), libab_tree* tree, libab_ref* scope); @@ -133,7 +135,7 @@ libab_result libab_create_function_tree(libab_ref* into, * @param scope the scope in which this function was declared. * @return libab_result the result of any necessary allocations. */ -libab_result libab_create_function_behavior(libab_ref* into, +libab_result libab_create_function_behavior(libab* ab, libab_ref* into, void (*free_function)(void*), libab_behavior* behavior, libab_ref* scope); @@ -143,7 +145,7 @@ libab_result libab_create_function_behavior(libab_ref* into, * @param the function_list type. * @return the result of the allocations. */ -libab_result libab_create_function_list(libab_ref* into, libab_ref* type); +libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type); /** * Creates a new table entry that holds the given value. * @param table the table to store the entry into. diff --git a/src/gc.c b/src/gc.c index 98ce12e..5e6bacb 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1,31 +1,32 @@ #include "gc.h" #include "refcount.h" #include +#include void libab_gc_list_init(libab_gc_list* list) { - list->head = list->tail = NULL; + memset(&list->head_sentinel, 0, sizeof(list->head_sentinel)); + memset(&list->tail_sentinel, 0, sizeof(list->tail_sentinel)); + list->head_sentinel.next = &list->tail_sentinel; + list->tail_sentinel.prev = &list->head_sentinel; } void _gc_count_visit_children(libab_ref_count* ref, libab_visitor_function_ptr func, void* data) { if(ref->strong && ref->visit_children) ref->visit_children(ref->data, func, data); } void libab_gc_visit_children(libab_ref* ref, libab_visitor_function_ptr func, void* data) { - _gc_count_visit_children(ref->count, func, data); + if(!ref->null) _gc_count_visit_children(ref->count, func, data); } void _libab_gc_list_append(libab_gc_list* list, libab_ref_count* node) { + libab_ref_count* before; if(node->next) node->next->prev = node->prev; if(node->prev) node->prev->next = node->next; - - node->prev = list->tail; - node->next = NULL; - if(list->head) { - list->tail->next = node; - } else { - list->head = node; - } - list->tail = node; + before = &list->tail_sentinel; + node->next = before; + node->prev = before->prev; + before->prev->next = node; + before->prev = node; } void libab_gc_add(libab_ref* ref, libab_visit_function_ptr visit_children, @@ -35,7 +36,7 @@ void libab_gc_add(libab_ref* ref, } void _gc_decrement(libab_ref_count* count, void* data) { - if(count->visit_children) count->gc--; + count->gc--; } void _gc_save(libab_ref_count* count, void* data) { libab_gc_list* list = data; @@ -51,27 +52,30 @@ void libab_gc_run(libab_gc_list* list) { libab_ref_count* head; size_t count = 0; - head = list->head; - while(head) { - head->gc = head->weak; + #define ITERATE(CODE) head = list->head_sentinel.next; \ + while(head != &list->tail_sentinel) { \ + CODE;\ + head = head->next; \ } - head = list->head; - while(head) { - _gc_count_visit_children(head, _gc_decrement, NULL); - } + libab_gc_list_init(&safe); + ITERATE(head->gc = head->weak); + ITERATE(_gc_count_visit_children(head, _gc_decrement, NULL)); + ITERATE(printf("%d outside references\n", head->gc)); + ITERATE(_gc_count_visit_children(head, _gc_save, &safe)); + ITERATE(count++); - head = list->head; - while(head) { - _gc_count_visit_children(head, _gc_save, &safe); - } - - head = list->head; - while(head) { - count++; - } printf("Can free %d\n", count); - list->head = safe.head; - list->tail = safe.tail; + if(safe.head_sentinel.next != &safe.tail_sentinel) { + printf("Safe isn't empty!\n"); + list->head_sentinel.next = safe.head_sentinel.next; + list->head_sentinel.next->prev = &list->head_sentinel; + list->tail_sentinel.prev = safe.tail_sentinel.prev; + list->tail_sentinel.prev->next = &list->tail_sentinel; + } else { + printf("Safe is empty!\n"); + list->head_sentinel.next = &list->tail_sentinel; + list->tail_sentinel.prev = &list->head_sentinel; + } } diff --git a/src/interactive.c b/src/interactive.c index b37334e..108bc6a 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -30,7 +30,7 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) { double* new_double = malloc(sizeof(*new_double)); if(new_double) { *new_double = val; - result = libab_create_value_raw(into, new_double, &type_num); + result = libab_create_value_raw(ab, into, new_double, &type_num); if(result != LIBAB_SUCCESS) { free(new_double); } @@ -216,6 +216,7 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) { int main() { libab_result result; libab_ref scope; + libab_ref test; libab ab; if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) { @@ -225,10 +226,12 @@ int main() { result = register_functions(&ab); if(result == LIBAB_SUCCESS) { - result = libab_create_table(&scope, &ab.table); + result = libab_create_table(&ab, &scope, &ab.table); } if(result == LIBAB_SUCCESS) { loop(&ab, INTERACTIONS, &scope); + libab_table_search_value(libab_ref_get(&scope), "test", &test); + printf("%p\n", libab_ref_get(&test)); libab_ref_free(&scope); } diff --git a/src/interpreter.c b/src/interpreter.c index 2a317cd..19d5174 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -13,7 +13,7 @@ libab_result _create_bool_value(libab* ab, int val, libab_ref* into) { new_bool = malloc(sizeof(*new_bool)); if(new_bool) { *new_bool = val; - result = libab_create_value_raw(into, new_bool, &type_bool); + result = libab_create_value_raw(ab, into, new_bool, &type_bool); if(result != LIBAB_SUCCESS) { free(new_bool); } @@ -33,7 +33,7 @@ libab_result libab_interpreter_init(libab_interpreter* intr, libab* ab) { libab_ref_null(&intr->value_false); libab_ref_null(&unit_data); - result = libab_create_value_ref(&intr->value_unit, &unit_data, &ab->type_unit); + result = libab_create_value_ref(ab, &intr->value_unit, &unit_data, &ab->type_unit); if(result == LIBAB_SUCCESS) { libab_ref_free(&intr->value_true); result = _create_bool_value(ab, 1, &intr->value_true); @@ -75,7 +75,7 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state, if ((data = state->ab->impl.parse_num(from))) { libab_ref_free(into); - result = libab_create_value_raw(into, data, &state->ab->type_num); + result = libab_create_value_raw(state->ab, into, data, &state->ab->type_num); if (result != LIBAB_SUCCESS) { ((libab_parsetype*)libab_ref_get(&state->ab->type_num)) @@ -466,13 +466,14 @@ libab_result _interpreter_find_match(libab_function_list* function_values, * @param type the new type. * @param into the reference into which to store the new value. */ -libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type, +libab_result _interpreter_cast_param(libab* ab, libab_ref* param, + libab_ref* type, libab_ref_vec* into) { libab_result result = LIBAB_SUCCESS; libab_value* old_value = libab_ref_get(param); libab_ref new_value; - result = libab_create_value_ref(&new_value, &old_value->data, type); + result = libab_create_value_ref(ab, &new_value, &old_value->data, type); if (result == LIBAB_SUCCESS) { result = libab_ref_vec_insert(into, &new_value); } @@ -488,7 +489,8 @@ libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type, * @param into the pre-initialized vector to store the new values into. * @return the result of any allocations. */ -libab_result _interpreter_cast_params(libab_ref_vec* params, +libab_result _interpreter_cast_params(libab* ab, + libab_ref_vec* params, libab_ref_vec* new_types, libab_ref_vec* into) { libab_result result = LIBAB_SUCCESS; @@ -500,7 +502,7 @@ libab_result _interpreter_cast_params(libab_ref_vec* params, libab_ref_vec_index(params, index, &temp_param); libab_ref_vec_index(new_types, index, &temp_type); - result = _interpreter_cast_param(&temp_param, &temp_type, into); + result = _interpreter_cast_param(ab, &temp_param, &temp_type, into); libab_ref_free(&temp_param); libab_ref_free(&temp_type); @@ -531,7 +533,7 @@ libab_result _interpreter_call_tree(struct interpreter_state* state, libab_ref param; libab_table* new_scope_raw; size_t i; - libab_result result = libab_create_table(&new_scope, scope); + libab_result result = libab_create_table(state->ab, &new_scope, scope); if(result == LIBAB_SUCCESS) { new_scope_raw = libab_ref_get(&new_scope); @@ -581,22 +583,24 @@ libab_result _interpreter_call_behavior(struct interpreter_state* state, * @param function the function to copy. * @param into the reference to store the copy into. */ -libab_result _interpreter_copy_function_basic(libab_ref* function, +libab_result _interpreter_copy_function_basic(libab* ab, + libab_ref* function, libab_ref* scope, libab_ref* into) { libab_function* func = libab_ref_get(function); void (*free_function)(void*) = function->count->free_func; - return libab_create_function_behavior(into, free_function, &func->behavior, scope); + return libab_create_function_behavior(ab, into, free_function, &func->behavior, scope); } -libab_result _interpreter_copy_function_with_params(libab_ref* function, +libab_result _interpreter_copy_function_with_params(libab* ab, + libab_ref* function, libab_ref_vec* params, libab_ref* scope, libab_ref* into) { int index = 0; libab_ref param; libab_function* func; - libab_result result = _interpreter_copy_function_basic(function, scope, into); + libab_result result = _interpreter_copy_function_basic(ab, function, scope, into); func = libab_ref_get(into); for(; index < params->size && result == LIBAB_SUCCESS; index++) { @@ -669,14 +673,14 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state, value = libab_ref_get(function); libab_ref_null(&new_type); - result = _interpreter_copy_function_with_params(&value->data, params, scope, &new_function); + result = _interpreter_copy_function_with_params(state->ab, &value->data, params, scope, &new_function); if(result == LIBAB_SUCCESS) { libab_ref_free(&new_type); result = _interpreter_copy_type_offset(&value->type, 0, &new_type); } if(result == LIBAB_SUCCESS) { - result = libab_create_value_ref(into, &new_function, &new_type); + result = libab_create_value_ref(state->ab, into, &new_function, &new_type); } else { libab_ref_null(into); } @@ -711,10 +715,11 @@ libab_result _interpreter_foreach_insert_param(const libab_ref* param, return result; } -libab_result _interpreter_create_scope(libab_ref* into, +libab_result _interpreter_create_scope(libab* ab, + libab_ref* into, libab_ref* parent_scope, libab_ref_trie* param_map) { - libab_result result = libab_create_table(into, parent_scope); + libab_result result = libab_create_table(ab, into, parent_scope); if (result == LIBAB_SUCCESS) { result = libab_ref_trie_foreach(param_map, _interpreter_foreach_insert_param, into); @@ -750,7 +755,7 @@ libab_result _interpreter_perform_function_call(struct interpreter_state* state, function_type = libab_ref_get(&function_value->type); new_params = params->size - function->params.size; - result = _interpreter_create_scope(&new_scope, &function->scope, param_map); + result = _interpreter_create_scope(state->ab, &new_scope, &function->scope, param_map); if(result != LIBAB_SUCCESS) { libab_ref_null(into); @@ -789,7 +794,7 @@ libab_result _interpreter_cast_and_perform_function_call( function = libab_ref_get(&function_value->data); result = libab_ref_vec_init_copy(&new_params, &function->params); if (result == LIBAB_SUCCESS) { - result = _interpreter_cast_params(params, new_types, &new_params); + result = _interpreter_cast_params(state->ab, params, new_types, &new_params); if (result == LIBAB_SUCCESS) { result = _interpreter_perform_function_call(state, to_call, @@ -1117,7 +1122,7 @@ libab_result _interpreter_create_function_value( libab_ref_null(&type); libab_ref_null(into); - result = libab_create_function_tree(&function, libab_free_function, tree, scope); + result = libab_create_function_tree(state->ab, &function, libab_free_function, tree, scope); if(result == LIBAB_SUCCESS) { libab_ref_free(&type); @@ -1126,7 +1131,7 @@ libab_result _interpreter_create_function_value( if(result == LIBAB_SUCCESS) { libab_ref_free(into); - result = libab_create_value_ref(into, &function, &type); + result = libab_create_value_ref(state->ab, into, &function, &type); } if(result != LIBAB_SUCCESS) { @@ -1175,7 +1180,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree, (mode == SCOPE_NORMAL && libab_tree_has_scope(tree->variant)); if (needs_scope) { - result = libab_create_table(&new_scope, scope); + result = libab_create_table(state->ab, &new_scope, scope); scope = &new_scope; } diff --git a/src/libabacus.c b/src/libabacus.c index 757591d..f0a95a9 100644 --- a/src/libabacus.c +++ b/src/libabacus.c @@ -27,6 +27,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*), int interpreter_initialized = 0; libab_ref null_ref; libab_result result; + libab_gc_list_init(&ab->containers); libab_ref_null(&null_ref); libab_ref_null(&ab->type_num); libab_ref_null(&ab->type_bool); @@ -34,7 +35,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*), libab_ref_null(&ab->type_unit); ab->impl.parse_num = parse_function; - result = libab_create_table(&ab->table, &null_ref); + result = libab_create_table(ab, &ab->table, &null_ref); if (result == LIBAB_SUCCESS) { libab_ref_free(&ab->type_num); @@ -144,28 +145,29 @@ libab_result libab_register_operator_postfix(libab* ab, const char* op, return _register_operator(ab, op, OPERATOR_POSTFIX, 0, 0, function); } -libab_result _create_value_function_internal(libab_ref* into, libab_ref* type, +libab_result _create_value_function_internal(libab* ab, + libab_ref* into, libab_ref* type, libab_function_ptr func, libab_ref* scope) { libab_ref function_ref; libab_result result = - libab_create_function_internal(&function_ref, libab_free_function, func, scope); + libab_create_function_internal(ab, &function_ref, libab_free_function, func, scope); libab_ref_null(into); if (result == LIBAB_SUCCESS) { libab_ref_free(into); - result = libab_create_value_ref(into, &function_ref, type); + result = libab_create_value_ref(ab, into, &function_ref, type); } libab_ref_free(&function_ref); return result; } -libab_result _create_value_function_list(libab_ref* into, libab_ref* type) { +libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) { libab_ref list_ref; - libab_result result = libab_create_function_list(&list_ref, type); + libab_result result = libab_create_function_list(ab, &list_ref, type); libab_ref_null(into); if (result == LIBAB_SUCCESS) { libab_ref_free(into); - result = libab_create_value_ref(into, &list_ref, type); + result = libab_create_value_ref(ab, into, &list_ref, type); } libab_ref_free(&list_ref); return result; @@ -187,7 +189,7 @@ libab_result _libab_register_function_existing(libab* ab, } else if (old_type->data_u.base == &_basetype_function) { libab_ref new_list; result = - _create_value_function_list(&new_list, &ab->type_function_list); + _create_value_function_list(ab, &new_list, &ab->type_function_list); if (result == LIBAB_SUCCESS) { libab_function_list* list = libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data); @@ -232,7 +234,7 @@ libab_result libab_register_function(libab* ab, const char* name, libab_table_entry* existing_entry; libab_ref function_value; libab_result result = - _create_value_function_internal(&function_value, type, func, &ab->table); + _create_value_function_internal(ab, &function_value, type, func, &ab->table); if (result == LIBAB_SUCCESS) { existing_entry = libab_table_search_filter( @@ -516,6 +518,7 @@ libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope } libab_result libab_free(libab* ab) { + libab_result result = LIBAB_SUCCESS; libab_table_free(libab_ref_get(&ab->table)); libab_ref_free(&ab->table); libab_ref_free(&ab->type_num); @@ -524,5 +527,7 @@ libab_result libab_free(libab* ab) { libab_ref_free(&ab->type_unit); libab_parser_free(&ab->parser); libab_interpreter_free(&ab->intr); - return libab_lexer_free(&ab->lexer); + result = libab_lexer_free(&ab->lexer); + libab_gc_run(&ab->containers); + return result; } diff --git a/src/util.c b/src/util.c index 287b4f1..e024357 100644 --- a/src/util.c +++ b/src/util.c @@ -2,6 +2,7 @@ #include "value.h" #include #include +#include #include "free_functions.h" libab_result libab_convert_lex_result(liblex_result to_convert) { @@ -186,7 +187,29 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate, return result; } -libab_result libab_create_table(libab_ref* into, libab_ref* parent) { +void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) { + if (entry->variant == ENTRY_VALUE) { + libab_gc_visit_children(&entry->data_u.value, visitor, data); + } +} + +void _gc_visit_table_trie(libab_trie_node* parent, libab_visitor_function_ptr visitor, void* data) { + ll_node* head = parent->values.head; + if(parent == NULL) return; + _gc_visit_table_trie(parent->child, visitor, data); + _gc_visit_table_trie(parent->next, visitor, data); + while(head != NULL) { + _gc_visit_table_entry(head->data, visitor, data); + head = head->next; + } +} + +void _gc_visit_table_children(void* parent, libab_visitor_function_ptr visitor, void* data) { + libab_table* table = parent; + libab_gc_visit_children(&table->parent, visitor, data); +} + +libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent) { libab_table* table; libab_result result = LIBAB_SUCCESS; if ((table = malloc(sizeof(*table)))) { @@ -203,12 +226,19 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent) { if (result != LIBAB_SUCCESS) { libab_ref_null(into); + } else { + libab_gc_add(into, _gc_visit_table_children, &ab->containers); } return result; } -libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, - libab_ref* type) { +void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) { + libab_value* value = val; + libab_gc_visit_children(&value->data, visitor, data); +} + +libab_result libab_create_value_ref(libab* ab, libab_ref* into, + libab_ref* data, libab_ref* type) { libab_value* value; libab_result result = LIBAB_SUCCESS; if ((value = malloc(sizeof(*value)))) { @@ -224,12 +254,14 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, if (result != LIBAB_SUCCESS) { libab_ref_null(into); + } else { + libab_gc_add(into, _gc_visit_value_children, &ab->containers); } return result; } -libab_result libab_create_value_raw(libab_ref* into, void* data, - libab_ref* type) { +libab_result libab_create_value_raw(libab* ab, libab_ref* into, + void* data, libab_ref* type) { libab_value* value; libab_result result = LIBAB_SUCCESS; @@ -249,12 +281,19 @@ libab_result libab_create_value_raw(libab_ref* into, void* data, if (result != LIBAB_SUCCESS) { libab_ref_null(into); free(value); + } else { + libab_gc_add(into, _gc_visit_value_children, &ab->containers); } return result; } -libab_result libab_create_function_internal(libab_ref* into, +void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) { + libab_function* func = function; + libab_gc_visit_children(&func->scope, visitor, data); +} + +libab_result libab_create_function_internal(libab* ab, libab_ref* into, void (*free_function)(void*), libab_function_ptr fun, libab_ref* scope) { @@ -277,12 +316,14 @@ libab_result libab_create_function_internal(libab_ref* into, if (result != LIBAB_SUCCESS) { libab_ref_null(into); free(new_function); + } else { + libab_gc_add(into, _gc_visit_function_children, &ab->containers); } return result; } -libab_result libab_create_function_tree(libab_ref* into, +libab_result libab_create_function_tree(libab* ab, libab_ref* into, void (*free_function)(void*), libab_tree* tree, libab_ref* scope) { @@ -305,12 +346,14 @@ libab_result libab_create_function_tree(libab_ref* into, if (result != LIBAB_SUCCESS) { libab_ref_null(into); free(new_function); + } else { + libab_gc_add(into, _gc_visit_function_children, &ab->containers); } return result; } -libab_result libab_create_function_behavior(libab_ref* into, +libab_result libab_create_function_behavior(libab* ab, libab_ref* into, void (*free_function)(void*), libab_behavior* behavior, libab_ref* scope) { @@ -333,12 +376,14 @@ libab_result libab_create_function_behavior(libab_ref* into, if(result != LIBAB_SUCCESS) { libab_ref_null(into); free(new_function); + } else { + libab_gc_add(into, _gc_visit_function_children, &ab->containers); } return result; } -libab_result libab_create_function_list(libab_ref* into, libab_ref* type) { +libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type) { libab_function_list* list; libab_result result = LIBAB_SUCCESS; @@ -360,6 +405,8 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) { if (result != LIBAB_SUCCESS) { libab_ref_null(into); free(list); + } else { + libab_gc_add(into, _gc_visit_function_children, &ab->containers); } return result;