authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:34-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:22:41-04:00
loge7d452338c07fd1c8469ae78ed28451ee43089dc
treee7b6348c435bf54e927b993d25f5fb1840e16731
parente12274f2bcae4a9aebac788bf57988e4fdf7ba10

- MappedFile: add shrinkNode,

- MappedFile: avoid resizeNode unintentially growing nodes when a size <= the current size is requested

1 files changed, 66 insertions(+), 1 deletions(-)

src/link/MappedFile.zig+66-1
......@@ -375,6 +375,25 @@ pub const Node = extern struct {
375375 }
376376 }
377377
378 /// Shrink a node to `size`, exactly.
379 /// If the new size can't contain all the children, returns error.ShrinkImpossible.
380 /// If `shift_next` is set, then the following node is shifted backwards into
381 /// the free space as much as alignment allows.
382 pub fn shrink(
383 ni: Node.Index,
384 mf: *MappedFile,
385 gpa: std.mem.Allocator,
386 size: u64,
387 shift_next: bool,
388 ) !void {
389 try mf.shrinkNode(gpa, ni, size, shift_next);
390 var writers_it = mf.writers.first;
391 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
392 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
393 w.interface.buffer = w.ni.slice(mf);
394 }
395 }
396
378397 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
379398 w.* = .{
380399 .gpa = gpa,
......@@ -582,7 +601,9 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
582601 free_node.flags.resized = false;
583602 }
584603 _, const parent_size = opts.parent.location(mf).resolve(mf);
585 if (offset > parent_size) try opts.parent.resize(mf, gpa, offset);
604 const required_parent_size = offset + opts.add_node.size;
605 if (required_parent_size > parent_size)
606 try opts.parent.resize(mf, gpa, required_parent_size);
586607 try free_ni.resize(mf, gpa, opts.add_node.size);
587608 }
588609 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);
......@@ -670,11 +691,55 @@ pub fn addNodeAfter(
670691 });
671692}
672693
694fn shrinkNode(
695 mf: *MappedFile,
696 gpa: std.mem.Allocator,
697 ni: Node.Index,
698 size: u64,
699 shrink_next: bool,
700) !void {
701 const node = ni.get(mf);
702 const old_offset, _ = node.location().resolve(mf);
703
704 // This would require unmapping first
705 if (ni == Node.Index.root) return error.Unimplemented;
706
707 if (node.last != .none) {
708 const last = node.last.get(mf);
709 const last_offset, const last_size = last.location().resolve(mf);
710 if (last_offset + last_size > size) return error.ShrinkImpossible;
711 }
712
713 try mf.large.ensureUnusedCapacity(gpa, 4);
714 try mf.updates.ensureUnusedCapacity(gpa, 2);
715
716 ni.setLocationAssumeCapacity(mf, old_offset, size);
717 if (!shrink_next or node.next == .none) return;
718
719 const next = node.next.get(mf);
720 const old_next_offset, const next_size = next.location().resolve(mf);
721 const padding = old_next_offset - (old_offset + size);
722 const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding));
723
724 if (next.flags.has_content and new_next_offset < old_next_offset) {
725 const old_file_offset = node.next.fileLocation(mf, false).offset;
726 const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset;
727 @memmove(
728 mf.memory_map.memory[new_file_offset..][0..next_size],
729 mf.memory_map.memory[old_file_offset..][0..next_size],
730 );
731 }
732
733 node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size);
734}
735
673736fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) (Allocator.Error || Io.Cancelable || IoError)!void {
674737 const io = mf.io;
675738 const node = ni.get(mf);
676739 const old_offset, const old_size = node.location().resolve(mf);
677740 const new_size = node.flags.alignment.forward(@intCast(requested_size));
741 if (new_size <= old_size) return;
742
678743 // Resize the entire file
679744 if (ni == Node.Index.root) {
680745 try mf.ensureCapacityForSetLocation(gpa);