Add Leak Detection to Ona Heap Allocator #15

Merged
kayomn merged 12 commits from ona-allocator-safety-tracker into main 2023-06-04 16:07:47 +02:00
1 changed files with 26 additions and 33 deletions
Showing only changes of commit 331d862246 - Show all commits

View File

@ -69,21 +69,6 @@ const Object = struct {
self.ref_count += 1; self.ref_count += 1;
} }
pub fn release(self: *Object, env: *Self) bool {
coral.debug.assert(self.ref_count != 0);
self.ref_count -= 1;
if (self.ref_count == 0) {
coral.io.deallocate(env.allocator, self.state.userdata);
self.state.fields.deinit(env.allocator);
return false;
}
return true;
}
}; };
pub const ObjectInfo = struct { pub const ObjectInfo = struct {
@ -185,14 +170,7 @@ pub fn check(self: *Self, condition: bool, failure_message: []const u8) !void {
} }
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
var global_data = self.heap.fetch(self.global_object); self.discard(.{.object = self.global_object});
if (global_data.release(self)) {
self.heap.remove(self.global_object);
} else {
self.heap.assign(self.global_object, global_data);
}
self.values.deinit(self.allocator); self.values.deinit(self.allocator);
self.calls.deinit(self.allocator); self.calls.deinit(self.allocator);
self.heap.deinit(self.allocator); self.heap.deinit(self.allocator);
@ -203,7 +181,19 @@ pub fn discard(self: *Self, val: types.Val) void {
.object => |object| { .object => |object| {
var data = self.heap.fetch(object); var data = self.heap.fetch(object);
if (data.release(self)) { coral.debug.assert(data.ref_count != 0);
data.ref_count -= 1;
kayomn marked this conversation as resolved Outdated

May be worth adding an assert to check that the VM environment heap is empty by now before calling deinit.

May be worth adding an assert to check that the VM environment heap is empty by now before calling deinit.
if (data.ref_count == 0) {
data.state.info.deinitializer(.{
.env = self,
.obj = val.as_ref(),
});
coral.io.deallocate(self.allocator, data.state.userdata);
data.state.fields.deinit(self.allocator);
self.heap.remove(object); self.heap.remove(object);
} else { } else {
self.heap.assign(object, data); self.heap.assign(object, data);
@ -223,6 +213,7 @@ pub fn execute_data(self: *Self, source: DataSource) types.RuntimeError!types.Va
} }
}; };
var compiled_chunk = init_compiled_chunk: {
var chunk = try Chunk.init(self, source.name); var chunk = try Chunk.init(self, source.name);
errdefer chunk.deinit(); errdefer chunk.deinit();
@ -233,7 +224,10 @@ pub fn execute_data(self: *Self, source: DataSource) types.RuntimeError!types.Va
return compile_error; return compile_error;
}; };
const script = try self.new_object(coral.io.bytes_of(&chunk), .{ break: init_compiled_chunk chunk;
};
const script = try self.new_object(coral.io.bytes_of(&compiled_chunk), .{
.identity = typeid, .identity = typeid,
.deinitializer = Behaviors.deinitialize, .deinitializer = Behaviors.deinitialize,
}); });
@ -355,12 +349,11 @@ pub fn native_cast(self: *Self, castable: types.Ref, id: *const anyopaque, compt
try self.check(castable == .object, "invalid type conversion: object"); try self.check(castable == .object, "invalid type conversion: object");
const object = self.heap.fetch(castable.object); const object = self.heap.fetch(castable.object);
const alignment = @alignOf(Type); const is_expected_type = (object.state.info.identity == id) and (object.state.userdata.len == @sizeOf(Type));
const is_expected_type = (object.state.info.identity == id) and (object.state.userdata.len == alignment);
try self.check(is_expected_type, "invalid object cast: native type"); try self.check(is_expected_type, "invalid object cast: native type");
return @ptrCast(*Type, @alignCast(alignment, object.state.userdata)); return @ptrCast(*Type, @alignCast(@alignOf(Type), object.state.userdata));
} }
pub fn new_array(self: *Self) coral.io.AllocationError!types.Val { pub fn new_array(self: *Self) coral.io.AllocationError!types.Val {