authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-12 13:27:57+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-12 13:27:57+02:00
log452ec646f90e43d516768d43cf8581d68a9ba776
treea91487513afa81dca000e17e5553ecf324e8eb33
parentcc5dbff35fc8024cff0a1559de12ffbf7b809107
parent30713514345f4416f7e68342be5555734e55410e

Merge pull request 'Elf2: fixes' (#36114) from jacobly/elf2-fixes into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36114 Reviewed-by: mlugg <mlugg@noreply.codeberg.org>

3 files changed, 168 insertions(+), 139 deletions(-)

src/link/Coff.zig+2-2
...@@ -3602,13 +3602,13 @@ fn objectSectionMapIndex(...@@ -3602,13 +3602,13 @@ fn objectSectionMapIndex(
3602 const parent_alignment = parent_ni.alignment(&coff.mf);3602 const parent_alignment = parent_ni.alignment(&coff.mf);
3603 if (alignment.compare(.gt, parent_alignment)) {3603 if (alignment.compare(.gt, parent_alignment)) {
3604 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });3604 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });
3605 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true });3605 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3606 }3606 }
36073607
3608 const old_alignment = sym.ni.alignment(&coff.mf);3608 const old_alignment = sym.ni.alignment(&coff.mf);
3609 if (alignment.compare(.gt, old_alignment)) {3609 if (alignment.compare(.gt, old_alignment)) {
3610 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });3610 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });
3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true });3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3612 }3612 }
36133613
3614 try coff.verifyParentSectionAttributes(3614 try coff.verifyParentSectionAttributes(
src/link/Elf2.zig+100-75
...@@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
4659 const new_alignment: std.mem.Alignment = .fromByteUnits(4659 const new_alignment: std.mem.Alignment = .fromByteUnits(
4660 std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)),4660 std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)),
4661 );4661 );
4662 try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{ .set_alignment = true });4662 try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{});
4663 }4663 }
4664 // ...and update the shdr as needed.4664 // ...and update the shdr as needed.
4665 switch (elf.shdrPtr(existing_shndx)) {4665 switch (elf.shdrPtr(existing_shndx)) {
...@@ -4796,7 +4796,7 @@ fn uavMapIndex(...@@ -4796,7 +4796,7 @@ fn uavMapIndex(
4796 if (!uav_gop.found_existing) {4796 if (!uav_gop.found_existing) {
4797 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs4797 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
4798 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{4798 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
4799 .moved = true, // see assert at end of `flushUav`4799 .moved = true, // see assert at end of `genUav`
4800 .alignment = resolved_align.toStdMem(),4800 .alignment = resolved_align.toStdMem(),
4801 });4801 });
4802 var name_buf: [32]u8 = undefined;4802 var name_buf: [32]u8 = undefined;
...@@ -4822,7 +4822,7 @@ fn uavMapIndex(...@@ -4822,7 +4822,7 @@ fn uavMapIndex(
4822 } else {4822 } else {
4823 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;4823 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
4824 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {4824 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
4825 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{ .set_alignment = true });4825 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{});
4826 }4826 }
4827 }4827 }
4828 return umi;4828 return umi;
...@@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars...@@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
5551 // We have a copy relocation for this global, but the amount of space we5551 // We have a copy relocation for this global, but the amount of space we
5552 // reserved for it could be too small or underaligned!5552 // reserved for it could be too small or underaligned!
5553 try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size);5553 try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size);
5554 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{ .set_alignment = true });5554 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{});
5555 const global_ptr = elf.globalByName(name).?;5555 const global_ptr = elf.globalByName(name).?;
5556 switch (elf.symPtr(global_ptr.symtab_index)) {5556 switch (elf.symPtr(global_ptr.symtab_index)) {
5557 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),5557 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),
...@@ -7005,22 +7005,27 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7005,22 +7005,27 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
7005 // called to apply the NAV's new relocations.7005 // called to apply the NAV's new relocations.
7006 try ni.moved(gpa, &elf.mf);7006 try ni.moved(gpa, &elf.mf);
70077007
7008 var nw: MappedFile.Node.Writer = undefined;7008 {
7009 ni.writer(&elf.mf, gpa, &nw);7009 var nw: MappedFile.Node.Writer = undefined;
7010 defer nw.deinit();7010 ni.writer(&elf.mf, gpa, &nw);
7011 codegen.generateSymbol(7011 defer nw.deinit();
7012 &elf.base,7012 codegen.generateSymbol(
7013 pt,7013 &elf.base,
7014 .fromInterned(nav.resolved.?.value),7014 pt,
7015 &nw.interface,7015 .fromInterned(nav.resolved.?.value),
7016 .{ .atom_index = Node.toAtom(ni) },7016 &nw.interface,
7017 ) catch |err| switch (err) {7017 .{ .atom_index = Node.toAtom(ni) },
7018 error.WriteFailed => return nw.err.?,7018 ) catch |err| switch (err) {
7019 else => |e| return e,7019 error.WriteFailed => return nw.err.?,
7020 };7020 else => |e| return e,
7021 switch (elf.symPtr(nmi.symbol(elf).index())) {7021 };
7022 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),7022 switch (elf.symPtr(nmi.symbol(elf).index())) {
7023 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
7024 }
7023 }7025 }
7026
7027 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
7028 try elf.genPending(pt);
7024}7029}
70257030
7026pub fn updateFunc(7031pub fn updateFunc(
...@@ -7056,29 +7061,34 @@ fn updateFuncInner(...@@ -7056,29 +7061,34 @@ fn updateFuncInner(
7056 // called to apply the NAV's new relocations.7061 // called to apply the NAV's new relocations.
7057 try ni.moved(gpa, &elf.mf);7062 try ni.moved(gpa, &elf.mf);
70587063
7059 var nw: MappedFile.Node.Writer = undefined;7064 {
7060 ni.writer(&elf.mf, gpa, &nw);7065 var nw: MappedFile.Node.Writer = undefined;
7061 defer nw.deinit();7066 ni.writer(&elf.mf, gpa, &nw);
7062 codegen.emitFunction(7067 defer nw.deinit();
7063 &elf.base,7068 codegen.emitFunction(
7064 pt,7069 &elf.base,
7065 func_index,7070 pt,
7066 Node.toAtom(ni),7071 func_index,
7067 mir,7072 Node.toAtom(ni),
7068 &nw.interface,7073 mir,
7069 .none,7074 &nw.interface,
7070 ) catch |err| switch (err) {7075 .none,
7071 error.WriteFailed => return nw.err.?,7076 ) catch |err| switch (err) {
7072 else => |e| return e,7077 error.WriteFailed => return nw.err.?,
7073 };7078 else => |e| return e,
7074 switch (elf.symPtr(nmi.symbol(elf).index())) {7079 };
7075 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),7080 switch (elf.symPtr(nmi.symbol(elf).index())) {
7081 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
7082 }
7076 }7083 }
7084
7085 // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs.
7086 try elf.genPending(pt);
7077}7087}
70787088
7079pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {7089pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void {
7080 const diags = &elf.base.comp.link_diags;7090 const diags = &elf.base.comp.link_diags;
7081 elf.flushLazy(pt, .{7091 elf.genLazy(pt, .{
7082 .kind = .const_data,7092 .kind = .const_data,
7083 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),7093 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
7084 }) catch |err| switch (err) {7094 }) catch |err| switch (err) {
...@@ -7183,40 +7193,13 @@ fn updateDynamicTextrel(elf: *Elf) Error!void {...@@ -7183,40 +7193,13 @@ fn updateDynamicTextrel(elf: *Elf) Error!void {
7183pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {7193pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7184 const comp = elf.base.comp;7194 const comp = elf.base.comp;
7185 const diags = &comp.link_diags;7195 const diags = &comp.link_diags;
7196
7197 assert(elf.pending_uavs.items.len == 0);
7198 for (&elf.lazy.values) |*lazy| {
7199 assert(lazy.pending_index == lazy.map.count());
7200 }
7201
7186 task: {7202 task: {
7187 while (elf.pending_uavs.pop()) |umi| {
7188 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = umi });
7189 defer sub_prog_node.end();
7190 elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) {
7191 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7192 else => |e| return e,
7193 };
7194 break :task;
7195 }
7196 var lazy_it = elf.lazy.iterator();
7197 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
7198 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
7199 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
7200 lazy.value.pending_index += 1;
7201 const kind = switch (lmr.kind) {
7202 .code => "code",
7203 .const_data => "data",
7204 };
7205 var name: [std.Progress.Node.max_name_len]u8 = undefined;
7206 const sub_prog_node = elf.synth_prog_node.start(
7207 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
7208 kind,
7209 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
7210 }) catch &name,
7211 0,
7212 );
7213 defer sub_prog_node.end();
7214 elf.flushLazy(pt, lmr) catch |err| switch (err) {
7215 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
7216 else => |e| return e,
7217 };
7218 break :task;
7219 };
7220 if (elf.input_section_pending_index < elf.input_sections.items.len) {7203 if (elf.input_section_pending_index < elf.input_sections.items.len) {
7221 const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index);7204 const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index);
7222 elf.input_section_pending_index += 1;7205 elf.input_section_pending_index += 1;
...@@ -7315,8 +7298,6 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {...@@ -7315,8 +7298,6 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
7315 } else elf.mf.update_prog_node.completeOne();7298 } else elf.mf.update_prog_node.completeOne();
7316 }7299 }
7317 }7300 }
7318 if (elf.pending_uavs.items.len > 0) return true;
7319 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
7320 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;7301 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
7321 if (elf.changed_symtab_index.count() > 0) return true;7302 if (elf.changed_symtab_index.count() > 0) return true;
7322 if (elf.mf.updates.items.len > 0) return true;7303 if (elf.mf.updates.items.len > 0) return true;
...@@ -7351,7 +7332,43 @@ fn idleProgNode(...@@ -7351,7 +7332,43 @@ fn idleProgNode(
7351 }, 0);7332 }, 0);
7352}7333}
73537334
7354fn flushUav(7335fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void {
7336 const zcu = elf.base.comp.zcu.?;
7337 pending: while (true) {
7338 if (elf.pending_uavs.pop()) |umi| {
7339 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
7340 const prog_name = std.mem.print(&prog_name_buf, "{f}", .{
7341 Value.fromInterned(umi.uavValue(elf)).fmtValue(pt),
7342 }) catch &prog_name_buf;
7343 const prog_node = elf.const_prog_node.start(prog_name, 0);
7344 defer prog_node.end();
7345 try elf.genUav(pt, umi);
7346 continue :pending;
7347 }
7348 var lazy_it = elf.lazy.iterator();
7349 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
7350 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
7351 lazy.value.pending_index += 1;
7352 const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty);
7353 var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined;
7354 const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) {
7355 .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
7356 .error_set => switch (lmr.kind) {
7357 .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf,
7358 .const_data => "@errorName",
7359 },
7360 else => unreachable,
7361 };
7362 const prog_node = elf.synth_prog_node.start(prog_name, 0);
7363 defer prog_node.end();
7364 try elf.genLazy(pt, lmr);
7365 continue :pending;
7366 };
7367 break;
7368 }
7369}
7370
7371fn genUav(
7355 elf: *Elf,7372 elf: *Elf,
7356 pt: Zcu.PerThread,7373 pt: Zcu.PerThread,
7357 umi: Node.UavMapIndex,7374 umi: Node.UavMapIndex,
...@@ -7380,11 +7397,11 @@ fn flushUav(...@@ -7380,11 +7397,11 @@ fn flushUav(
7380 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),7397 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
7381 }7398 }
7382 // The UAV should already be considered to have moved, because it is created as moved and7399 // The UAV should already be considered to have moved, because it is created as moved and
7383 // pending calls to `flushUav` always happen before pending calls to `flushMoved`.7400 // pending calls to `genUav` always happen before pending calls to `flushMoved`.
7384 assert(ni.hasMoved(&elf.mf));7401 assert(ni.hasMoved(&elf.mf));
7385}7402}
73867403
7387fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {7404fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
7388 const zcu = pt.zcu;7405 const zcu = pt.zcu;
7389 const gpa = zcu.gpa;7406 const gpa = zcu.gpa;
73907407
...@@ -7497,6 +7514,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -7497,6 +7514,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
7497fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {7514fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
7498 const trace = tracy.trace(@src());7515 const trace = tracy.trace(@src());
7499 defer trace.end();7516 defer trace.end();
7517
7518 elf.mf.nodes_lock.lock();
7519 defer elf.mf.nodes_lock.unlock();
7520
7500 switch (elf.getNode(ni)) {7521 switch (elf.getNode(ni)) {
7501 .file => unreachable,7522 .file => unreachable,
7502 .ehdr, .shdr => elf.flushFileOffset(ni),7523 .ehdr, .shdr => elf.flushFileOffset(ni),
...@@ -7662,6 +7683,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -7662,6 +7683,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
7662fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {7683fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
7663 const trace = tracy.trace(@src());7684 const trace = tracy.trace(@src());
7664 defer trace.end();7685 defer trace.end();
7686
7687 elf.mf.nodes_lock.lock();
7688 defer elf.mf.nodes_lock.unlock();
7689
7665 _, const size = ni.location(&elf.mf).resolve(&elf.mf);7690 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
7666 switch (elf.getNode(ni)) {7691 switch (elf.getNode(ni)) {
7667 .file => {},7692 .file => {},
src/link/MappedFile.zig+66-62
...@@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I...@@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I
95 .fallocate_punch_hole_unsupported = false,95 .fallocate_punch_hole_unsupported = false,
96 };96 };
97 try mf.nodes.ensureUnusedCapacity(gpa, 1);97 try mf.nodes.ensureUnusedCapacity(gpa, 1);
98 const root_ni = mf.addNode(gpa, .{ .add_node = .{98 const root_ni = try mf.addNode(gpa, .{ .add_node = .{
99 .size = size,99 .size = size,
100 .alignment = mf.flags.block_size,100 .alignment = mf.flags.block_size,
101 .fixed = true,101 .fixed = true,
102 } }) catch |err| switch (err) {102 } });
103 error.MappedFileIo => return mf.io_err.?,
104 else => |e| return e,
105 };
106 assert(root_ni == Node.Index.root);103 assert(root_ni == Node.Index.root);
107 try mf.ensureTotalCapacityInner(@intCast(size));104 try mf.ensureTotalCapacityInner(@intCast(size));
108 return mf;105 return mf;
...@@ -355,9 +352,7 @@ pub const Node = extern struct {...@@ -355,9 +352,7 @@ pub const Node = extern struct {
355352
356 pub const RealignNodeOptions = struct {353 pub const RealignNodeOptions = struct {
357 /// Shift the node backwards if possible354 /// Shift the node backwards if possible
358 try_backwards: bool = true,355 try_backwards: bool = false,
359 /// If `set, persists `new_alignment` as the node's alignment for future operations.
360 set_alignment: bool = true,
361 };356 };
362357
363 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.358 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.
...@@ -378,11 +373,7 @@ pub const Node = extern struct {...@@ -378,11 +373,7 @@ pub const Node = extern struct {
378 return error.MappedFileIo;373 return error.MappedFileIo;
379 },374 },
380 };375 };
381 var writers_it = mf.writers.first;376 mf.updateWriters();
382 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
383 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
384 w.interface.buffer = w.ni.slice(mf);
385 }
386 }377 }
387378
388 /// Shrink a node to `size`, exactly.379 /// Shrink a node to `size`, exactly.
...@@ -398,11 +389,7 @@ pub const Node = extern struct {...@@ -398,11 +389,7 @@ pub const Node = extern struct {
398 shift_next: bool,389 shift_next: bool,
399 ) Error!void {390 ) Error!void {
400 try mf.shrinkNode(gpa, ni, size, shift_next);391 try mf.shrinkNode(gpa, ni, size, shift_next);
401 var writers_it = mf.writers.first;392 mf.updateWriters();
402 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
403 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
404 w.interface.buffer = w.ni.slice(mf);
405 }
406 }393 }
407394
408 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {395 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
...@@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
562 next: Node.Index = .none,549 next: Node.Index = .none,
563 offset: u64 = 0,550 offset: u64 = 0,
564 add_node: AddNodeOptions,551 add_node: AddNodeOptions,
565}) Error!Node.Index {552}) (Allocator.Error || Io.Cancelable || IoError)!Node.Index {
566 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);553 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);
567 mf.nodes_lock.assertUnlocked();554 mf.nodes_lock.assertUnlocked();
568 const offset = opts.add_node.alignment.forward(@intCast(opts.offset));
569 if (opts.parent != .none) {
570 const new_end = offset + opts.add_node.size;
571 switch (opts.next) {
572 .none => {
573 _, const parent_size = opts.parent.location(mf).resolve(mf);
574 if (new_end > parent_size)
575 try opts.parent.resize(mf, gpa, new_end);
576 },
577 else => |next_ni| {
578 const next_offset, _ = next_ni.location(mf).resolve(mf);
579 if (new_end > next_offset)
580 try next_ni.realign(mf, gpa, opts.add_node.alignment, .{
581 .try_backwards = false,
582 .set_alignment = false,
583 });
584 },
585 }
586 }
587 const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: {555 const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: {
588 if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{556 if (std.math.cast(u32, opts.offset)) |small_offset| break :location .{ .small, .{
589 .small = .{ .offset = small_offset, .size = 0 },557 .small = .{ .offset = small_offset, .size = 0 },
590 } };558 } };
591 try mf.large.ensureUnusedCapacity(gpa, 2);559 try mf.large.ensureUnusedCapacity(gpa, 2);
592 defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 });560 defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 });
593 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };561 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };
594 };562 };
595 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {563 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {
...@@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
616 .last = .none,584 .last = .none,
617 .flags = .{585 .flags = .{
618 .location_tag = location_tag,586 .location_tag = location_tag,
619 .alignment = opts.add_node.alignment,587 .alignment = .@"1",
620 .fixed = opts.add_node.fixed,588 .fixed = opts.add_node.fixed,
621 .moved = true,589 .moved = true,
622 .resized = true,590 .resized = true,
...@@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
627 };595 };
628596
629 {597 {
630 try free_ni.resize(mf, gpa, opts.add_node.size);598 try mf.realignNode(gpa, free_ni, opts.add_node.alignment, .{});
599 try mf.resizeNode(gpa, free_ni, opts.add_node.size);
631 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);600 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);
632 free_node.flags.moved = false;601 free_node.flags.moved = false;
633 free_node.flags.resized = false;602 free_node.flags.resized = false;
634 }603 }
635 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);604 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);
636 if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf);605 if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf);
606 mf.updateWriters();
637 return free_ni;607 return free_ni;
638}608}
639609
...@@ -658,7 +628,15 @@ pub fn addOnlyChildNode(...@@ -658,7 +628,15 @@ pub fn addOnlyChildNode(
658 return mf.addNode(gpa, .{628 return mf.addNode(gpa, .{
659 .parent = parent_ni,629 .parent = parent_ni,
660 .add_node = opts,630 .add_node = opts,
661 });631 }) catch |err| switch (err) {
632 error.OutOfMemory,
633 error.Canceled,
634 => |e| return e,
635 else => |e| {
636 mf.io_err = e;
637 return error.MappedFileIo;
638 },
639 };
662}640}
663641
664pub fn addFirstChildNode(642pub fn addFirstChildNode(
...@@ -673,7 +651,15 @@ pub fn addFirstChildNode(...@@ -673,7 +651,15 @@ pub fn addFirstChildNode(
673 .parent = parent_ni,651 .parent = parent_ni,
674 .next = parent.first,652 .next = parent.first,
675 .add_node = opts,653 .add_node = opts,
676 });654 }) catch |err| switch (err) {
655 error.OutOfMemory,
656 error.Canceled,
657 => |e| return e,
658 else => |e| {
659 mf.io_err = e;
660 return error.MappedFileIo;
661 },
662 };
677}663}
678664
679pub fn addLastChildNode(665pub fn addLastChildNode(
...@@ -695,7 +681,15 @@ pub fn addLastChildNode(...@@ -695,7 +681,15 @@ pub fn addLastChildNode(
695 },681 },
696 },682 },
697 .add_node = opts,683 .add_node = opts,
698 });684 }) catch |err| switch (err) {
685 error.OutOfMemory,
686 error.Canceled,
687 => |e| return e,
688 else => |e| {
689 mf.io_err = e;
690 return error.MappedFileIo;
691 },
692 };
699}693}
700694
701pub fn addNodeAfter(695pub fn addNodeAfter(
...@@ -714,7 +708,15 @@ pub fn addNodeAfter(...@@ -714,7 +708,15 @@ pub fn addNodeAfter(
714 .next = prev.next,708 .next = prev.next,
715 .offset = prev_offset + prev_size,709 .offset = prev_offset + prev_size,
716 .add_node = opts,710 .add_node = opts,
717 });711 }) catch |err| switch (err) {
712 error.OutOfMemory,
713 error.Canceled,
714 => |e| return e,
715 else => |e| {
716 mf.io_err = e;
717 return error.MappedFileIo;
718 },
719 };
718}720}
719721
720fn shrinkNode(722fn shrinkNode(
...@@ -1043,26 +1045,20 @@ fn realignNode(...@@ -1043,26 +1045,20 @@ fn realignNode(
1043 new_alignment: std.mem.Alignment,1045 new_alignment: std.mem.Alignment,
1044 opts: Node.Index.RealignNodeOptions,1046 opts: Node.Index.RealignNodeOptions,
1045) (Allocator.Error || Io.Cancelable || IoError)!void {1047) (Allocator.Error || Io.Cancelable || IoError)!void {
1046 assert(ni != Node.Index.root); // currently unsupported
1047 mf.nodes_lock.assertUnlocked();1048 mf.nodes_lock.assertUnlocked();
10481049
1049 const node = ni.get(mf);1050 const node = ni.get(mf);
1050 const old_offset, const size = node.location().resolve(mf);1051 {
10511052 const prev_alignment = node.flags.alignment;
1052 assert(new_alignment.compare(.gt, node.flags.alignment));1053 node.flags.alignment = new_alignment;
10531054 if (new_alignment.compare(.lte, prev_alignment)) return;
1054 const prev_alignment = node.flags.alignment;
1055 node.flags.alignment = new_alignment;
1056 defer {
1057 // alignment needs to be temporarily set for the resizes below
1058 if (!opts.set_alignment) node.flags.alignment = prev_alignment;
1059 }1055 }
10601056
1061 const new_size = node.flags.alignment.forward(@intCast(size));1057 const old_offset, const size = node.location().resolve(mf);
1062 if (new_alignment.check(@intCast(old_offset))) {1058 if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size);
1063 if (new_size > size) try mf.resizeNode(gpa, ni, new_size);1059
1064 return;1060 const new_size = new_alignment.forward(@intCast(size));
1065 }1061 if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size);
10661062
1067 _, const parent_size = node.parent.location(mf).resolve(mf);1063 _, const parent_size = node.parent.location(mf).resolve(mf);
1068 const trailing_end = trailing_end: switch (node.next) {1064 const trailing_end = trailing_end: switch (node.next) {
...@@ -1122,7 +1118,7 @@ fn realignNode(...@@ -1122,7 +1118,7 @@ fn realignNode(
11221118
1123 ni.setLocationAssumeCapacity(mf, forward_offset, new_size);1119 ni.setLocationAssumeCapacity(mf, forward_offset, new_size);
1124 } else {1120 } else {
1125 const temp_size = node.flags.alignment.forward(@intCast(new_size + 1));1121 const temp_size = new_alignment.forward(@intCast(new_size + 1));
1126 try mf.resizeNode(gpa, ni, temp_size);1122 try mf.resizeNode(gpa, ni, temp_size);
1127 const new_offset, _ = ni.location(mf).resolve(mf);1123 const new_offset, _ = ni.location(mf).resolve(mf);
11281124
...@@ -1148,6 +1144,14 @@ fn realignNode(...@@ -1148,6 +1144,14 @@ fn realignNode(
1148 }1144 }
1149}1145}
11501146
1147fn updateWriters(mf: *MappedFile) void {
1148 var writers_it = mf.writers.first;
1149 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
1150 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
1151 w.interface.buffer = w.ni.slice(mf);
1152 }
1153}
1154
1151fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void {1155fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void {
1152 // make a copy of this node at the new location1156 // make a copy of this node at the new location
1153 try mf.copyRange(old_file_offset, new_file_offset, size);1157 try mf.copyRange(old_file_offset, new_file_offset, size);