commit a3ec95884dae6f80c5a3e9f8f2d3b425a53e1b56
parent 6883315460175834a896139a80400514706f150b
Author: Szymon Mikulicz <szymon.mikulicz@posteo.net>
Date: Tue, 18 Aug 2026 14:06:11 +0200
Marking stack
Diffstat:
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())));
}
};