From c0a4f80d80d75f7d3250d12554501fd7197e9bb0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 3 Sep 2026 09:13:36 -0700 Subject: [PATCH] terminal: hash map and ref counted set can initialize from zeroed memory --- src/terminal/hash_map.zig | 27 ++++++++++++++++++++++++--- src/terminal/ref_counted_set.zig | 29 ++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/terminal/hash_map.zig b/src/terminal/hash_map.zig index 6f3b8b3aa..777a3559c 100644 --- a/src/terminal/hash_map.zig +++ b/src/terminal/hash_map.zig @@ -152,8 +152,19 @@ pub fn OffsetHashMap( /// memory. The backing memory must be aligned to base_align. pub fn init(buf: OffsetBuf, l: Layout) Self { assert(base_align.check(@intFromPtr(buf.start()))); + return fromUnmanaged(buf, Unmanaged.init(buf, l)); + } - const m = Unmanaged.init(buf, l); + /// Like `init`, but for backing memory that the caller guarantees + /// is already zero-filled (e.g. fresh OS pages). Only the header + /// is written: all-zero slot metadata already means every slot is + /// free, so the metadata array is left untouched. + pub fn initAssumeZeroed(buf: OffsetBuf, l: Layout) Self { + assert(base_align.check(@intFromPtr(buf.start()))); + return fromUnmanaged(buf, Unmanaged.initAssumeZeroed(buf, l)); + } + + fn fromUnmanaged(buf: OffsetBuf, m: Unmanaged) Self { return .{ .metadata = getOffset( Unmanaged.Metadata, buf, @@ -344,6 +355,17 @@ fn HashMapUnmanaged( /// Initialize a hash map with a given capacity and a buffer. The /// buffer must fit within the size defined by `layoutForCapacity`. pub fn init(buf: OffsetBuf, layout: Layout) Self { + var map = initAssumeZeroed(buf, layout); + map.initMetadatas(); + return map; + } + + /// Like `init`, but for a buffer that the caller guarantees is + /// already zero-filled. Only the header is written: an all-zero + /// metadata byte is a free slot (see `Metadata.isFree`), so the + /// slot metadata is left untouched. Behavior is undefined if the + /// metadata region is not zero. + pub fn initAssumeZeroed(buf: OffsetBuf, layout: Layout) Self { assert(base_align.check(@intFromPtr(buf.start()))); // Get all our main pointers @@ -351,13 +373,12 @@ fn HashMapUnmanaged( const metadata_ptr: [*]Metadata = @ptrCast(metadata_buf.start()); // Build our map - var map: Self = .{ .metadata = metadata_ptr }; + const map: Self = .{ .metadata = metadata_ptr }; const hdr = map.header(); hdr.capacity = layout.capacity; hdr.size = 0; if (@sizeOf([*]K) != 0) hdr.keys = metadata_buf.member(K, layout.keys_start); if (@sizeOf([*]V) != 0) hdr.values = metadata_buf.member(V, layout.vals_start); - map.initMetadatas(); return map; } diff --git a/src/terminal/ref_counted_set.zig b/src/terminal/ref_counted_set.zig index a8e64fcc7..669c2c575 100644 --- a/src/terminal/ref_counted_set.zig +++ b/src/terminal/ref_counted_set.zig @@ -212,6 +212,30 @@ pub fn RefCountedSet( @memset(table.ptr(base)[0..l.table_cap], 0); @memset(items.ptr(base)[0..l.cap], .{}); + return initFromParts(table, items, l, context); + } + + /// Like `init`, but for backing memory that the caller guarantees + /// is already zero-filled (e.g. fresh OS pages). This writes + /// nothing to the backing buffer, so the OS pages behind the table + /// and items stay untouched until the first `add`. + /// + /// Behavior is undefined if the backing memory is not zero. + pub fn initAssumeZeroed(base: OffsetBuf, l: Layout, context: Context) Self { + return initFromParts( + base.member(Id, l.table_start), + base.member(Item, l.items_start), + l, + context, + ); + } + + fn initFromParts( + table: Offset(Id), + items: Offset(Item), + l: Layout, + context: Context, + ) Self { return .{ .table = table, .items = items, @@ -726,7 +750,9 @@ pub fn RefCountedSet( var psl_stats: [32]Id = @splat(0); - for (items[0..self.layout.cap], 0..) |item, id| { + // Start at item 1 because item 0 is reserved and never + // assigned to. Its metadata doesn't matter. + for (items[1..self.next_id], 1..) |item, id| { if (item.meta.bucket < std.math.maxInt(Id)) { assert(table[item.meta.bucket] == id); psl_stats[item.meta.psl] += 1; @@ -740,6 +766,7 @@ pub fn RefCountedSet( psl_stats = @splat(0); for (table[0..self.layout.table_cap], 0..) |id, bucket| { + if (id == 0) continue; const item = items[id]; if (item.meta.bucket < std.math.maxInt(Id)) { assert(item.meta.bucket == bucket);