diff --git a/lang/compile.py b/lang/compile.py index f05fb6d..77f945b 100755 --- a/lang/compile.py +++ b/lang/compile.py @@ -484,12 +484,13 @@ return 'IRMetadata(id=%s, name=%s, uses=%s)' % (self.id, self.name, self.uses) class IRClass(): - def __init__(self, name, functions): + def __init__(self, name, functions, args_len): self.name = name self.functions = functions + self.args_len = args_len def __repr__(self): - return 'IRClass(name=%s, functions=%s)' % (self.name, self.functions) + return 'IRClass(name=%s, functions=%s, args_len=%i)' % (self.name, self.functions, self.args_len) ## IR Generator @@ -668,7 +669,8 @@ if metadata is None: print("Unable to find module metadata?") return None - return IRClass(metadata.name, []) + args_len = len(metadata.uses) + return IRClass(metadata.name, [], args_len) def map_class_functions(functions, classes): mapped_classes = [] @@ -682,7 +684,8 @@ print("Unknown class %s" % (name)) return None funcs = functions[name] - new_class = IRClass(name, funcs) + args_len = class_.args_len + new_class = IRClass(name, funcs, args_len) mapped_classes.append(new_class) return mapped_classes @@ -950,40 +953,21 @@ return "static const unsigned char bytecode_%s_%s [] = {%s};\n\n" \ % (node.class_, node.name, c_bytecode) -def generate_module_args(module_args): - return """static ObjectList create_args(VmState state, ObjectList use_modules) { - (void)state; (void)use_modules; - int args_count = %i; - ObjectList list = object_list_create(state, args_count); - vm_abort_if(state, object_list_length(state, use_modules) < args_count, "create_args: Not enough use_modules"); - for(int i = 0; i < args_count; ++i) { - Object obj = object_list_get(state, use_modules, i); - object_list_set(state, use_modules, i, object_none()); - object_list_set(state, list, i, obj); - } - return list; -} - -static void free_args(VmState state, ObjectList *args) { - for(int i = 0; i < object_list_length(state, *args); ++i) - object_list_set(state, *args, i, object_none()); - object_list_free(state, args); -}""" % (len(module_args)) - -def generate_class_boilerplate(): +def generate_class_boilerplate(args_len): return """static struct object_class CLASSNAME_class; static Object CLASSNAME_create(VmState state, ObjectList use_modules) { Object obj = object_create(state, &CLASSNAME_class, sizeof(ObjectList)); ObjectList *args = (ObjectList *)object_priv(state, obj, &CLASSNAME_class); - *args = create_args(state, use_modules); + *args = use_modules; + vm_abort_if(state, object_list_length(state, use_modules) < %i, "create_args: Not enough use_modules"); return obj; } static void CLASSNAME_cleanup(VmState state, Object obj) { ObjectList *args = (ObjectList *)object_priv(state, obj, &CLASSNAME_class); - free_args(state, args); -}""" + object_list_drop(state, args); +}""" % (args_len) def generate_class_call(class_name, func_name, index): call = '{.name = "%s", .handler = CLASSNAME_call_bytecode, .priv = %s },\n\t' % (func_name, index) @@ -1018,7 +1002,7 @@ def generate_c_class(class_ir): functions = [] - output = generate_class_boilerplate() + output = generate_class_boilerplate(class_ir.args_len) output += "\n\n" output += generate_class_structs(class_ir) output = output.replace('CLASSNAME', class_ir.name) @@ -1063,8 +1047,6 @@ output = generate_header(source) output += "\n\n/* BYTECODES */\n\n" output += bytecodes - output += "/* MODULE ARGS */\n\n" - output += generate_module_args(module_args) output += classes output += "\n\n/* METADATA */\n\n" output += metadata diff --git a/lang/module.c b/lang/module.c index 0601025..b56119f 100644 --- a/lang/module.c +++ b/lang/module.c @@ -143,7 +143,6 @@ abort_print("Too many module use_modules"); } Object module = info->create(state, use_modules); - object_list_free(state, &use_modules); return module; } diff --git a/lang/object.c b/lang/object.c index 8fb4893..1d6a433 100644 --- a/lang/object.c +++ b/lang/object.c @@ -78,6 +78,7 @@ struct object_list { int length; + atomic_int ref_count; Object elems[]; }; @@ -88,6 +89,7 @@ vm_abort_if( state, list == NULL, "object_list_create: not enough memory"); list->length = length; + list->ref_count = 1; for (int i = 0; i < length; ++i) list->elems[i] = object_none(); return list; @@ -109,8 +111,21 @@ return obj; } -void object_list_free(VmState state, ObjectList *list) { +void object_list_hold(VmState state, ObjectList list) { (void)state; - free(*list); - *list = NULL; + atomic_fetch_add_explicit(&list->ref_count, 1, memory_order_relaxed); +} + +void object_list_drop(VmState state, ObjectList *listptr) { + (void)state; + ObjectList list = (ObjectList)*listptr; + atomic_int count = atomic_fetch_sub_explicit( + &list->ref_count, 1, memory_order_relaxed); + if (count == 1) { + // We were the last user of the list, clean it up + for (int i = 0; i < list->length; ++i) + object_drop(state, &(list->elems[i])); + free(list); + } + *listptr = NULL; } diff --git a/lang/object.h b/lang/object.h index 517addc..6b5c4e0 100644 --- a/lang/object.h +++ b/lang/object.h @@ -54,9 +54,11 @@ // A new reference is created for the caller Object object_list_get(VmState state, ObjectList list, int index); -// Frees a list of objects -// This doesn't drop any references to objects -// Sets list to NULL -void object_list_free(VmState state, ObjectList *list); +// Adds a reference to an object list +void object_list_hold(VmState state, ObjectList list); + +// Drops a reference to an object list, possibly cleaning its contents +// Sets listptr to NULL +void object_list_drop(VmState state, ObjectList *listptr); #endif diff --git a/lang/vm.c b/lang/vm.c index 2f2dbef..1c47406 100644 --- a/lang/vm.c +++ b/lang/vm.c @@ -35,7 +35,7 @@ void vm_destroy(VmState *state) { struct vm_state **priv = (struct vm_state **)state; - object_list_free(*state, &(*priv)->stack); + object_list_drop(*state, &(*priv)->stack); free((*priv)->stack_trace); free(*priv); }