DzLox

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

commit a3ec95884dae6f80c5a3e9f8f2d3b425a53e1b56
parent 6883315460175834a896139a80400514706f150b
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date:   Tue, 18 Aug 2026 14:06:11 +0200

Marking stack

Diffstat:
Mzlox/fib.lox | 11++++-------
Mzlox/src/gc.zig | 70++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mzlox/src/list.zig | 42++++++++++++++++++++++--------------------
Mzlox/src/obj.zig | 2+-
Mzlox/src/obj/function.zig | 2+-
Mzlox/src/obj/string.zig | 5+++--
Mzlox/src/vm.zig | 13++++++++-----
Mzlox/src/vm/native.zig | 2+-
8 files changed, 88 insertions(+), 59 deletions(-)

diff --git a/zlox/fib.lox b/zlox/fib.lox @@ -18,15 +18,12 @@ fun printf(fmt, args) { } fun main() { - con num = 25; + con num = 28; con start = clock(); + con result = fib(num); + con end = clock() - start; - con args = []; - args[0] = num; - args[1] = fib(num); - args[2] = clock() - start; - - printf("fib({}) == {}, time: {}", args); + printf("fib({}) == {}, time: {} ms", [num, result, end]); } main(); diff --git a/zlox/src/gc.zig b/zlox/src/gc.zig @@ -12,8 +12,17 @@ pub const GC = struct { const List = list.List(*Obj); - pub const CallbackArg = *anyopaque; - pub const Callback = *const fn (CallbackArg) void; + pub const Callback = struct { + pub const Arg = *anyopaque; + pub const Fn = *const fn (Arg) void; + + arg: Arg, + @"fn": Fn, + + pub fn call(self: *const @This()) void { + self.@"fn"(self.arg); + } + }; const DBG_STRESS = true; const DBG_LOG = true; @@ -22,8 +31,7 @@ pub const GC = struct { io: std.Io, table: Obj.String.Table, list: List, - callback: ?Callback, - callback_arg: ?CallbackArg, + callbacks: list.List(Callback), fn dbg_print(comptime fmt: []const u8, args: anytype) void { if (DBG_LOG) { @@ -37,29 +45,45 @@ pub const GC = struct { .io = io, .table = Obj.String.Table.init(allocator), .list = List.init(allocator), - .callback = null, - .callback_arg = null, + .callbacks = list.List(Callback).init(allocator), }; } fn collect(self: *Self) void { - dbg_print("Collection begin\n", .{}); - if (self.callback) |callback| { - if (self.callback_arg) |callback_arg| { - callback(callback_arg); + self.callbacks.for_each({}, struct { + pub fn fun(cb_ptr: ?Callback) void { + if (cb_ptr) |cb| { + cb.call(); + } } - } - dbg_print("Collection end\n", .{}); + }.fun); } - pub fn set_callback(self: *Self, callback: Callback, callback_arg: CallbackArg) void { - self.callback = callback; - self.callback_arg = callback_arg; + pub fn push_callback(self: *Self, callback: Callback.Fn, arg: Callback.Arg) !void { + try self.callbacks.push(Callback{ .@"fn" = callback, .arg = arg }); } - pub fn reset_callback(self: *Self) void { - self.callback = null; - self.callback_arg = null; + pub fn pop_callback(self: *Self) void { + _ = self.callbacks.pop() catch return; + } + + pub fn dbg_obj(info: []const u8, obj: anytype, comptime prin: bool) void { + if (prin) { + dbg_print("[{s}] {s: <8} [{s}] 0x{x} {f}\n", .{ + info, + @tagName(obj.type), + if (obj.fields.mark) "X" else " ", + @intFromPtr(obj), + obj, + }); + } else { + dbg_print("[{s}] {s: <8} [{s}] 0x{x}\n", .{ + info, + @tagName(obj.type), + if (obj.fields.mark) "X" else " ", + @intFromPtr(obj), + }); + } } pub fn emplace(self: *Self, comptime tp: Obj.Type, arg: tp.get().Arg) (List.Error || tp.get().Error)!*tp.get() { @@ -72,7 +96,7 @@ pub const GC = struct { if (DBG_STRESS) { self.collect(); } - dbg_print("Allocating {any} at 0x{x}: {f}\n", .{ obj.obj.type, @intFromPtr(obj), obj }); + dbg_obj("A", &obj.obj, true); try self.list.push(obj.cast()); } return obj; @@ -105,7 +129,8 @@ pub const GC = struct { else => {}, }, *Obj => { - dbg_print("Marking {any} at 0x{x}: {f}\n", .{ arg.type, @intFromPtr(arg), arg }); + dbg_obj("M", arg, true); + arg.fields.mark = true; switch (arg.type) { .Function => if ((arg.cast(.Function) catch unreachable).name.ptr()) |name| { @@ -115,7 +140,7 @@ pub const GC = struct { } }, *const Obj => { - dbg_print("Skipping const {any} at 0x{x}: {f}\n", .{ arg.type, @intFromPtr(arg), arg }); + dbg_obj("S", arg, true); }, else => if (comptime Obj.isChild(T)) { mark(arg.cast()); @@ -132,9 +157,10 @@ pub const GC = struct { pub fn deinit(self: *Self) void { while (true) { const el = self.list.pop() catch break; - dbg_print("Freeing {any} at 0x{x}\n", .{ el.type, @intFromPtr(el) }); + dbg_obj("F", el, false); el.free(self.allocator); } + self.callbacks.free(); self.list.free(); self.table.deinit(); } diff --git a/zlox/src/list.zig b/zlox/src/list.zig @@ -27,7 +27,7 @@ pub fn List(T: type) type { }; } - pub fn eql(self: *const Self, other: *const Self, eql_fn: fn(T, T) bool) bool { + pub fn eql(self: *const Self, other: *const Self, eql_fn: fn (T, T) bool) bool { if (self.len != other.len) return false; if (self.len == 0) return true; var tip1 = self.tip; @@ -48,7 +48,9 @@ pub fn List(T: type) type { } pub fn free(self: *Self) void { - while (true) {_ = self.pop() catch return;} + while (true) { + _ = self.pop() catch return; + } } pub fn get(self: *const Self, index: usize) Error!T { @@ -61,13 +63,13 @@ pub fn List(T: type) type { if (idx < idx_rev) { var tip = self.tip; - while(idx > 1) : (idx -= 1) { + while (idx > 1) : (idx -= 1) { tip = tip.?.next; } return tip.?.val orelse Error.IndexOutOfBounds; } else { var end = self.end; - while(idx_rev > 1) : (idx_rev -= 1) { + while (idx_rev > 1) : (idx_rev -= 1) { end = end.?.prev; } return end.?.val orelse Error.IndexOutOfBounds; @@ -81,20 +83,20 @@ pub fn List(T: type) type { var isNewVal = false; if (idx <= 0) { - while(idx < 0) : (idx += 1) { + while (idx < 0) : (idx += 1) { try self._push(null); } try self._push(val); isNewVal = true; } else if (idx < idx_rev) { var tip = self.tip; - while(idx > 1) : (idx -= 1) { + while (idx > 1) : (idx -= 1) { tip = tip.?.next; } tip.?.val = val; } else { var end = self.end; - while(idx_rev > 1) : (idx_rev -= 1) { + while (idx_rev > 1) : (idx_rev -= 1) { end = end.?.prev; } end.?.val = val; @@ -116,30 +118,30 @@ pub fn List(T: type) type { } pub fn insert_before(self: *Self, element: ?*Element, val: T) Error!void { - if(element) |el| { - if(el.prev) |prev| { + if (element) |el| { + if (el.prev) |prev| { const new = try self.allocator.create(Element); - new.* = .{.val = val, .next = el, .prev = prev}; + new.* = .{ .val = val, .next = el, .prev = prev }; prev.next = new; el.prev = new; self.len += 1; return; - } - } + } + } try self.push(val); } pub fn insert_after(self: *Self, element: ?*Element, val: T) Error!void { - if(element) |el| { - if(el.next) |next| { + if (element) |el| { + if (el.next) |next| { const new = try self.allocator.create(Element); - new.* = .{.val = val, .next = next, .prev = el}; + new.* = .{ .val = val, .next = next, .prev = el }; next.prev = new; el.next = new; self.len += 1; return; - } - } + } + } try self.push_end(val); } @@ -177,7 +179,7 @@ pub fn List(T: type) type { if (self.tip) |old_tip| { old_tip.prev = new_tip; } - new_tip.* = Element{.val = val, .next = self.tip, .prev = null}; + new_tip.* = Element{ .val = val, .next = self.tip, .prev = null }; self.tip = new_tip; self.len += 1; } @@ -194,7 +196,7 @@ pub fn List(T: type) type { if (self.end) |old_end| { old_end.next = new_end; } - new_end.* = Element{.val = val, .prev = self.end, .next = null}; + new_end.* = Element{ .val = val, .prev = self.end, .next = null }; self.end = new_end; self.len += 1; } @@ -203,7 +205,7 @@ pub fn List(T: type) type { return self._push_end(val); } - pub fn for_each(self: *const Self, arg: anytype, fun: fn (@TypeOf(arg), ?T) void) void { + pub fn for_each(self: *const Self, arg: anytype, fun: if (@TypeOf(arg) == void) fn (?T) void else fn (@TypeOf(arg), ?T) void) void { var end = self.end; while (end) |el| : (end = el.prev) { if (@TypeOf(arg) == void) diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig @@ -59,7 +59,7 @@ pub fn Obj(fields: anytype) type { return (try tp.get().init(arg, allocator)).cast(); } - pub fn format(self: *const Self, writer: *std.Io.Writer) !void { + pub fn format(self: anytype, writer: *std.Io.Writer) !void { switch (self.type) { inline else => |tp| try self._cast(tp).format(writer), } diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig @@ -48,7 +48,7 @@ pub fn Function(fields: anytype) type { .Function => _ = try writer.write("<F: "), .Script => _ = try writer.write("<S: "), } - if (self.name.get()) |name| { + if (self.name.ptr()) |name| { _ = try writer.write(name.slice()); } else { _ = try writer.write("-"); diff --git a/zlox/src/obj/string.zig b/zlox/src/obj/string.zig @@ -11,7 +11,7 @@ pub fn String(fields: anytype) type { const Self = @This(); pub const Table = table.Table(*Self, void, hash.hash_t(*const Self), Self.eql); pub const Arg = []const []const u8; - pub const Error = error { OutOfMemory, IndexOutOfBounds } || Table.Error; + pub const Error = error{ OutOfMemory, IndexOutOfBounds } || Table.Error; obj: Super, len: usize = 0, @@ -21,6 +21,7 @@ pub fn String(fields: anytype) type { const p: utils.copy_const(@TypeOf(self), [*]u8) = @ptrCast(self); return p + @sizeOf(Self); } + fn new(arg: Arg, params: ArgParams, allocator: std.mem.Allocator) Error!*Self { const ret: *Self = @ptrCast(try allocator.alignedAlloc(u8, std.mem.Alignment.of(Self), @sizeOf(Self) + params.len)); ret.* = Self{ @@ -65,7 +66,7 @@ pub fn String(fields: anytype) type { var idx: usize = 0; for (self.arg) |el| { if (!std.mem.eql(u8, k2.data()[idx .. idx + el.len], el)) - return false; + return false; idx += el.len; } return true; diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -105,8 +105,8 @@ pub const VM = struct { const callstack_size = 64; const stack_size = 256; - self.objects.set_callback(&VM.gc_callback, self); - defer self.objects.reset_callback(); + try self.objects.push_callback(&VM.gc_callback, self); + defer self.objects.pop_callback(); const function = try compiler.Compiler(stack_size).compile(source, &self.objects); @@ -137,8 +137,8 @@ pub const VM = struct { .open_upvalues = List.init(vm.allocator), }; - vm.objects.set_callback(&Self.gc_callback, &self); - defer vm.objects.reset_callback(); + try vm.objects.push_callback(&Self.gc_callback, &self); + defer vm.objects.pop_callback(); defer self.open_upvalues.free(); @@ -151,7 +151,10 @@ pub const VM = struct { pub fn gc_callback(self_ptr: *anyopaque) void { const self: *@This() = @ptrCast(@alignCast(self_ptr)); - VM.gc_callback(self.vm); + var stackPtr: [*]Value = &self.stack; + while (stackPtr != self.stackTop) : (stackPtr += 1) { + GC.mark(stackPtr[0]); + } } fn frame(self: anytype) utils.copy_const(@TypeOf(self), *CallFrame) { diff --git a/zlox/src/vm/native.zig b/zlox/src/vm/native.zig @@ -12,7 +12,7 @@ pub const Clock = struct { } pub fn clock(gc: *GC, _: []const Value) Error!Value { - return Value.init(@as(f64, @floatFromInt(std.Io.Timestamp.untilNow(start, gc.io, std.Io.Clock.awake).toSeconds()))); + return Value.init(@as(f64, @floatFromInt(std.Io.Timestamp.untilNow(start, gc.io, std.Io.Clock.awake).toMilliseconds()))); } };