commit ea03f224ef9647514545a56168f6bf065039bce4
parent c4e963983d4a234f56bacfb0b0c95e452bee3885
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date: Fri, 20 Sep 2024 15:44:49 +0200
Start gc
Diffstat:
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 => {}
+ }
+ }
};