diff --git a/lang/bytecode.c b/lang/bytecode.c index 9b74196..1df1c22 100644 --- a/lang/bytecode.c +++ b/lang/bytecode.c @@ -169,10 +169,10 @@ case OP_GET_ARG: { debug_msg("OP_GET_ARG %i\n", *pos_code); int index = *pos_code++; - vm_abort_if(state, args->length <= index, + vm_abort_if(state, + object_list_length(state, args) <= index, "argument out of range"); - Object obj = args->elems[index]; - object_hold(state, obj); + Object obj = object_list_get(state, args, index); vm_stack_push(state, obj); break; } diff --git a/lang/compile.py b/lang/compile.py index 2f9f388..f05fb6d 100755 --- a/lang/compile.py +++ b/lang/compile.py @@ -951,34 +951,37 @@ % (node.class_, node.name, c_bytecode) def generate_module_args(module_args): - return """static struct object_list *create_args(VmState state, struct object_list *use_modules) { + return """static ObjectList create_args(VmState state, ObjectList use_modules) { (void)state; (void)use_modules; int args_count = %i; - struct object_list *list = object_list_create(args_count); - vm_abort_if(state, use_modules->length < args_count, "create_args: Not enough use_modules"); - for(int i = 0; i < args_count; ++i) - list->elems[i] = use_modules->elems[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, struct object_list **args) { - for(int i = 0; i < (*args)->length; ++i) - object_drop(state, &(*args)->elems[i]); - object_list_free(args); +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(): return """static struct object_class CLASSNAME_class; -static Object CLASSNAME_create(VmState state, struct object_list *use_modules) { - Object obj = object_create(state, &CLASSNAME_class, sizeof(struct object_list *)); - struct object_list **args = (struct object_list **)object_priv(state, obj, &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); return obj; } static void CLASSNAME_cleanup(VmState state, Object obj) { - struct object_list **args = (struct object_list **)object_priv(state, obj, &CLASSNAME_class); + ObjectList *args = (ObjectList *)object_priv(state, obj, &CLASSNAME_class); free_args(state, args); }""" diff --git a/lang/module.c b/lang/module.c index 308c5b8..0601025 100644 --- a/lang/module.c +++ b/lang/module.c @@ -127,7 +127,7 @@ // Creates a module and stores it in a mapping Object create_module( VmState state, struct module_mapping *mapping, const ModuleInfo *info) { - struct object_list *use_modules = object_list_create(16); + ObjectList use_modules = object_list_create(state, 16); int use_modules_next = 0; for (const char **use = info->uses; *use != NULL; ++use) { const ModuleInfo *use_info = info_by_name(*use); @@ -136,13 +136,14 @@ Object use_module = get_module_by_info(mapping, use_info); // Create a new reference for the module object_hold(state, use_module); - use_modules->elems[use_modules_next++] = use_module; + object_list_set( + state, use_modules, use_modules_next++, use_module); // Check there's enough room left for this - if (use_modules->length < use_modules_next) + if (object_list_length(state, use_modules) < use_modules_next) abort_print("Too many module use_modules"); } Object module = info->create(state, use_modules); - object_list_free(&use_modules); + object_list_free(state, &use_modules); return module; } diff --git a/lang/object.c b/lang/object.c index 07b1504..8fb4893 100644 --- a/lang/object.c +++ b/lang/object.c @@ -76,19 +76,41 @@ vm_abort_msg(state, "dispatch_call: no call found to dispatch"); } -struct object_list *object_list_create(int length) { +struct object_list { + int length; + Object elems[]; +}; + +ObjectList object_list_create(VmState state, int length) { size_t elem_size = sizeof(Object) * length; size_t size = sizeof(struct object_list) + elem_size; - struct object_list *list = calloc(size, 1); - if (list == NULL) - abort_print("object_list_create: not enough memory"); + ObjectList list = calloc(size, 1); + vm_abort_if( + state, list == NULL, "object_list_create: not enough memory"); list->length = length; for (int i = 0; i < length; ++i) list->elems[i] = object_none(); return list; } -void object_list_free(struct object_list **list) { +int object_list_length(VmState state, ObjectList list) { + (void)state; + return list->length; +} + +void object_list_set(VmState state, ObjectList list, int index, Object obj) { + object_drop(state, &(list->elems[index])); + list->elems[index] = obj; +} + +Object object_list_get(VmState state, ObjectList list, int index) { + Object obj = list->elems[index]; + object_hold(state, obj); + return obj; +} + +void object_list_free(VmState state, ObjectList *list) { + (void)state; free(*list); *list = NULL; } diff --git a/lang/object.h b/lang/object.h index 1ff70bf..517addc 100644 --- a/lang/object.h +++ b/lang/object.h @@ -39,20 +39,24 @@ // Calls a method on an object void dispatch_call(VmState state, Object obj, const char *name); -// List of objects -struct object_list { - int length; - Object elems[]; -}; - -// Creates a list of objects -// This doesn't hold any references to objects +// Creates a list of objects with a specific length // All objects are initialized to object_none -struct object_list *object_list_create(int length); +ObjectList object_list_create(VmState state, int length); + +// Gets the length of an object list +int object_list_length(VmState state, ObjectList list); + +// Sets an element in the object list +// The object's reference is taken from the caller +void object_list_set(VmState state, ObjectList list, int index, Object obj); + +// Gets an element from the object list +// 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(struct object_list **list); +void object_list_free(VmState state, ObjectList *list); #endif diff --git a/lang/types.h b/lang/types.h index 3e316a0..2835e7d 100644 --- a/lang/types.h +++ b/lang/types.h @@ -8,6 +8,10 @@ struct object; typedef struct object *Object; +// Opaque type for an object list +struct object_list; +typedef struct object_list *ObjectList; + // Opaque type for the VM state struct vm_state; typedef struct vm_state *VmState; diff --git a/lang/vm.c b/lang/vm.c index 974c9e5..2f2dbef 100644 --- a/lang/vm.c +++ b/lang/vm.c @@ -12,7 +12,7 @@ #include struct vm_state { - struct object_list *stack; + ObjectList stack; int stack_base; int stack_next; Object tail_obj; @@ -28,14 +28,14 @@ state->stack_next = 0; state->tail_obj = object_none(); state->tail_name = NULL; - state->stack = object_list_create(16); + state->stack = object_list_create(state, 16); state->stack_trace = stacktrace_create(32); return (VmState)state; } void vm_destroy(VmState *state) { struct vm_state **priv = (struct vm_state **)state; - object_list_free(&(*priv)->stack); + object_list_free(*state, &(*priv)->stack); free((*priv)->stack_trace); free(*priv); } @@ -46,9 +46,7 @@ vm_abort_if(state, index < 0, "vm_stack_set: negative value"); vm_abort_if(state, offset >= priv->stack_next, "vm_stack_set: stack overflow"); - Object *stack_pos = &priv->stack->elems[offset]; - object_drop(state, stack_pos); - *stack_pos = obj; + object_list_set(state, priv->stack, offset, obj); } Object vm_stack_get(VmState state, int index) { @@ -57,8 +55,7 @@ vm_abort_if(state, index < 0, "vm_stack_get: negative value"); vm_abort_if(state, offset >= priv->stack_next, "vm_stack_get: stack overflow"); - Object obj = priv->stack->elems[offset]; - object_hold(state, obj); + Object obj = object_list_get(state, priv->stack, offset); return obj; } @@ -66,20 +63,20 @@ struct vm_state *priv = (struct vm_state *)state; // stack_next starts at 0, stack_size starts at 1 // Convert stack_size to a max stack offset to compensate - int max_stack = priv->stack->length - 1; + int max_stack = object_list_length(state, priv->stack) - 1; // Check if stack_next is outside the stack before // writing to it vm_abort_if(state, priv->stack_next > max_stack, "vm_stack_push: stack overflow"); - priv->stack->elems[priv->stack_next++] = obj; + object_list_set(state, priv->stack, priv->stack_next++, obj); } Object vm_stack_pop(VmState state) { struct vm_state *priv = (struct vm_state *)state; vm_abort_if(state, priv->stack_next <= priv->stack_base, "vm_stack_pop: stack base underflow"); - Object obj = priv->stack->elems[--priv->stack_next]; - priv->stack->elems[priv->stack_next] = object_none(); + Object obj = object_list_get(state, priv->stack, --priv->stack_next); + object_list_set(state, priv->stack, priv->stack_next, object_none()); return obj; }