diff --git a/source/ona/kym.zig b/source/ona/kym.zig index 016ffe9..178311b 100644 --- a/source/ona/kym.zig +++ b/source/ona/kym.zig @@ -142,8 +142,17 @@ pub const RuntimeEnv = struct { coral.debug.assert(frame != null); - coral.debug.assert(self.local_refs.drop( - (self.local_refs.values.len - frame.?.locals_top) + frame.?.arg_count)); + { + var pops_remaining = (self.local_refs.values.len - frame.?.locals_top) + frame.?.arg_count; + + while (pops_remaining != 0) : (pops_remaining -= 1) { + const local = self.local_refs.pop(); + + coral.debug.assert(local != null); + + self.discard(local.?); + } + } } return caller.invoke(self); @@ -160,7 +169,13 @@ pub const RuntimeEnv = struct { if (ref_data.ref_count == 0) { switch (ref_data.object) { .string => |string| self.allocator.deallocate(string), - .dynamic => |virtual| self.allocator.deallocate(virtual), + + .dynamic => |dynamic| { + dynamic.typeinfo.clean(self, dynamic.userdata); + self.allocator.deallocate(dynamic.userdata); + self.allocator.deallocate(dynamic); + }, + else => {}, } } else { @@ -208,6 +223,12 @@ pub const RuntimeEnv = struct { } pub fn free(self: *RuntimeEnv) void { + for (self.local_refs.values) |ref| { + self.discard(ref); + } + + self.frames.free(); + self.syscallers.free(); self.local_refs.free(); self.ref_values.free(); } @@ -362,7 +383,7 @@ pub const TestContext = struct { pub const Typeinfo = struct { name: []const coral.io.Byte, call: *const fn (env: *RuntimeEnv) RuntimeError!?*RuntimeRef = default_call, - clean: *const fn (userdata: []coral.io.Byte) void = default_clean, + clean: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte) void = default_clean, get: *const fn (context: IndexContext) RuntimeError!?*RuntimeRef = default_get, set: *const fn (context: IndexContext, value: ?*const RuntimeRef) RuntimeError!void = default_set, test_difference: *const fn (context: TestContext) RuntimeError!Float = default_test_difference, @@ -372,7 +393,7 @@ pub const Typeinfo = struct { return env.raise(error.TypeMismatch, "object is not callable"); } - fn default_clean(_: []coral.io.Byte) void { + fn default_clean(_: *RuntimeEnv, _: []coral.io.Byte) void { // Nothing to clean by default. } @@ -473,13 +494,7 @@ pub fn set_field( return set(env, indexable_ref, field_name_ref, value_ref); } -pub fn new_table(env: *RuntimeEnv) RuntimeError!?*RuntimeRef { - var table = Table.make(env); - - errdefer table.free(); - - return try env.new_dynamic(coral.io.bytes_of(&table), &Table.typeinfo); -} +pub const new_table = Table.new; pub fn test_difference(env: *RuntimeEnv, lhs_ref: ?*const RuntimeRef, rhs_ref: ?*const RuntimeRef) RuntimeError!Float { return switch (env.unbox(lhs_ref)) { diff --git a/source/ona/kym/Chunk.zig b/source/ona/kym/Chunk.zig index e06002c..c58346f 100644 --- a/source/ona/kym/Chunk.zig +++ b/source/ona/kym/Chunk.zig @@ -211,8 +211,6 @@ pub fn as_caller(self: *Self) kym.Caller { } pub fn compile_ast(self: *Self, ast: Ast) kym.RuntimeError!void { - self.free(); - try self.constant_refs.grow(coral.math.max_int(@typeInfo(u16).Int)); var compiler = AstCompiler{.chunk = self}; diff --git a/source/ona/kym/Table.zig b/source/ona/kym/Table.zig index ac5819f..09ae165 100644 --- a/source/ona/kym/Table.zig +++ b/source/ona/kym/Table.zig @@ -11,14 +11,16 @@ const FieldTable = coral.map.StringTable(struct { const Self = @This(); -pub fn free(self: *Self) void { - self.fields.free(); -} - -pub fn make(env: *kym.RuntimeEnv) Self { - return .{ +pub fn new(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef { + var self = Self{ .fields = FieldTable.make(env.allocator), }; + + errdefer { + self.fields.free(); + } + + return try env.new_dynamic(coral.io.bytes_of(&self), &typeinfo); } pub const typeinfo = kym.Typeinfo{ @@ -28,8 +30,19 @@ pub const typeinfo = kym.Typeinfo{ .set = typeinfo_set, }; -fn typeinfo_clean(userdata: []u8) void { - @as(*Self, @ptrCast(@alignCast(userdata.ptr))).free(); +fn typeinfo_clean(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void { + const table = @as(*Self, @ptrCast(@alignCast(userdata.ptr))); + + { + var field_iterable = table.fields.as_iterable(); + + while (field_iterable.next()) |entry| { + env.discard(entry.value.key_ref); + env.discard(entry.value.value_ref); + } + } + + table.fields.free(); } fn typeinfo_get(context: kym.IndexContext) kym.RuntimeError!?*kym.RuntimeRef {