DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

commit ea03f224ef9647514545a56168f6bf065039bce4
parent c4e963983d4a234f56bacfb0b0c95e452bee3885
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Fri, 20 Sep 2024 15:44:49 +0200

Start gc

Diffstat:
Mzlox/src/comptime_utils.zig | 14++++++++++++++
Mzlox/src/gc.zig | 24+++++++++++++++++++++++-
Mzlox/src/list.zig | 10++++++++--
Mzlox/src/obj.zig | 37++++++++++++++++++++++++++++++-------
Mzlox/src/obj/closure.zig | 4+---
Mzlox/src/obj/function.zig | 4+---
Mzlox/src/obj/list.zig | 8+++++---
Mzlox/src/obj/native.zig | 4+---
Mzlox/src/obj/string.zig | 4+---
Mzlox/src/obj/table.zig | 4+---
Mzlox/src/obj/upvalue.zig | 4+---
Mzlox/src/table.zig | 10++++++++--
Mzlox/src/value.zig | 7+++++++
13 files changed, 101 insertions(+), 33 deletions(-)

diff --git a/zlox/src/comptime_utils.zig b/zlox/src/comptime_utils.zig @@ -23,3 +23,17 @@ pub fn tagFromType(T: type, U: type) std.meta.Tag(T) { pub fn fn_error(comptime fun: anytype) type { return @typeInfo(@typeInfo(@TypeOf(fun)).@"fn".return_type.?).error_union.error_set; } + +pub fn param_type(comptime fun: anytype, idx: comptime_int) type { + return @TypeOf(fun).@"fn".params[idx].type.?; +} + +pub fn if_not_null(comptime fun: anytype) fn (?param_type(fun, 0)) void { + return struct { + pub fn function(arg: ?param_type(fun, 0)) void { + if (arg) |a| { + _ = fun(a); + } + } + }.function; +} diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig @@ -9,10 +9,19 @@ pub const GC = struct { const List = list.List(*Obj); + const DBG_STRESS = true; + const DBG_LOG = true; + allocator: std.mem.Allocator, table: Obj.String.Table, list: List, + fn dbg_print(comptime fmt: []const u8, args: anytype) void { + if (DBG_LOG) { + std.debug.print("[GC] " ++ fmt, args); + } + } + pub fn init(allocator: std.mem.Allocator) !Self { return Self{ .allocator = allocator, @@ -21,13 +30,25 @@ pub const GC = struct { }; } + fn collect(self: *Self) void { + dbg_print("Collection begin\n", .{}); + _ = self; + dbg_print("Collection end\n", .{}); + } + pub fn emplace(self: *Self, comptime tp: Obj.Type, arg: tp.get().Arg) (List.Error || tp.get().Error)!*tp.get() { var newObj = true; const obj = switch (tp) { .String => try Obj.String.intern(arg, &self.table, &newObj, self.allocator), else => try tp.get().init(arg, self.allocator), }; - if (newObj) try self.list.push(obj.cast()); + if (newObj) { + if (DBG_STRESS) { + // self.collect(); + } + dbg_print("Allocating {} at 0x{x}: {s}\n", .{obj.obj.type, @intFromPtr(obj), obj}); + try self.list.push(obj.cast()); + } return obj; } @@ -38,6 +59,7 @@ pub const GC = struct { pub fn deinit(self: *Self) void { while (true) { const el = self.list.pop() catch break; + dbg_print("Freeing {} at 0x{x}: {s}\n", .{el.type, @intFromPtr(el), el}); el.free(self.allocator); } self.list.free(); diff --git a/zlox/src/list.zig b/zlox/src/list.zig @@ -206,14 +206,20 @@ pub fn List(T: type) type { pub fn for_each(self: *const Self, arg: anytype, fun: fn (@TypeOf(arg), ?T) void) void { var end = self.end; while (end) |el| : (end = el.prev) { - fun(arg, el.val); + if (@TypeOf(arg) == void) + fun(el.val) + else + fun(arg, el.val); } } pub fn for_each_try(self: *const Self, arg: anytype, fun: anytype) utils.fn_error(fun)!void { var end = self.end; while (end) |el| : (end = el.prev) { - try fun(arg, el.val); + if (@TypeOf(arg) == void) + try fun(el.val) + else + try fun(arg, el.val); } } }; diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig @@ -1,10 +1,18 @@ const std = @import("std"); const utils = @import("comptime_utils.zig"); +fn nameOf(fqn: []const u8) []const u8 { + if (std.mem.lastIndexOf(u8, fqn, ".")) |index| { + return fqn[index + 1 ..]; + } + return fqn; +} + pub const Obj = packed struct { - const Super = @This(); + const Self = @This(); type: Type, + marked: bool, pub const List = @import("obj/list.zig").List; pub const String = @import("obj/string.zig").String; @@ -34,32 +42,47 @@ pub const Obj = packed struct { Upvalue, pub fn get(comptime self: @This()) type { - return @field(Super, @tagName(self)); + return @field(Self, @tagName(self)); } }; - pub fn init(comptime tp: Type, arg: tp.get().Arg, allocator: std.mem.Allocator) !*Super { + pub fn make(child: type) Self { + return Self { + .type = @field(Type, nameOf(@typeName(child))), + .marked = false + }; + } + + pub fn mark(self: *Self) void { + self.marked = true; + switch (self.type) { + inline .List, .Table => |tp| self._cast(tp).mark(), + else => {} + } + } + + pub fn init(comptime tp: Type, arg: tp.get().Arg, allocator: std.mem.Allocator) !*Self { return (try tp.get().init(arg, allocator)).cast(); } - pub fn format(self: *const Super, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { switch (self.type) { inline else => |tp| try self._cast(tp).format(fmt, options, writer), } } - pub fn eql(self: *const Super, other: *const Super) bool { + pub fn eql(self: *const Self, other: *const Self) bool { if (!self.is(other.type)) return false; return switch (self.type) { inline else => |tp| self._cast(tp).eql(other._cast(tp)), }; } - pub fn free(obj: *Super, allocator: std.mem.Allocator) void { + pub fn free(obj: *Self, allocator: std.mem.Allocator) void { return switch (obj.type) { inline else => |tp| obj._cast(tp).free(allocator), }; } - pub fn is(self: *const Super, tp: Type) bool { + pub fn is(self: *const Self, tp: Type) bool { return self.type == tp; } diff --git a/zlox/src/obj/closure.zig b/zlox/src/obj/closure.zig @@ -17,9 +17,7 @@ pub const Closure = packed struct { pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.Closure, - }, + .obj = Super.make(Self), .upvalues = (try allocator.alloc(?*Super.Upvalue, arg.upvalue_count)).ptr, .upvalues_len = arg.upvalue_count, .function = arg, diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig @@ -25,9 +25,7 @@ pub const Function = packed struct { pub fn init(tp: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.Function, - }, + .obj = Super.make(Self), .chunk = try allocator.create(chunk.Chunk), .arity = 0, .name = null, diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig @@ -20,9 +20,7 @@ pub const List = packed struct { pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.List, - }, + .obj = Super.make(Self), .list = try allocator.create(Self.List) }; self.list.* = Self.List.init(allocator); @@ -58,6 +56,10 @@ pub const List = packed struct { _ = try writer.writeAll("]"); } + pub fn mark(self: *Self) void { + self.list.for_each({}, utils.if_not_null(Value.mark)); + } + pub fn eql(self: *const Self, other: *const Self) bool { return self.list.eql(other.list, Value.eql); } diff --git a/zlox/src/obj/native.zig b/zlox/src/obj/native.zig @@ -31,9 +31,7 @@ pub const Native = packed struct { pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.Native, - }, + .obj = Super.make(Self), .fun = arg.fun, .arity_min = arg.arity_min, .arity_max = arg.arity_max, diff --git a/zlox/src/obj/string.zig b/zlox/src/obj/string.zig @@ -23,9 +23,7 @@ pub const String = packed struct { fn new(arg: Arg, params: ArgParams, allocator: std.mem.Allocator) Error!*Self { const ret: *Self = @ptrCast(try allocator.alignedAlloc(u8, @alignOf(Self), @sizeOf(Self) + params.len)); ret.* = Self{ - .obj = Super{ - .type = Super.Type.String, - }, + .obj = Super.make(Self), .hash = params.hash, }; for (arg) |el| { diff --git a/zlox/src/obj/table.zig b/zlox/src/obj/table.zig @@ -19,9 +19,7 @@ pub const Table = packed struct { pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.Table, - }, + .obj = Super.make(Self), .table = try allocator.create(Self.Table), .len = 0, }; diff --git a/zlox/src/obj/upvalue.zig b/zlox/src/obj/upvalue.zig @@ -18,9 +18,7 @@ pub const Upvalue = packed struct { pub fn init(arg: Arg, allocator: std.mem.Allocator) Error!*Self { const self: *Self = try allocator.create(Self); self.* = Self{ - .obj = Super{ - .type = Super.Type.Upvalue, - }, + .obj = Super.make(Self), .location = arg.val, .closed = false, .slot = arg.slot diff --git a/zlox/src/table.zig b/zlox/src/table.zig @@ -91,7 +91,10 @@ pub fn Table(K: type, V: type, hash_fn: fn (K) u32, cmp_fn: fn (K, K) bool) type pub fn for_each(self: *const Self, arg: anytype, fun: fn (@TypeOf(arg), K, V) void) void { for (self.entries) |entry| { switch (entry) { - .some => |some| fun(arg, some.key, some.value), + .some => |some| if (@TypeOf(arg) == void) + fun(some.key, some.value) + else + fun(arg, some.key, some.value), else => {}, } } @@ -100,7 +103,10 @@ pub fn Table(K: type, V: type, hash_fn: fn (K) u32, cmp_fn: fn (K, K) bool) type pub fn for_each_try(self: *const Self, arg: anytype, fun: anytype) utils.fn_error(fun)!void { for (self.entries) |entry| { switch (entry) { - .some => |some| try fun(arg, some.key, some.value), + .some => |some| if (@TypeOf(arg) == void) + try fun(some.key, some.value) + else + try fun(arg, some.key, some.value), else => {}, } } diff --git a/zlox/src/value.zig b/zlox/src/value.zig @@ -91,4 +91,11 @@ pub const Value = union(enum) { .obj => |x| x.eql(other.obj), }; } + + pub fn mark(self: Self) void { + switch(self) { + .obj => |x| x.mark(), + else => {} + } + } };