diff options
| -rw-r--r-- | src/zisp/gc/meta_alloc.zig | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/src/zisp/gc/meta_alloc.zig b/src/zisp/gc/meta_alloc.zig index aa21967..c8d46e1 100644 --- a/src/zisp/gc/meta_alloc.zig +++ b/src/zisp/gc/meta_alloc.zig @@ -99,7 +99,7 @@ const SLAB_LEN: UnitIdx = 1 << 31; /// A slab of memory. const Slab = [SLAB_LEN]Unit; -/// A pointer to a slot of allocated memory; N units depenging on size class. +/// A pointer to a slot of allocated memory; N units depending on size class. const SlotPtr = [*]Unit; /// Size classes. @@ -200,21 +200,59 @@ const TlSlabInfo = struct { /// Thread-local metadata per slab / size class. threadlocal var tl_slab_infos: [SIZES.len]TlSlabInfo = @splat(.{}); -/// Wrapper around std.posix.mmap(). -fn mmap(size: usize) []align(4096) u8 { - return std.posix.mmap( +/// Wrapper around the platform's mmap() or equivalent. The 'commit' argument +/// indicates whether read/write access should already be enabled. If false, +/// one must later use mcommit() to enable part or all of it. +fn mmap(size: usize, commit: bool) [*]align(4096) u8 { + // TODO: MS Windows + const ret = std.c.mmap( null, size, - .{ .READ = true, .WRITE = true }, + .{ .READ = commit, .WRITE = commit }, .{ .TYPE = .PRIVATE, .ANONYMOUS = true }, -1, 0, - ) catch @panic("Syscall mmap() failed."); + ); + if (ret == std.c.MAP_FAILED) { + // TODO: Report reason. + @panic("Failed to map memory."); + } + return @ptrCast(@alignCast(ret)); +} + +/// Signal to the platform that we now require slab[0..idx] to be accessible. +fn mcommit(slab: *Slab, idx: UnitIdx) void { + // TODO: MS Windows + const ptr: *align(4096) anyopaque = @ptrCast(@alignCast(slab)); + const len: usize = idx * @sizeOf(Unit); + const ret = std.c.mprotect( + ptr, + len, + .{ .READ = true, .WRITE = true }, + ); + if (ret == -1) { + // TODO: Report reason. + @panic("Failed to commit memory."); + } +} + +/// Signal to the platform that slab[idx..len] can be discarded, so it doesn't +/// need physical backing memory until we write to it again. This does *not* +/// undo mcommit(), so there is no need to call it again. +fn mdiscard(ptr: [*]const u8, len: usize) void { + // TODO: MS Windows + const ret = std.c.madvise( + ptr, + len, + std.c.MADV.DONTNEED, + ); + // Practically can't happen. + std.debug.assert(ret != -1); } /// Must call this once to initialize the slabs. export fn init() void { - slabs = @ptrCast(mmap(SIZES.len * SLAB_LEN * @sizeOf(Unit))); + slabs = @ptrCast(mmap(SIZES.len * SLAB_LEN * @sizeOf(Unit), false)); } /// Allocate a slot of the given size, which must be a power of two and greater @@ -226,7 +264,7 @@ export fn alloc(size: usize) [*]u8 { @branchHint(.likely); return @ptrCast(alloc_size_class(sci, size)); } else { - return mmap(size).ptr; + return mmap(size, true); } } @@ -237,7 +275,9 @@ export fn free(size: usize, ptr: [*]u8) void { @branchHint(.likely); free_size_class(sci, @ptrCast(@alignCast(ptr))); } else { - std.posix.munmap(@alignCast(ptr[0..size])); + const ret = std.c.munmap(@ptrCast(@alignCast(ptr)), size); + // Practically can't happen. + std.debug.assert(ret != -1); } } @@ -396,6 +436,8 @@ fn alloc_fresh( std.debug.panic("Exhausted slab for size class: {}", .{size}); } + mcommit(slab, new_wm); + tl.wm_hi = new_wm; tl.wm_lo = old_wm + slot_len; return slab[old_wm..].ptr; |
