diff --git a/lang/bytecode.c b/lang/bytecode.c index e3d0dcc..f92ba1d 100644 --- a/lang/bytecode.c +++ b/lang/bytecode.c @@ -28,6 +28,7 @@ OP_CALL, 0x2, 'A', 'd', 'd', '\0', OP_DROP, 0x1, OP_SET, 0x0, + OP_DROP, 0x4, OP_RET }; // clang-format on @@ -53,9 +54,11 @@ case OP_CALL: { int arg_count = *pos_code++; const char *dispatch = (const char *)pos_code; - struct object *obj = *(--pos_stack); + struct object *obj = *--pos_stack; struct object **args = pos_stack - arg_count; dispatch_call(obj, dispatch, arg_count, args); + *pos_stack = NULL; + object_drop(&obj); break; } case OP_NULL: { @@ -63,22 +66,28 @@ break; } case OP_GET: { - *pos_stack++ = stack[*pos_code++]; + struct object *obj = stack[*pos_code++]; + object_hold(obj); + *pos_stack++ = obj; break; } case OP_SET: { - stack[*pos_code++] = *--pos_stack; + struct object **obj_old = &stack[*pos_code++]; + struct object *obj_new = *--pos_stack; + if (*obj_old != NULL) { + object_drop(obj_old); + } + *obj_old = obj_new; + // obj_new reference doesn't change break; } case OP_DROP: { - pos_stack -= *pos_code++; + unsigned char count = *pos_code++; + while (count--) { + object_drop(--pos_stack); + } break; } } } - // Clean up the stack - struct object **pos_cleanup = pos_stack - arg_count; - while (pos_cleanup != stack) { - object_drop(pos_cleanup--); - } } diff --git a/lang/func.c b/lang/func.c index 13472cc..83e5cb7 100644 --- a/lang/func.c +++ b/lang/func.c @@ -30,6 +30,13 @@ static void func_call(struct object *obj, int arg_count, struct object **args) { abort_if(arg_count != 1, "func_add called with more than 1 argument"); abort_if(obj->class_data != &func_class, "func_call obj is not a func"); + // We expect the bytecode to clean up the stack, so add additional + // references here so the caller doesn't have to + for (int i = 0; i < arg_count; ++i) { + if (args[i] != NULL) { + object_hold(args[i]); + } + } bytecode_run(args, arg_count); } diff --git a/lang/object.c b/lang/object.c index f360b75..64e7ce4 100644 --- a/lang/object.c +++ b/lang/object.c @@ -6,6 +6,11 @@ #include #include +void object_hold(struct object *obj) { + abort_if(obj == NULL, "object_hold holding NULL"); + atomic_fetch_add_explicit(&obj->ref_count, 1, memory_order_relaxed); +} + void object_drop(struct object **objptr) { abort_if(*objptr == NULL, "object_drop dropping NULL"); struct object *obj = *objptr; diff --git a/lang/object.h b/lang/object.h index dc4be25..78d702f 100644 --- a/lang/object.h +++ b/lang/object.h @@ -31,6 +31,9 @@ *calls; // Points to array terminated by call with NULL name }; +// Adds a reference to an object +void object_hold(struct object *obj); + // Drops a reference to an object, possibly cleaning up the object // Sets objptr to NULL void object_drop(struct object **objptr);