authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-17 10:59:01+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-24 20:42:40+01:00
logd9078dae3b6266767d66d5f2100f321b200cbd6b
tree15ff1606b2afe1c2f55ef99eca8539579bc6b9d5
parentff85396f7a85750cb703460b5b57b9860088c5ef
signaturelock-open Commit is signed but in an unrecognized format.

link.MappedFile: new `Alignment` type and non-optional `Node.Index`

There are two refactors here (apologies for putting them in the same commit!). First, I have replaced uses of `std.mem.Alignment` with a new type based on a fixed `u64` address space. While it is technically okay to use `std.mem.Alignment` in `MappedFile` (because memory-mapping limits the file size to the host's address space size), in practice it is somewhat inconvenient. I wanted to use `InternPool.Alignment`, but that type has an annoying problem of its own: for legacy reasons, it is optional (that is, it has a `.none` field), which makes for very ambiguous APIs unless you meticulously assert and comment all uses of the type. I therefore chose to add yet another alignment type to the Zig repository---sorrry! My hope going forward is that at some point, we can rename the existing `InternPool.Alignment` type to `InternPool.Alignment.Optional`, rename this new type to `InternPool.Alignment`, and slowly transition the entire compiler towards correctly distinguishing between "optional" and "non-optional" alignments. Second, I have made `MappedFile.Node.Index` non-optional (i.e. removed its `.none` tag). Notably, the old definition of this type had `.root == .none`, which was pretty awkward (you couldn't represent a node index which could be the root node *and* could be empty) and unsafe (we couldn't get safety checks for trying to use a "null" node index, instead we would just operate on the root node). To fix this, it has been split into `Node.Index` and `Node.Index.Optional`---I'm sure you all know the drill by now, it's just like all of the index types in `InternPool`. Some of the code I've written in this migration is definitely quite ugly, because I did a fairly mechanical replacement (e.g. for the most part I didn't introduce local constants). The code can be neatened up to avoid the mess of `unwrap` calls all over the place! Also, in `link.Coff`, it's possible that I made some fields optional when they shouldn't have been, which would definitely contribute to the `.unwrap().?` mess I wrote in that linker...

4 files changed, 622 insertions(+), 529 deletions(-)

src/InternPool.zig-11
......@@ -5987,17 +5987,6 @@ pub const Alignment = enum(u6) {
59875987 return n + 1;
59885988 }
59895989
5990 pub fn toStdMem(a: Alignment) std.mem.Alignment {
5991 assert(a != .none);
5992 return @fromBackingInt(@intCast(@backingInt(a)));
5993 }
5994
5995 pub fn fromStdMem(a: std.mem.Alignment) Alignment {
5996 const r: Alignment = @fromBackingInt(@intCast(@backingInt(a)));
5997 assert(r != .none);
5998 return r;
5999 }
6000
60015990 pub fn toLlvm(a: Alignment) std.zig.llvm.Builder.Alignment {
60025991 return @fromBackingInt(@intCast(@backingInt(a)));
60035992 }
src/link/Coff.zig+142-144
......@@ -21,6 +21,7 @@ const Zcu = @import("../Zcu.zig");
2121const ModuleDefinition = @import("../libs/mingw/def.zig").ModuleDefinition;
2222const implib = @import("../libs/mingw/implib.zig");
2323const Path = std.Build.Cache.Path;
24const Alignment = MappedFile.Alignment;
2425
2526base: link.File,
2627options: link.File.OpenOptions,
......@@ -602,7 +603,7 @@ pub const Member = struct {
602603};
603604
604605pub const LongNamesTable = struct {
605 ni: MappedFile.Node.Index = .none,
606 ni: MappedFile.Node.Index.Optional = .none,
606607 entries: std.array_hash_map.Auto(void, Entry),
607608
608609 pub const Entry = struct {
......@@ -832,7 +833,7 @@ pub const String = enum(u32) {
832833
833834pub const Section = struct {
834835 si: Symbol.Index,
835 relocation_table_ni: MappedFile.Node.Index,
836 relocation_table_ni: MappedFile.Node.Index.Optional,
836837
837838 pub const RelocationIndex = enum(u16) {
838839 none,
......@@ -855,7 +856,7 @@ pub const Section = struct {
855856 sn: Symbol.SectionNumber,
856857 ) ?*align(2) std.coff.Relocation {
857858 if (sri == .none) return null;
858 const table_slice = sn.section(coff).relocation_table_ni.slice(&coff.mf);
859 const table_slice = sn.section(coff).relocation_table_ni.unwrap().?.slice(&coff.mf);
859860 return @ptrCast(@alignCast(&table_slice[@as(u32, sri.unwrap().?) * std.coff.Relocation.sizeOf()]));
860861 }
861862 };
......@@ -891,7 +892,7 @@ const SpecialSymbol = enum {
891892};
892893
893894pub const Symbol = struct {
894 ni: MappedFile.Node.Index,
895 ni: MappedFile.Node.Index.Optional,
895896 rva: u32,
896897 value: std.meta.BareUnion(Symbol.Value),
897898 extra: std.meta.BareUnion(Symbol.Extra),
......@@ -986,7 +987,7 @@ pub const Symbol = struct {
986987 pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 {
987988 return switch (sym.flags.value_tag) {
988989 .node_offset => offset: {
989 assert(switch (coff.getNode(sym.ni)) {
990 assert(switch (coff.getNode(sym.ni.unwrap().?)) {
990991 // Separate nodes are not created for these entries per-symbol
991992 .input_section, .import_address_table => true,
992993 else => false,
......@@ -1052,9 +1053,7 @@ pub const Symbol = struct {
10521053 }
10531054
10541055 pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index {
1055 const ni = si.get(coff).ni;
1056 assert(ni != .none);
1057 return ni;
1056 return si.get(coff).ni.unwrap().?;
10581057 }
10591058
10601059 pub fn sti(si: Symbol.Index, coff: *Coff) SymbolTable.Index {
......@@ -1075,7 +1074,7 @@ pub const Symbol = struct {
10751074
10761075 pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void {
10771076 const sym = si.get(coff);
1078 sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff);
1077 sym.rva = coff.computeNodeRva(sym.ni.unwrap().?) + sym.nodeOffset(coff);
10791078 try si.applyLocationRelocs(coff);
10801079 try si.applyTargetRelocs(coff, .none);
10811080
......@@ -1199,12 +1198,11 @@ pub const Reloc = extern struct {
11991198
12001199 pub fn apply(reloc: *Reloc, coff: *Coff) !void {
12011200 const loc_sym = reloc.loc.get(coff);
1202 switch (loc_sym.ni) {
1203 .none => return,
1204 else => |ni| if (ni.hasMoved(&coff.mf)) return,
1205 }
12061201
1207 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];
1202 const loc_sym_ni = loc_sym.ni.unwrap() orelse return;
1203 if (loc_sym_ni.hasMoved(&coff.mf)) return;
1204
1205 const loc_slice = loc_sym_ni.slice(&coff.mf)[@intCast(reloc.offset)..];
12081206 const target_endian = coff.targetEndian();
12091207 const target_machine = coff.targetLoad(&coff.headerPtr().machine);
12101208
......@@ -1331,9 +1329,12 @@ pub const Reloc = extern struct {
13311329 }
13321330
13331331 const target_sym = reloc.target.get(coff);
1334 const is_abs = switch (target_sym.ni) {
1335 .none => if (target_sym.section_number == .ABSOLUTE) true else return,
1336 else => |ni| if (ni.hasMoved(&coff.mf)) return else false,
1332 const is_abs = if (target_sym.ni.unwrap()) |ni| is_abs: {
1333 if (ni.hasMoved(&coff.mf)) return;
1334 break :is_abs false;
1335 } else is_abs: {
1336 if (target_sym.section_number != .ABSOLUTE) return;
1337 break :is_abs true;
13371338 };
13381339
13391340 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
......@@ -1573,7 +1574,7 @@ fn create(
15731574 33...64 => .@"PE32+",
15741575 else => return error.UnsupportedCOFFArchitecture,
15751576 };
1576 const section_align: std.mem.Alignment = switch (machine) {
1577 const section_align: Alignment = switch (machine) {
15771578 .AMD64, .I386 => @fromBackingInt(@intCast(12)),
15781579 .SH3, .SH3DSP, .SH4, .SH5 => @fromBackingInt(@intCast(12)),
15791580 .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @fromBackingInt(@intCast(12)),
......@@ -1617,22 +1618,22 @@ fn create(
16171618 .entries = .empty,
16181619 },
16191620 .import_table = .{
1620 .ni = .none,
1621 .ni = undefined,
16211622 .entries = .empty,
16221623 .iat_symbol_indices = .empty,
16231624 },
16241625 .export_table = .{
1625 .ni = .none,
1626 .export_directory_table_ni = .none,
1626 .ni = undefined,
1627 .export_directory_table_ni = undefined,
16271628 .export_address_table_si = .null,
1628 .name_pointer_table_ni = .none,
1629 .ordinal_table_ni = .none,
1630 .name_table_ni = .none,
1629 .name_pointer_table_ni = undefined,
1630 .ordinal_table_ni = undefined,
1631 .name_table_ni = undefined,
16311632 .entries = .empty,
16321633 },
16331634 .symbol_table = .{
1634 .ni = .none,
1635 .strings_ni = .none,
1635 .ni = undefined,
1636 .strings_ni = undefined,
16361637 .strings = .empty,
16371638 .symbols = .empty,
16381639 .pending_symbol_index = 0,
......@@ -1794,13 +1795,13 @@ fn initHeaders(
17941795 minor_subsystem_version: u16,
17951796 magic: std.coff.OptionalHeader.Magic,
17961797 subsystem: std.coff.Subsystem,
1797 section_align: std.mem.Alignment,
1798 section_align: Alignment,
17981799 file_name: []const u8,
17991800) !void {
18001801 const comp = coff.base.comp;
18011802 const gpa = comp.gpa;
18021803 const target_endian = coff.targetEndian();
1803 const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment);
1804 const file_align: Alignment = comptime .fromByteUnits(default_file_alignment);
18041805 const is_image = coff.isImage();
18051806 const is_archive = coff.isArchive();
18061807 const target = &comp.root_mod.resolved_target.result;
......@@ -2191,7 +2192,7 @@ fn initHeaders(
21912192 coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity();
21922193
21932194 const export_address_table_sym = coff.export_table.export_address_table_si.get(coff);
2194 export_address_table_sym.ni = export_address_table_ni;
2195 export_address_table_sym.ni = .wrap(export_address_table_ni);
21952196 assert(export_address_table_sym.loc_relocs == .none);
21962197 export_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
21972198 export_address_table_sym.section_number =
......@@ -2260,7 +2261,7 @@ pub fn initBuiltins(coff: *Coff) !void {
22602261 if (coff.isImage()) {
22612262 const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data });
22622263 const sym = si.get(coff);
2263 sym.ni = Node.known.header;
2264 sym.ni = .wrap(Node.known.header);
22642265 }
22652266
22662267 defer coff.flushSectionMerges() catch unreachable;
......@@ -2302,14 +2303,14 @@ pub fn initBuiltins(coff: *Coff) !void {
23022303 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });
23032304 const list_len_sym = list_len_si.get(coff);
23042305 list_len_sym.setExtra(.{ .size = addr_info.size });
2305 list_len_sym.ni = try coff.mf.addFirstChildNode(gpa, start_sym.ni, .{
2306 list_len_sym.ni = .wrap(try coff.mf.addFirstChildNode(gpa, start_sym.ni.unwrap().?, .{
23062307 .size = addr_info.size,
23072308 .fixed = true,
2308 });
2309 }));
23092310 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });
23102311 list_len_sym.section_number = start_sym.section_number;
23112312
2312 const start_slice = list_len_sym.ni.slice(&coff.mf);
2313 const start_slice = list_len_sym.ni.unwrap().?.slice(&coff.mf);
23132314 switch (addr_info.magic) {
23142315 _ => unreachable,
23152316 inline .PE32, .@"PE32+" => |t| {
......@@ -2324,14 +2325,14 @@ pub fn initBuiltins(coff: *Coff) !void {
23242325 const list_end_si = coff.addSymbolAssumeCapacity();
23252326 const list_end_sym = list_end_si.get(coff);
23262327 list_end_sym.setExtra(.{ .size = addr_info.size });
2327 list_end_sym.ni = try coff.mf.addFirstChildNode(gpa, end_sym.ni, .{
2328 list_end_sym.ni = .wrap(try coff.mf.addFirstChildNode(gpa, end_sym.ni.unwrap().?, .{
23282329 .size = addr_info.size,
23292330 .fixed = true,
2330 });
2331 }));
23312332 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });
23322333 list_end_sym.section_number = start_sym.section_number;
23332334
2334 @memset(list_end_sym.ni.slice(&coff.mf), 0);
2335 @memset(list_end_sym.ni.unwrap().?.slice(&coff.mf), 0);
23352336
23362337 try list_len_si.flushMoved(coff);
23372338 try list_end_si.flushMoved(coff);
......@@ -2387,7 +2388,7 @@ fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
23872388}
23882389fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
23892390 const parent_rva = parent_rva: {
2390 const parent_si = switch (coff.getNode(ni.parent(&coff.mf))) {
2391 const parent_si = switch (coff.getNode(ni.parent(&coff.mf).unwrap().?)) {
23912392 .file,
23922393 .header,
23932394 .signature,
......@@ -2452,11 +2453,11 @@ fn computeSymbolSectionOffset(
24522453 relative_to: enum { image, pseudo },
24532454) u32 {
24542455 var section_offset: u32 = sym.nodeOffset(coff);
2455 var parent_ni = sym.ni;
2456 var parent_ni = sym.ni.unwrap().?;
24562457 while (true) {
24572458 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);
24582459 section_offset += @intCast(offset);
2459 parent_ni = parent_ni.parent(&coff.mf);
2460 parent_ni = parent_ni.parent(&coff.mf).unwrap().?;
24602461 switch (coff.getNode(parent_ni)) {
24612462 else => unreachable,
24622463 .image_section => break,
......@@ -2475,7 +2476,7 @@ pub inline fn targetEndian(_: *const Coff) std.lang.Endian {
24752476
24762477fn targetAddrInfo(coff: *Coff) struct {
24772478 size: u8,
2478 alignment: std.mem.Alignment,
2479 alignment: Alignment,
24792480 magic: std.coff.OptionalHeader.Magic,
24802481} {
24812482 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
......@@ -2875,9 +2876,9 @@ fn navSection(
28752876 switch (nav_resolved.@"linksection") {
28762877 .none => coff.mf.flags.block_size,
28772878 else => switch (nav_resolved.@"align") {
2878 .none => Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu),
2879 else => |alignment| alignment,
2880 }.toStdMem(),
2879 .none => .fromIp(Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu)),
2880 else => |a| .fromIp(a),
2881 },
28812882 },
28822883 attributes,
28832884 )).symbol(coff);
......@@ -3151,7 +3152,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
31513152 else
31523153 .NULL,
31533154 };
3154 } else blk: switch (coff.getNode(sym.ni)) {
3155 } else blk: switch (coff.getNode(sym.ni.unwrap().?)) {
31553156 .image_section => .{
31563157 try coff.getOrPutSymbolName(&sym.section_number.header(coff).name, null),
31573158 1,
......@@ -3192,7 +3193,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
31923193 };
31933194 },
31943195 else => {
3195 log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni)), si });
3196 log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni.unwrap().?)), si });
31963197 unreachable;
31973198 },
31983199 };
......@@ -3255,13 +3256,13 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
32553256 std.mem.byteSwapAllFieldsAligned(std.coff.WeakExternalDefinition, .@"2", aux_ptr);
32563257
32573258 break :aux_init;
3258 } else switch (coff.getNode(sym.ni)) {
3259 } else switch (coff.getNode(sym.ni.unwrap().?)) {
32593260 .image_section => |sec_si| {
32603261 assert(si == sec_si);
32613262 const header = sym.section_number.header(coff);
32623263 const aux_ptr = coff.symbolTableSectionAuxEntryPtr(sti.*).?;
32633264 aux_ptr.* = .{
3264 .length = @intCast(sym.ni.location(&coff.mf).resolve(&coff.mf)[1]),
3265 .length = @intCast(sym.ni.unwrap().?.location(&coff.mf).resolve(&coff.mf)[1]),
32653266 .number_of_relocations = header.number_of_relocations,
32663267 .number_of_linenumbers = header.number_of_linenumbers,
32673268 .checksum = 0,
......@@ -3288,7 +3289,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
32883289 .ABSOLUTE,
32893290 .DEBUG,
32903291 => unreachable,
3291 else => switch (coff.getNode(sym.ni)) {
3292 else => switch (coff.getNode(sym.ni.unwrap().?)) {
32923293 .image_section => 0,
32933294 else => coff.computeSymbolSectionOffset(sym, .image),
32943295 },
......@@ -3397,7 +3398,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
33973398
33983399 {
33993400 const sym = si.get(coff);
3400 sym.ni = ni;
3401 sym.ni = .wrap(ni);
34013402 sym.rva = rva;
34023403 sym.section_number = @fromBackingInt(@intCast(section_table_len));
34033404 }
......@@ -3481,7 +3482,7 @@ const ObjectSectionAttributes = packed struct {
34813482fn pseudoSectionMapIndex(
34823483 coff: *Coff,
34833484 name: String,
3484 alignment: std.mem.Alignment,
3485 alignment: Alignment,
34853486 attributes: ObjectSectionAttributes,
34863487) !Node.PseudoSectionMapIndex {
34873488 const gpa = coff.base.comp.gpa;
......@@ -3510,7 +3511,7 @@ fn pseudoSectionMapIndex(
35103511 const si = coff.addSymbolAssumeCapacity();
35113512 pseudo_section_gop.value_ptr.* = si;
35123513 const sym = si.get(coff);
3513 sym.ni = ni;
3514 sym.ni = .wrap(ni);
35143515 sym.rva = coff.computeNodeRva(ni);
35153516 sym.section_number = parent.get(coff).section_number;
35163517 assert(sym.loc_relocs == .none);
......@@ -3543,7 +3544,7 @@ fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 {
35433544fn objectSectionMapIndex(
35443545 coff: *Coff,
35453546 name: String,
3546 alignment: std.mem.Alignment,
3547 alignment: Alignment,
35473548 attributes: ObjectSectionAttributes,
35483549) !Node.ObjectSectionMapIndex {
35493550 const gpa = coff.base.comp.gpa;
......@@ -3565,7 +3566,7 @@ fn objectSectionMapIndex(
35653566 try coff.nodes.ensureUnusedCapacity(gpa, 1);
35663567 try coff.symbols.ensureUnusedCapacity(gpa, 1);
35673568 const parent_ni = parent.node(coff);
3568 var prev_ni: MappedFile.Node.Index = .none;
3569 var prev_oni: MappedFile.Node.Index.Optional = .none;
35693570 var next_it = parent_ni.children(&coff.mf);
35703571 while (next_it.next()) |next_ni| switch (std.mem.order(
35713572 u8,
......@@ -3574,22 +3575,19 @@ fn objectSectionMapIndex(
35743575 )) {
35753576 .lt => break,
35763577 .eq => unreachable,
3577 .gt => prev_ni = next_ni,
3578 };
3579 const ni = switch (prev_ni) {
3580 .none => try coff.mf.addFirstChildNode(gpa, parent_ni, .{
3581 .alignment = alignment,
3582 .fixed = true,
3583 }),
3584 else => try coff.mf.addNodeAfter(gpa, prev_ni, .{
3585 .alignment = alignment,
3586 .fixed = true,
3587 }),
3578 .gt => prev_oni = .wrap(next_ni),
35883579 };
3580 const ni = if (prev_oni.unwrap()) |prev_ni| try coff.mf.addNodeAfter(gpa, prev_ni, .{
3581 .alignment = alignment,
3582 .fixed = true,
3583 }) else try coff.mf.addFirstChildNode(gpa, parent_ni, .{
3584 .alignment = alignment,
3585 .fixed = true,
3586 });
35893587 const si = coff.addSymbolAssumeCapacity();
35903588 object_section_gop.value_ptr.* = si;
35913589 const sym = si.get(coff);
3592 sym.ni = ni;
3590 sym.ni = .wrap(ni);
35933591 sym.rva = coff.computeNodeRva(ni);
35943592 sym.section_number = parent.get(coff).section_number;
35953593 assert(sym.loc_relocs == .none);
......@@ -3598,17 +3596,17 @@ fn objectSectionMapIndex(
35983596 break :sym sym;
35993597 } else object_section_gop.value_ptr.get(coff);
36003598
3601 const parent_ni = sym.ni.parent(&coff.mf);
3599 const parent_ni = sym.ni.unwrap().?.parent(&coff.mf).unwrap().?;
36023600 const parent_alignment = parent_ni.alignment(&coff.mf);
36033601 if (alignment.compare(.gt, parent_alignment)) {
36043602 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });
36053603 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
36063604 }
36073605
3608 const old_alignment = sym.ni.alignment(&coff.mf);
3606 const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf);
36093607 if (alignment.compare(.gt, old_alignment)) {
36103608 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });
3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3609 try sym.ni.unwrap().?.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
36123610 }
36133611
36143612 try coff.verifyParentSectionAttributes(
......@@ -3764,8 +3762,10 @@ fn addRelocAssumeCapacity(
37643762 if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr|
37653763 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
37663764
3767 if (section.relocation_table_ni == .none) {
3768 section.relocation_table_ni = try coff.mf.addLastChildNode(
3765 if (section.relocation_table_ni.unwrap()) |relocation_table_ni| {
3766 try relocation_table_ni.resize(&coff.mf, gpa, new_size);
3767 } else {
3768 section.relocation_table_ni = .wrap(try coff.mf.addLastChildNode(
37693769 gpa,
37703770 coff.sectionParent(),
37713771 .{
......@@ -3774,10 +3774,8 @@ fn addRelocAssumeCapacity(
37743774 .moved = true,
37753775 .resized = true,
37763776 },
3777 );
3777 ));
37783778 coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });
3779 } else {
3780 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
37813779 }
37823780
37833781 // TODO: These need to allocate from a free list, once deleting relocs from the table is supported
......@@ -4581,7 +4579,7 @@ fn loadObject(
45814579 },
45824580 .SAME_SIZE => {
45834581 // TODO: Verify that this node isn't resized after creation
4584 _, const size = si.get(coff).ni.location(&coff.mf).resolve(&coff.mf);
4582 _, const size = si.get(coff).ni.unwrap().?.location(&coff.mf).resolve(&coff.mf);
45854583 if (size == section.header.size_of_raw_data) {
45864584 symbol.si = si;
45874585 break :comdat .skip;
......@@ -4598,9 +4596,9 @@ fn loadObject(
45984596 },
45994597 .EXACT_MATCH => {
46004598 const sym = si.get(coff);
4601 const existing_crc = switch (coff.getNode(sym.ni)) {
4599 const existing_crc = switch (coff.getNode(sym.ni.unwrap().?)) {
46024600 .input_section => |isi| isi.inputSection(coff).crc,
4603 else => Crc32.hash(sym.ni.sliceConst(&coff.mf)),
4601 else => Crc32.hash(sym.ni.unwrap().?.sliceConst(&coff.mf)),
46044602 };
46054603
46064604 if (existing_crc == section.comdat_crc) {
......@@ -4666,7 +4664,7 @@ fn loadObject(
46664664
46674665 section.parent_si = (try coff.objectSectionMapIndex(
46684666 section.name,
4669 section.header.flags.ALIGN.alignment() orelse .@"1",
4667 .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1),
46704668 .fromFlags(section.header.flags),
46714669 )).symbol(coff);
46724670 }
......@@ -4681,7 +4679,7 @@ fn loadObject(
46814679
46824680 const ni = try coff.mf.addLastChildNode(gpa, section.parent_si.node(coff), .{
46834681 .size = section.header.size_of_raw_data,
4684 .alignment = section.header.flags.ALIGN.alignment() orelse .@"1",
4682 .alignment = .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1),
46854683 .moved = true,
46864684 });
46874685 coff.nodes.appendAssumeCapacity(.{ .input_section = @fromBackingInt(@intCast(coff.input_sections.items.len)) });
......@@ -4691,7 +4689,7 @@ fn loadObject(
46914689 pending_symbols.values()[psi].si = section.si;
46924690
46934691 const sym = section.si.get(coff);
4694 sym.ni = ni;
4692 sym.ni = .wrap(ni);
46954693 sym.section_number = section.parent_si.get(coff).section_number;
46964694
46974695 coff.input_sections.addOneAssumeCapacity().* = .{
......@@ -4852,7 +4850,7 @@ fn loadObject(
48524850 }
48534851
48544852 if (section.comdat_psi.unwrap() == @as(u32, @intCast(i)))
4855 coff.getNode(section.si.get(coff).ni).input_section.inputSection(coff).comdat_si = symbol.si;
4853 coff.getNode(section.si.get(coff).ni.unwrap().?).input_section.inputSection(coff).comdat_si = symbol.si;
48564854 }
48574855
48584856 if (symbol.weak_external_psi.unwrap()) |weak_external_i| {
......@@ -4967,14 +4965,14 @@ fn loadObject(
49674965 const section = &sections[symbol.section_number.toIndex()];
49684966 include_section = section.comdat_result == .include;
49694967 if (include_section) {
4970 const isi = coff.getNode(section.si.get(coff).ni).input_section;
4968 const isi = coff.getNode(section.si.get(coff).ni.unwrap().?).input_section;
49714969 isi.inputSection(coff).first_li = @fromBackingInt(@intCast(coff.input_symbols.items.len));
49724970 }
49734971 }
49744972 }
49754973
49764974 if (include_section) {
4977 assert(coff.getNode(symbol.si.get(coff).ni) == .input_section);
4975 assert(coff.getNode(symbol.si.get(coff).ni.unwrap().?) == .input_section);
49784976 symbol.si.get(coff).setExtra(.{ .isli = @fromBackingInt(@intCast(coff.input_symbols.items.len)) });
49794977 coff.input_symbols.addOneAssumeCapacity().* = .{
49804978 .si = symbol.si,
......@@ -5002,7 +5000,7 @@ fn failMultipleDefinitions(
50025000 var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes);
50035001 try err.addMsg("multiple definitions of '{s}'", .{name.toSlice(coff)});
50045002
5005 switch (coff.getNode(existing_si.get(coff).ni)) {
5003 switch (coff.getNode(existing_si.get(coff).ni.unwrap().?)) {
50065004 .input_section => |isi| {
50075005 const other_ioi = isi.input(coff);
50085006 err.addNote("first seen in input '{f}{f}'", .{
......@@ -5474,12 +5472,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54745472 try coff.nodes.ensureUnusedCapacity(gpa, 1);
54755473 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
54765474 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
5477 .alignment = zcu.navAlignment(nav_index).toStdMem(),
5475 .alignment = .fromIp(zcu.navAlignment(nav_index)),
54785476 .moved = true,
54795477 });
54805478 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
54815479 const sym = si.get(coff);
5482 sym.ni = ni;
5480 sym.ni = .wrap(ni);
54835481 sym.section_number = sec_si.get(coff).section_number;
54845482 },
54855483 else => si.deleteLocationRelocs(coff),
......@@ -5490,7 +5488,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
54905488 if (!isImage(coff) and sym.target_relocs != .none)
54915489 try coff.pendingSymbolTableEntry(si);
54925490
5493 break :ni sym.ni;
5491 break :ni sym.ni.unwrap().?;
54945492 };
54955493
54965494 {
......@@ -5515,7 +5513,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
55155513 try ni.resize(&coff.mf, gpa, si.get(coff).extra.size);
55165514 var parent_ni = ni;
55175515 while (true) {
5518 parent_ni = parent_ni.parent(&coff.mf);
5516 parent_ni = parent_ni.parent(&coff.mf).unwrap().?;
55195517 switch (coff.getNode(parent_ni)) {
55205518 else => unreachable,
55215519 .image_section, .pseudo_section => break,
......@@ -5542,10 +5540,11 @@ pub fn lowerUav(
55425540 try coff.pending_uavs.ensureUnusedCapacity(gpa, 1);
55435541 const umi = try coff.uavMapIndex(uav_val);
55445542 const si = umi.symbol(coff);
5545 if (switch (si.get(coff).ni) {
5546 .none => true,
5547 else => |ni| uav_align.toStdMem().order(ni.alignment(&coff.mf)).compare(.gt),
5548 }) {
5543 const need_update: bool = update: {
5544 const existing_ni = si.get(coff).ni.unwrap() orelse break :update true;
5545 break :update Alignment.compare(.fromIp(uav_align), .gt, existing_ni.alignment(&coff.mf));
5546 };
5547 if (need_update) {
55495548 const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi);
55505549 if (gop.found_existing) {
55515550 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
......@@ -5603,16 +5602,16 @@ fn updateFuncInner(
56035602 .debug,
56045603 .safe,
56055604 .fast,
5606 => target_util.defaultFunctionAlignment(target),
5607 .small => target_util.minFunctionAlignment(target),
5605 => .fromIp(target_util.defaultFunctionAlignment(target)),
5606 .small => .fromIp(target_util.minFunctionAlignment(target)),
56085607 },
5609 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
5610 }.toStdMem(),
5608 else => |a| .fromIp(a.maxStrict(target_util.minFunctionAlignment(target))),
5609 },
56115610 .moved = true,
56125611 });
56135612 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
56145613 const sym = si.get(coff);
5615 sym.ni = ni;
5614 sym.ni = .wrap(ni);
56165615 sym.section_number = sec_si.get(coff).section_number;
56175616 },
56185617 else => si.deleteLocationRelocs(coff),
......@@ -5622,7 +5621,7 @@ fn updateFuncInner(
56225621 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
56235622 if (!isImage(coff) and sym.target_relocs != .none)
56245623 try coff.pendingSymbolTableEntry(si);
5625 break :ni sym.ni;
5624 break :ni sym.ni.unwrap().?;
56265625 };
56275626
56285627 var nw: MappedFile.Node.Writer = undefined;
......@@ -5662,7 +5661,6 @@ fn flushImplib(
56625661 implib_file: []const u8,
56635662) !void {
56645663 // Emitting implibs is only valid for images
5665 assert(coff.export_table.ni != .none);
56665664
56675665 const comp = coff.base.comp;
56685666 const gpa = comp.gpa;
......@@ -5797,7 +5795,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
57975795 const loc_sym = loc_si.get(coff);
57985796
57995797 // TODO: Make this a helper for anything that needs to report "referenced by" notes
5800 switch (coff.getNode(loc_sym.ni)) {
5798 switch (coff.getNode(loc_sym.ni.unwrap().?)) {
58015799 .data_directories => {
58025800 const dir: std.coff.IMAGE.DIRECTORY_ENTRY =
58035801 @fromBackingInt(@intCast(reloc.offset / @sizeOf(std.coff.ImageDataDirectory)));
......@@ -5808,7 +5806,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
58085806 const other_ioi = isi.input(coff);
58095807 if (loc_sym.gmi == .none) {
58105808 const section = isi.inputSection(coff);
5811 const section_name = coff.getNode(loc_sym.ni.parent(&coff.mf))
5809 const section_name = coff.getNode(loc_sym.ni.unwrap().?.parent(&coff.mf).unwrap().?)
58125810 .object_section.name(coff).toSlice(coff);
58135811
58145812 if (section.comdat_si != .null) {
......@@ -6055,8 +6053,8 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
60556053 const sub_prog_node = coff.idleProgNode(
60566054 tid,
60576055 coff.symbol_prog_node,
6058 if (sym.ni != .none)
6059 coff.getNode(sym.ni)
6056 if (sym.ni.unwrap()) |sym_ni|
6057 coff.getNode(sym_ni)
60606058 else
60616059 .{ .import_thunk = sym.gmi },
60626060 );
......@@ -6173,7 +6171,7 @@ fn idleProgNode(
61736171 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
61746172 ioi.path(coff).fmtEscapeString(),
61756173 fmtMemberNameString(ioi.memberName(coff)),
6176 coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),
6174 coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf).unwrap().?).object_section.name(coff).toSlice(coff),
61776175 }) catch &name;
61786176 },
61796177 .import_thunk => |gmi| gmi.name(coff).toSlice(coff),
......@@ -6214,16 +6212,21 @@ fn flushUav(
62146212 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
62156213 const sym = si.get(coff);
62166214 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
6217 .alignment = uav_align.toStdMem(),
6215 .alignment = .fromIp(uav_align),
62186216 .moved = true,
62196217 });
62206218 coff.nodes.appendAssumeCapacity(.{ .uav = umi });
6221 sym.ni = ni;
6219 sym.ni = .wrap(ni);
62226220 sym.section_number = sec_si.get(coff).section_number;
62236221 },
62246222 else => {
6225 if (si.get(coff).ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte))
6223 if (Alignment.compare(
6224 si.get(coff).ni.unwrap().?.alignment(&coff.mf),
6225 .gte,
6226 .fromIp(uav_align),
6227 )) {
62266228 return;
6229 }
62276230 si.deleteLocationRelocs(coff);
62286231 },
62296232 }
......@@ -6233,7 +6236,7 @@ fn flushUav(
62336236 if (!isImage(coff) and sym.target_relocs != .none)
62346237 try coff.pendingSymbolTableEntry(si);
62356238
6236 break :ni sym.ni;
6239 break :ni sym.ni.unwrap().?;
62376240 };
62386241
62396242 var nw: MappedFile.Node.Writer = undefined;
......@@ -6497,7 +6500,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
64976500 lib_name,
64986501 ImportTable.Adapter{ .coff = coff },
64996502 );
6500 const import_hint_name_align: std.mem.Alignment = .@"2";
6503 const import_hint_name_align: Alignment = .@"2";
65016504 if (!gop.found_existing) {
65026505 errdefer _ = coff.import_table.entries.pop();
65036506 try coff.import_table.ni.resize(
......@@ -6507,7 +6510,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
65076510 );
65086511 const import_hint_name_table_len =
65096512 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);
6510 const idata_section_ni = coff.import_table.ni.parent(&coff.mf);
6513 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;
65116514 const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{
65126515 .size = addr_info.size * 2,
65136516 .alignment = addr_info.alignment,
......@@ -6521,7 +6524,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
65216524 const import_address_table_si = coff.addSymbolAssumeCapacity();
65226525 {
65236526 const import_address_table_sym = import_address_table_si.get(coff);
6524 import_address_table_sym.ni = import_address_table_ni;
6527 import_address_table_sym.ni = .wrap(import_address_table_ni);
65256528 assert(import_address_table_sym.loc_relocs == .none);
65266529 import_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
65276530 import_address_table_sym.section_number =
......@@ -6648,13 +6651,13 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
66486651 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
66496652
66506653 const target = &comp.root_mod.resolved_target.result;
6651 const alignment = switch (comp.root_mod.optimize_mode) {
6654 const alignment: Alignment = switch (comp.root_mod.optimize_mode) {
66526655 .debug,
66536656 .safe,
66546657 .fast,
6655 => target_util.defaultFunctionAlignment(target),
6656 .small => target_util.minFunctionAlignment(target),
6657 }.toStdMem();
6658 => .fromIp(target_util.defaultFunctionAlignment(target)),
6659 .small => .fromIp(target_util.minFunctionAlignment(target)),
6660 };
66586661 const parent_si = (try coff.pseudoSectionMapIndex(
66596662 .@".thunks",
66606663 alignment,
......@@ -6668,12 +6671,12 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
66686671 else => |tag| @panic(@tagName(tag)),
66696672 .AMD64 => {
66706673 const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 };
6671 const ni = try coff.mf.addLastChildNode(gpa, parent_sym.ni, .{
6674 const ni = try coff.mf.addLastChildNode(gpa, parent_sym.ni.unwrap().?, .{
66726675 .alignment = alignment,
66736676 .size = init.len,
66746677 });
66756678 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);
6676 sym.ni = ni;
6679 sym.ni = .wrap(ni);
66776680 sym.extra.size = init.len;
66786681 try coff.addReloc(
66796682 si,
......@@ -6736,7 +6739,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
67366739 try coff.symbols.ensureUnusedCapacity(gpa, 1);
67376740 const optional_hdr_si = coff.addSymbolAssumeCapacity();
67386741 const optional_hdr_sym = optional_hdr_si.get(coff);
6739 optional_hdr_sym.ni = Node.known.optional_header;
6742 optional_hdr_sym.ni = .wrap(Node.known.optional_header);
67406743 assert(optional_hdr_sym.loc_relocs == .none);
67416744 optional_hdr_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
67426745
......@@ -6783,7 +6786,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
67836786 try coff.symbols.ensureUnusedCapacity(gpa, 1);
67846787 const data_dir_si = coff.addSymbolAssumeCapacity();
67856788 const data_dir_sym = data_dir_si.get(coff);
6786 data_dir_sym.ni = Node.known.data_directories;
6789 data_dir_sym.ni = .wrap(Node.known.data_directories);
67876790 assert(data_dir_sym.loc_relocs == .none);
67886791 data_dir_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
67896792
......@@ -6826,7 +6829,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
68266829 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },
68276830 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },
68286831 });
6829 sym.ni = ni;
6832 sym.ni = .wrap(ni);
68306833 sym.section_number = sec_si.get(coff).section_number;
68316834 },
68326835 else => si.deleteLocationRelocs(coff),
......@@ -6836,7 +6839,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
68366839 if (!isImage(coff) and sym.target_relocs != .none)
68376840 try coff.pendingSymbolTableEntry(si);
68386841
6839 break :ni sym.ni;
6842 break :ni sym.ni.unwrap().?;
68406843 };
68416844
68426845 var required_alignment: InternPool.Alignment = .none;
......@@ -6914,7 +6917,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
69146917 const flags = coff.targetLoad(&sym.section_number.header(coff).flags);
69156918 if (!flags.CNT_UNINITIALIZED_DATA) {
69166919 const file_offset = if (isArchive(coff))
6917 sym.ni.location(&coff.mf).resolve(&coff.mf)[0]
6920 sym.ni.unwrap().?.location(&coff.mf).resolve(&coff.mf)[0]
69186921 else
69196922 ni.fileLocation(&coff.mf, false).offset;
69206923
......@@ -6927,7 +6930,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
69276930 .input_section => |isi| {
69286931 try isi.symbol(coff).flushMoved(coff);
69296932 for (coff.input_symbols.items[@backingInt(isi.firstSymbol(coff))..]) |input_symbol| {
6930 if (input_symbol.si.get(coff).ni != ni) break;
6933 if (input_symbol.si.get(coff).ni != ni.toOptional()) break;
69316934 try input_symbol.si.flushMoved(coff);
69326935 }
69336936 },
......@@ -7062,7 +7065,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
70627065 if (coff.isArchive() and coff.members.items.len > 0) {
70637066 const last_member = coff.members.items[coff.members.items.len - 1];
70647067 // See .archive_member branch for reasoning
7065 assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni);
7068 assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni.toOptional());
70667069 try coff.flushResized(last_member.content_ni);
70677070 }
70687071 },
......@@ -7090,19 +7093,15 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
70907093 => unreachable,
70917094 .archive_member => |mi| {
70927095 const content_ni = mi.get(coff).content_ni;
7093 const next_ni = content_ni.next(&coff.mf);
70947096 const content_offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf);
7095 const next_offset = switch (next_ni) {
7096 .none => offset: {
7097 assert(content_ni.parent(&coff.mf) == Node.known.file);
7098 // This must take into account the final file size. If there are trailing
7099 // bytes, they will be expected to contain another valid member header
7100 break :offset coff.mf.memory_map.memory.len;
7101 },
7102 else => offset: {
7103 assert(coff.getNode(next_ni) == .archive_member_header);
7104 break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0];
7105 },
7097 const next_offset = if (content_ni.next(&coff.mf).unwrap()) |next_ni| offset: {
7098 assert(coff.getNode(next_ni) == .archive_member_header);
7099 break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0];
7100 } else offset: {
7101 assert(content_ni.parent(&coff.mf) == Node.known.file.toOptional());
7102 // This must take into account the final file size. If there are trailing
7103 // bytes, they will be expected to contain another valid member header
7104 break :offset coff.mf.memory_map.memory.len;
71067105 };
71077106
71087107 // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size
......@@ -7356,7 +7355,7 @@ fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
73567355 const section_sym = section.si.get(coff);
73577356 section_sym.rva = rva;
73587357 coff.targetStore(&header.virtual_address, rva);
7359 try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf);
7358 try section_sym.ni.unwrap().?.childrenMoved(coff.base.comp.gpa, &coff.mf);
73607359 rva += coff.targetLoad(&header.virtual_size);
73617360 }
73627361 switch (coff.optionalHeaderPtr()) {
......@@ -7430,7 +7429,7 @@ fn updateExportInner(
74307429 // TODO: add an errMsg if this conflicts with an existing symbol
74317430 const export_si = try coff.globalSymbol(.{ .name = name });
74327431 const export_sym = export_si.get(coff);
7433 export_sym.ni = exported_ni;
7432 export_sym.ni = .wrap(exported_ni);
74347433 export_sym.rva = exported_sym.rva;
74357434 export_sym.section_number = exported_sym.section_number;
74367435 if (@"export".opts.linkage == .weak and !coff.isImage()) {
......@@ -7599,14 +7598,13 @@ fn printSymbol(
75997598 si: Symbol.Index,
76007599) !void {
76017600 const sym = si.get(coff);
7602 const node = coff.getNode(sym.ni);
7603 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{
7601 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{s: <26} | {x:08} ", .{
76047602 si,
76057603 sym.section_number,
76067604 if (sym.flags.extra_tag == .size)
76077605 @as(u64, sym.extra.size)
7608 else if (sym.ni != .none)
7609 sym.ni.location(&coff.mf).resolve(&coff.mf)[1]
7606 else if (sym.ni.unwrap()) |ni|
7607 ni.location(&coff.mf).resolve(&coff.mf)[1]
76107608 else
76117609 0,
76127610 switch (sym.flags.value_tag) {
......@@ -7627,7 +7625,7 @@ fn printSymbol(
76277625 },
76287626 sym.ni,
76297627 if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0,
7630 node,
7628 if (sym.ni.unwrap()) |ni| @tagName(coff.getNode(ni)) else "",
76317629 sym.rva,
76327630 });
76337631
......@@ -7635,7 +7633,7 @@ fn printSymbol(
76357633 try w.print("G {f}\n", .{fmtGlobalName(coff, sym.gmi)});
76367634 } else {
76377635 try w.writeAll("| ");
7638 try coff.printNodeName(w, tid, node);
7636 try coff.printNodeName(w, tid, coff.getNode(sym.ni.unwrap().?));
76397637 if (sym.flags.extra_tag == .isli)
76407638 try w.print(" | {s}", .{sym.extra.isli.name(coff).toSlice(coff)});
76417639 try w.writeByte('\n');
......@@ -7672,7 +7670,7 @@ fn printNodeName(
76727670 try w.print("({f}{f}, {s}", .{
76737671 ioi.path(coff).fmtEscapeString(),
76747672 fmtMemberNameString(ioi.memberName(coff)),
7675 coff.getNode(is.si.node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),
7673 coff.getNode(is.si.node(coff).parent(&coff.mf).unwrap().?).object_section.name(coff).toSlice(coff),
76767674 });
76777675 if (is.comdat_si != .null) {
76787676 const comdat_sym = is.comdat_si.get(coff);
src/link/Elf2.zig+182-187
......@@ -18,14 +18,16 @@ const tracy = @import("../tracy.zig");
1818const Type = @import("../Type.zig");
1919const Value = @import("../Value.zig");
2020const Zcu = @import("../Zcu.zig");
21const Alignment = MappedFile.Alignment;
2122
2223base: link.File,
2324options: link.File.OpenOptions,
2425mf: MappedFile,
2526ni: Node.Known,
2627nodes: std.MultiArrayList(Node),
28/// Does not contain an item for `SHN_UNDEF`.
2729shdrs: std.ArrayList(Section),
28phdrs: std.ArrayList(MappedFile.Node.Index),
30phdrs: std.ArrayList(MappedFile.Node.Index.Optional),
2931shndx: struct {
3032 got: Section.Index,
3133 /// Always `.UNDEF` on some targets (e.g. SPARC).
......@@ -99,7 +101,7 @@ dso_globals: std.array_hash_map.Auto(String(.strtab), struct {
99101 /// the section containing the symbol, and the symbol's offset within the section. I know this
100102 /// sounds like a terrible hack, but it is *genuinely* how you're supposed to do this. Copy
101103 /// relocations suck.
102 alignment: std.mem.Alignment,
104 alignment: Alignment,
103105}),
104106shstrtab: StringTable,
105107strtab: StringTable,
......@@ -175,7 +177,7 @@ symbol_relocs: std.ArrayList(SymbolReloc),
175177got_relocs: std.ArrayList(GotReloc),
176178/// Set of relocations which must be re-applied if the size of the TLS segment changes.
177179tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
178/// Index matches the index into `shdrs`.
180/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.
179181section_by_name: std.array_hash_map.Auto(String(.shstrtab), void),
180182/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation
181183/// entries which target that symbol must be updated to reference the correct symbol index.
......@@ -339,8 +341,6 @@ const Node = union(enum) {
339341 };
340342
341343 pub const Known = struct {
342 archive: MappedFile.Node.Index,
343 archive_header: MappedFile.Node.Index,
344344 elf: MappedFile.Node.Index,
345345 ehdr: MappedFile.Node.Index,
346346 shdr: MappedFile.Node.Index,
......@@ -349,7 +349,7 @@ const Node = union(enum) {
349349 text: MappedFile.Node.Index,
350350 data: MappedFile.Node.Index,
351351 data_rel_ro: MappedFile.Node.Index,
352 tls: MappedFile.Node.Index,
352 tls: MappedFile.Node.Index.Optional,
353353 };
354354
355355 comptime {
......@@ -505,7 +505,7 @@ const Section = struct {
505505 }
506506
507507 fn get(s: Index, elf: *Elf) *Section {
508 return &elf.shdrs.items[@backingInt(s)];
508 return &elf.shdrs.items[@backingInt(s) - 1]; // overflow means you tried to get the `.UNDEF` section
509509 }
510510
511511 fn name(s: Index, elf: *Elf) String(.shstrtab) {
......@@ -539,7 +539,7 @@ const Section = struct {
539539 }
540540 }
541541
542 fn ensureAligned(shndx: Index, elf: *Elf, min_align: std.mem.Alignment) Error!void {
542 fn ensureAligned(shndx: Index, elf: *Elf, min_align: Alignment) Error!void {
543543 switch (elf.shdrPtr(shndx)) {
544544 inline else => |shdr| {
545545 if (elf.targetLoad(&shdr.addralign) >= min_align.toByteUnits()) {
......@@ -552,7 +552,7 @@ const Section = struct {
552552 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
553553 try ni.realign(&elf.mf, elf.base.comp.gpa, min_align, .{});
554554 }
555 switch (elf.getNode(ni.parent(&elf.mf))) {
555 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
556556 .elf => {},
557557 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),
558558 else => unreachable,
......@@ -818,7 +818,7 @@ const GotReloc = struct {
818818 /// * A section
819819 /// * A NAV, UAV, or lazy code/data
820820 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
821 node: MappedFile.Node.Index,
821 node: MappedFile.Node.Index.Optional,
822822 /// The offset of the relocation inside of `node`.
823823 offset: u64,
824824 target: GotKey,
......@@ -942,8 +942,10 @@ const GotReloc = struct {
942942
943943 fn apply(reloc: *GotReloc, elf: *Elf) void {
944944 assert(elf.ehdrType() != .REL);
945 if (reloc.node == .none) return; // deleted
946 if (reloc.node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
945 const node = reloc.node.unwrap() orelse {
946 return; // deleted
947 };
948 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
947949 // There's no point applying the relocation now, because it will be re-applied by
948950 // `flushMoved` at some point anyway.
949951 return;
......@@ -968,8 +970,9 @@ const GotReloc = struct {
968970 }
969971 }
970972 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
971 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;
972 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];
973 const node = reloc.node.unwrap().?;
974 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
975 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
973976
974977 const got_vaddr = elf.shndx.got.vaddr(elf);
975978 const got_index: u64 = elf.got.getIndex(reloc.target).?;
......@@ -1587,7 +1590,7 @@ const SymbolReloc = struct {
15871590 }
15881591 },
15891592 .sparc_le_hix22 => {
1590 const tls_phndx = elf.getNode(elf.ni.tls).segment;
1593 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
15911594 const tls_size: u64 = switch (elf.phdrSlice()) {
15921595 inline else => |phdr| tls_size: {
15931596 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
......@@ -1646,7 +1649,6 @@ const SymbolReloc = struct {
16461649
16471650 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
16481651 assert(elf.ehdrType() != .REL);
1649 assert(reloc.node != .none);
16501652 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
16511653 // There's no point applying the relocation now, because it will be re-applied by
16521654 // `flushMoved` at some point anyway.
......@@ -1692,7 +1694,7 @@ const SymbolReloc = struct {
16921694 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
16931695 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
16941696 .II => {
1695 const tls_phndx = elf.getNode(elf.ni.tls).segment;
1697 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
16961698 const tls_size: u64 = switch (elf.phdrSlice()) {
16971699 inline else => |phdr| tls_size: {
16981700 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
......@@ -2044,7 +2046,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {
20442046}
20452047
20462048const AddLocalSymbolOptions = struct {
2047 node: MappedFile.Node.Index,
2049 node: MappedFile.Node.Index.Optional,
20482050 name: String(.strtab),
20492051 value: u64,
20502052 size: u64,
......@@ -2126,7 +2128,7 @@ const AddGlobalSymbolOptions = struct {
21262128 }
21272129 };
21282130
2129 node: MappedFile.Node.Index,
2131 node: MappedFile.Node.Index.Optional,
21302132 name: Name,
21312133 lib_name: ?[]const u8 = null,
21322134 value: u64,
......@@ -2294,8 +2296,8 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
22942296 }
22952297
22962298 const old_head: String(.strtab) = old_head: {
2297 if (opts.node == .none) break :old_head .empty;
2298 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(opts.node);
2299 const node = opts.node.unwrap() orelse break :old_head .empty;
2300 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(node);
22992301 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
23002302 gop.value_ptr.* = opts.name.strtab;
23012303 break :old_head old_head;
......@@ -2363,7 +2365,7 @@ fn setGlobalSymbolValue(
23632365 global_name: String(.strtab),
23642366 global_ptr: *Symbol.Global,
23652367 new: struct {
2366 node: MappedFile.Node.Index,
2368 node: MappedFile.Node.Index.Optional,
23672369 value: u64,
23682370 size: u64,
23692371 type: std.elf.STT,
......@@ -2371,18 +2373,17 @@ fn setGlobalSymbolValue(
23712373 },
23722374) void {
23732375 assert(new.shndx != .UNDEF);
2374 const old_node = global_ptr.symtab_index.ptr(elf).node;
2375 if (old_node != .none) {
2376 if (global_ptr.symtab_index.ptr(elf).node.unwrap()) |old_node| {
23762377 if (global_ptr.next_in_node != .empty) {
23772378 const next = elf.globalByName(global_ptr.next_in_node).?;
23782379 assert(next.prev_in_node == global_name);
2379 assert(next.symtab_index.ptr(elf).node == old_node);
2380 assert(next.symtab_index.ptr(elf).node.unwrap().? == old_node);
23802381 next.prev_in_node = global_ptr.prev_in_node;
23812382 }
23822383 if (global_ptr.prev_in_node != .empty) {
23832384 const prev = elf.globalByName(global_ptr.prev_in_node).?;
23842385 assert(prev.next_in_node == global_name);
2385 assert(prev.symtab_index.ptr(elf).node == old_node);
2386 assert(prev.symtab_index.ptr(elf).node.unwrap().? == old_node);
23862387 prev.next_in_node = global_ptr.next_in_node;
23872388 } else {
23882389 // We're the start of the linked list, so we need to change the head.
......@@ -2417,8 +2418,8 @@ fn setGlobalSymbolValue(
24172418 global_ptr.symtab_index.ptr(elf).node = new.node;
24182419
24192420 const old_head: String(.strtab) = old_head: {
2420 if (new.node == .none) break :old_head .empty;
2421 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new.node);
2421 const new_node = new.node.unwrap() orelse break :old_head .empty;
2422 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new_node);
24222423 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
24232424 gop.value_ptr.* = global_name;
24242425 break :old_head old_head;
......@@ -2644,7 +2645,7 @@ const Symbol = struct {
26442645 /// * A section (the symbol's value is some vaddr in that section)
26452646 /// * An input section (the symbol's value is some vaddr in that input section)
26462647 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)
2647 node: MappedFile.Node.Index,
2648 node: MappedFile.Node.Index.Optional,
26482649
26492650 /// The head of a linked list of relocations targeting this symbol.
26502651 first_target_reloc: SymbolReloc.Index,
......@@ -2852,8 +2853,7 @@ const Symbol = struct {
28522853 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at
28532854 /// some point due to a call to `flushMoved`.
28542855 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {
2855 const node = s.index(elf).ptr(elf).node;
2856 if (node != .none) {
2856 if (s.index(elf).ptr(elf).node.unwrap()) |node| {
28572857 return node.hasMoved(&elf.mf);
28582858 }
28592859 switch (s.unwrap()) {
......@@ -2998,7 +2998,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
29982998 ) catch unreachable;
29992999 gop.value_ptr.* = .{
30003000 .lsi = elf.addLocalSymbolAssumeCapacity(.{
3001 .node = node,
3001 .node = .wrap(node),
30023002 .name = try elf.string(.strtab, name),
30033003 .value = 0,
30043004 .size = 0,
......@@ -3349,16 +3349,14 @@ fn create(
33493349 .options = options,
33503350 .mf = try .init(file, comp.gpa, io),
33513351 .ni = .{
3352 .archive = .root,
3353 .archive_header = .none,
3354 .elf = .root,
3355 .ehdr = .none,
3356 .shdr = .none,
3357 .rodata = .none,
3358 .phdr = .none,
3359 .text = .none,
3360 .data = .none,
3361 .data_rel_ro = .none,
3352 .elf = undefined,
3353 .ehdr = undefined,
3354 .shdr = undefined,
3355 .rodata = undefined,
3356 .phdr = undefined,
3357 .text = undefined,
3358 .data = undefined,
3359 .data_rel_ro = undefined,
33623360 .tls = .none,
33633361 },
33643362 .nodes = .empty,
......@@ -3489,7 +3487,7 @@ fn initHeaders(
34893487 .EXEC => comp.config.link_mode == .dynamic,
34903488 .DYN => true,
34913489 };
3492 const addr_align: std.mem.Alignment = switch (class) {
3490 const addr_align: Alignment = switch (class) {
34933491 .NONE, _ => unreachable,
34943492 .@"32" => .@"4",
34953493 .@"64" => .@"8",
......@@ -3503,7 +3501,7 @@ fn initHeaders(
35033501 //
35043502 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it
35053503 // prevents alignment bugs from being hidden by your filesystem's block alignment.
3506 const node_block_align: std.mem.Alignment = elf.mf.flags.block_size;
3504 const node_block_align: Alignment = elf.mf.flags.block_size;
35073505
35083506 const plt: PltInfo = .fromMachine(machine);
35093507
......@@ -3601,18 +3599,19 @@ fn initHeaders(
36013599
36023600 const expected_nodes_len = @as(usize, if (is_archive) 2 else 0) + // .archive, .archive_header
36033601 3 + // `.file`, `.ehdr`, and `.shdr` nodes
3604 (shnum - 1) + // -1 because the null shdr does not have a `.section` node
3602 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
36053603 (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node
36063604
36073605 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
3608 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
3609 try elf.section_by_name.ensureUnusedCapacity(gpa, shnum);
3606 try elf.shdrs.ensureTotalCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
3607 try elf.section_by_name.ensureUnusedCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
36103608 try elf.phdrs.resize(gpa, phnum);
36113609 try elf.symtab.ensureTotalCapacity(gpa, 1);
36123610
36133611 if (is_archive) {
36143612 elf.nodes.appendAssumeCapacity(.archive);
3615 elf.ni.archive_header = try elf.mf.addOnlyChildNode(gpa, elf.ni.archive, .{
3613
3614 const archive_header_ni = try elf.mf.addOnlyChildNode(gpa, .root, .{
36163615 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2,
36173616 .alignment = .@"2",
36183617 .fixed = true,
......@@ -3620,7 +3619,8 @@ fn initHeaders(
36203619 .bubbles_moved = false,
36213620 .enable_next_moved = true,
36223621 });
3623 const archive_header_slice = elf.ni.archive_header.slice(&elf.mf);
3622 elf.nodes.appendAssumeCapacity(.archive_header);
3623 const archive_header_slice = archive_header_ni.slice(&elf.mf);
36243624 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);
36253625 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);
36263626 strtab_ar_hdr.* = .{
......@@ -3633,15 +3633,17 @@ fn initHeaders(
36333633 .ar_fmag = std.elf.ARFMAG.*,
36343634 };
36353635
3636 elf.nodes.appendAssumeCapacity(.archive_header);
3637 elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{
3636 elf.ni.elf = try elf.mf.addLastChildNode(gpa, .root, .{
36383637 .alignment = node_block_align.max(.@"2"),
36393638 .next_moved = true,
36403639 .bubbles_moved = false,
36413640 .enable_next_moved = true,
36423641 });
3642 elf.nodes.appendAssumeCapacity(.elf);
3643 } else {
3644 elf.ni.elf = .root;
3645 elf.nodes.appendAssumeCapacity(.elf);
36433646 }
3644 elf.nodes.appendAssumeCapacity(.elf);
36453647
36463648 const entsize: struct { ph: u32, sh: u32 } = switch (class) {
36473649 .NONE, _ => unreachable,
......@@ -3665,7 +3667,7 @@ fn initHeaders(
36653667 .bubbles_moved = false,
36663668 });
36673669 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata });
3668 elf.phdrs.items[phndx.rodata] = elf.ni.rodata;
3670 elf.phdrs.items[phndx.rodata] = .wrap(elf.ni.rodata);
36693671
36703672 elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
36713673 .size = @as(u64, phnum) * entsize.ph,
......@@ -3675,7 +3677,7 @@ fn initHeaders(
36753677 .bubbles_moved = false,
36763678 });
36773679 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr });
3678 elf.phdrs.items[phndx.phdr] = elf.ni.phdr;
3680 elf.phdrs.items[phndx.phdr] = .wrap(elf.ni.phdr);
36793681
36803682 elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
36813683 .alignment = node_block_align,
......@@ -3683,7 +3685,7 @@ fn initHeaders(
36833685 .bubbles_moved = false,
36843686 });
36853687 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text });
3686 elf.phdrs.items[phndx.text] = elf.ni.text;
3688 elf.phdrs.items[phndx.text] = .wrap(elf.ni.text);
36873689
36883690 elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
36893691 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node
......@@ -3692,7 +3694,7 @@ fn initHeaders(
36923694 .bubbles_moved = false,
36933695 });
36943696 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });
3695 elf.phdrs.items[phndx.data] = elf.ni.data;
3697 elf.phdrs.items[phndx.data] = .wrap(elf.ni.data);
36963698
36973699 if (plt.got_plt == null) {
36983700 const plt_ni = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
......@@ -3701,7 +3703,7 @@ fn initHeaders(
37013703 .bubbles_moved = false,
37023704 });
37033705 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });
3704 elf.phdrs.items[phndx.plt] = plt_ni;
3706 elf.phdrs.items[phndx.plt] = .wrap(plt_ni);
37053707 }
37063708
37073709 elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{
......@@ -3712,14 +3714,14 @@ fn initHeaders(
37123714 .bubbles_moved = false,
37133715 });
37143716 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro });
3715 elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro;
3717 elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro);
37163718
37173719 if (comp.config.any_non_single_threaded) {
3718 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
3720 elf.ni.tls = .wrap(try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
37193721 .alignment = node_block_align,
37203722 .moved = true,
37213723 .bubbles_moved = false,
3722 });
3724 }));
37233725 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls });
37243726 elf.phdrs.items[phndx.tls] = elf.ni.tls;
37253727 }
......@@ -3785,14 +3787,14 @@ fn initHeaders(
37853787 ehdr.phentsize = @sizeOf(ElfN.Phdr);
37863788 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
37873789 ehdr.shentsize = @sizeOf(ElfN.Shdr);
3788 ehdr.shnum = 1; // Only the null shdr initially---will be incremented by `addSection`
3790 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`
37893791 ehdr.shstrndx = std.elf.SHN_UNDEF;
37903792 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
37913793 },
37923794 }
37933795
37943796 elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
3795 .size = 1 * entsize.sh, // as above, only the null shdr initially
3797 .size = 1 * entsize.sh, // as above, only the SHN_UNDEF initially
37963798 .alignment = addr_align.max(node_block_align),
37973799 .moved = true,
37983800 .resized = true,
......@@ -3916,7 +3918,7 @@ fn initHeaders(
39163918 };
39173919 }
39183920
3919 if (comp.config.any_non_single_threaded) {
3921 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
39203922 const ph_tls = &phdr[phndx.tls];
39213923 ph_tls.* = .{
39223924 .type = .TLS,
......@@ -3926,7 +3928,7 @@ fn initHeaders(
39263928 .filesz = 0,
39273929 .memsz = 0,
39283930 .flags = .{ .R = true },
3929 .@"align" = @intCast(elf.ni.tls.alignment(&elf.mf).toByteUnits()),
3931 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
39303932 };
39313933 }
39323934
......@@ -3987,7 +3989,6 @@ fn initHeaders(
39873989 .entsize = 0,
39883990 };
39893991 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
3990 elf.shdrs.appendAssumeCapacity(.{ .lsi = .null, .ni = .none, .rela = .{ .shndx = .UNDEF } });
39913992
39923993 elf.symtab.addOneAssumeCapacity().* = .{
39933994 .node = .none,
......@@ -4092,7 +4093,7 @@ fn initHeaders(
40924093 .node_align = node_block_align,
40934094 });
40944095 } else {
4095 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt], .{
4096 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{
40964097 .name = ".plt",
40974098 .type = .PROGBITS,
40984099 .flags = .{ .ALLOC = true, .WRITE = true, .EXECINSTR = true },
......@@ -4115,7 +4116,7 @@ fn initHeaders(
41154116 .bubbles_moved = false,
41164117 });
41174118 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp });
4118 elf.phdrs.items[phndx.interp] = interp_ni;
4119 elf.phdrs.items[phndx.interp] = .wrap(interp_ni);
41194120
41204121 const sec_interp_shndx = try elf.addSection(interp_ni, .{
41214122 .name = ".interp",
......@@ -4135,7 +4136,7 @@ fn initHeaders(
41354136 .bubbles_moved = false,
41364137 });
41374138 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic });
4138 elf.phdrs.items[phndx.dynamic] = dynamic_ni;
4139 elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni);
41394140
41404141 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
41414142 .name = ".dynstr",
......@@ -4347,7 +4348,7 @@ fn initHeaders(
43474348 try elf.ensureUnusedSymbolCapacity(10, .maybe_global);
43484349 // Despite the name, `__dso_handle` is necessary even in static binaries.
43494350 _ = elf.addGlobalSymbolAssumeCapacity(.{
4350 .node = Section.Index.text.get(elf).ni,
4351 .node = .wrap(Section.Index.text.get(elf).ni),
43514352 .name = try .string(elf, "__dso_handle"),
43524353 .value = Section.Index.text.vaddr(elf),
43534354 .size = 0,
......@@ -4359,7 +4360,7 @@ fn initHeaders(
43594360 error.MultipleDefinitions => unreachable, // no inputs are processed yet
43604361 };
43614362 _ = elf.addGlobalSymbolAssumeCapacity(.{
4362 .node = elf.shndx.plt.get(elf).ni,
4363 .node = .wrap(elf.shndx.plt.get(elf).ni),
43634364 .name = try .string(elf, "_PROCEDURE_LINKAGE_TABLE_"),
43644365 .value = elf.shndx.plt.vaddr(elf),
43654366 .size = 0,
......@@ -4371,7 +4372,7 @@ fn initHeaders(
43714372 error.MultipleDefinitions => unreachable, // no inputs are processed yet
43724373 };
43734374 _ = elf.addGlobalSymbolAssumeCapacity(.{
4374 .node = elf.shndx.got.get(elf).ni,
4375 .node = .wrap(elf.shndx.got.get(elf).ni),
43754376 .name = try .string(elf, "_GLOBAL_OFFSET_TABLE_"),
43764377 .value = switch (machine) {
43774378 .AARCH64,
......@@ -4468,7 +4469,7 @@ fn initHeaders(
44684469 };
44694470 if (have_dynamic_section) {
44704471 _ = elf.addGlobalSymbolAssumeCapacity(.{
4471 .node = elf.shndx.dynamic.get(elf).ni,
4472 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
44724473 .name = try .string(elf, "_DYNAMIC"),
44734474 .value = elf.shndx.dynamic.vaddr(elf),
44744475 .size = 0,
......@@ -4484,16 +4485,16 @@ fn initHeaders(
44844485 assert(maybe_interp == null);
44854486 assert(!have_dynamic_section);
44864487 }
4487 if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{
4488 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
44884489 .name = ".tdata",
44894490 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
44904491 .node_align = node_block_align,
44914492 });
44924493
44934494 assert(elf.nodes.len == expected_nodes_len);
4494 assert(elf.shdrs.items.len == shnum);
4495 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF
44954496
4496 for (0..shnum) |shndx_raw| {
4497 for (1..shnum) |shndx_raw| { // start at 1 to exclude SHN_UNDEF
44974498 const shndx: Section.Index = @fromBackingInt(@intCast(shndx_raw));
44984499 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
44994500 }
......@@ -4569,7 +4570,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
45694570 .uav,
45704571 .lazy_code,
45714572 .lazy_const_data,
4572 => elf.getNode(ni.parent(&elf.mf)).section,
4573 => elf.getNode(ni.parent(&elf.mf).unwrap().?).section,
45734574 };
45744575}
45754576fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
......@@ -4593,7 +4594,7 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
45934594 };
45944595}
45954596fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4596 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) {
4597 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
45974598 .archive, .archive_header => unreachable,
45984599 .elf => return 0,
45994600 .ehdr, .shdr => unreachable,
......@@ -4660,7 +4661,7 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
46604661 if (got_relocs) |ptr| {
46614662 if (ptr.* != .none) {
46624663 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
4663 if (reloc.node != ni) break;
4664 if (reloc.node != ni.toOptional()) break;
46644665 reloc.delete(elf);
46654666 }
46664667 }
......@@ -4691,7 +4692,7 @@ fn flushMovedNodeRelocs(
46914692
46924693 if (first_got_reloc != .none) {
46934694 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {
4694 if (reloc.node != node) break;
4695 if (reloc.node != node.toOptional()) break;
46954696 reloc.apply(elf);
46964697 }
46974698 }
......@@ -4756,7 +4757,7 @@ fn targetPtrSize(elf: *const Elf) u8 {
47564757/// Page alignment for the target platform.
47574758/// Usually this returns the maximum page size supported on the
47584759/// target to maximize compatibility but there can be exceptions.
4759fn targetPageAlign(elf: *const Elf) std.mem.Alignment {
4760fn targetPageAlign(elf: *const Elf) Alignment {
47604761 return .fromByteUnits(switch (elf.ehdrMachine()) {
47614762 .AARCH64 => 0x10000,
47624763 .LOONGARCH => 0x10000,
......@@ -4810,7 +4811,7 @@ const PltInfo = struct {
48104811 /// entry, not the `.plt` entry. The `.plt.sec` section has no header entries, and is aligned to
48114812 /// the same boundary as the `.plt` section.
48124813 plt_sec: ?struct { entry_size: u8 },
4813 @"align": std.mem.Alignment,
4814 @"align": Alignment,
48144815 entry_size: u8,
48154816 header_entries: u8,
48164817
......@@ -4941,8 +4942,9 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
49414942 switch (elf.identClass()) {
49424943 .NONE, _ => unreachable,
49434944 inline else => |class| {
4945 const shdrs_len = elf.shdrs.items.len + 1; // +1 for SHN_UNDEF
49444946 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(
4945 raw_slice[0 .. elf.shdrs.items.len * @sizeOf(class.ElfN().Shdr)],
4947 raw_slice[0 .. shdrs_len * @sizeOf(class.ElfN().Shdr)],
49464948 ));
49474949 const shdr_ptr = &shdr_slice[@backingInt(shndx)];
49484950 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
......@@ -4951,7 +4953,7 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
49514953}
49524954
49534955fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr {
4954 assert(elf.ni.elf != MappedFile.Node.Index.root);
4956 assert(elf.ni.elf != .root);
49554957 const file_offset = ni.fileLocation(&elf.mf, false).offset;
49564958 return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) {
49574959 else => unreachable,
......@@ -5055,7 +5057,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
50555057 const parent_node: MappedFile.Node.Index = parent: {
50565058 if (!opts.flags.ALLOC) break :parent elf.ni.elf;
50575059 if (opts.flags.EXECINSTR) break :parent elf.ni.text;
5058 if (opts.flags.TLS) break :parent elf.ni.tls;
5060 if (opts.flags.TLS) break :parent elf.ni.tls.unwrap().?;
50595061 if (opts.flags.WRITE) break :parent elf.ni.data;
50605062 break :parent elf.ni.rodata;
50615063 };
......@@ -5148,12 +5150,12 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
51485150 break :section .data_rel_ro; // TODO: it would be better to use `.rodata` if the NAV value doesn't have relocs
51495151 }
51505152 };
5151 const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) {
5153 const alignment: Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) {
51525154 .@"fn" => a: {
51535155 const mod = zcu.navFileScope(nav_index).mod.?;
51545156 const target = &mod.resolved_target.result;
51555157 const min = target_util.minFunctionAlignment(target);
5156 break :a switch (nav.resolved.?.@"align") {
5158 break :a .fromIp(switch (nav.resolved.?.@"align") {
51575159 else => |a| a.maxStrict(min),
51585160 .none => switch (mod.optimize_mode) {
51595161 .debug,
......@@ -5162,20 +5164,20 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
51625164 => target_util.defaultFunctionAlignment(target),
51635165 .small => min,
51645166 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
5165 };
5167 });
51665168 },
51675169 else => switch (nav.resolved.?.@"align") {
5168 .none => Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu),
5169 else => |a| a,
5170 .none => .fromIp(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
5171 else => |a| .fromIp(a),
51705172 },
51715173 };
5172 try shndx.ensureAligned(elf, alignment.toStdMem());
5174 try shndx.ensureAligned(elf, alignment);
51735175 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
5174 .alignment = alignment.toStdMem(),
5176 .alignment = alignment,
51755177 });
51765178 nav_gop.value_ptr.* = .{
51775179 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5178 .node = node,
5180 .node = .wrap(node),
51795181 .name = try elf.string(.strtab, nav.fqn.toSlice(ip)),
51805182 .value = 0,
51815183 .size = 0,
......@@ -5204,19 +5206,19 @@ fn uavMapIndex(
52045206 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
52055207
52065208 const abi_align = Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu);
5207 const resolved_align: InternPool.Alignment = switch (uav_align) {
5208 .none => abi_align,
5209 else => |a| a.minStrict(abi_align),
5209 const resolved_align: Alignment = switch (uav_align) {
5210 .none => .fromIp(abi_align),
5211 else => |a| .fromIp(a.minStrict(abi_align)),
52105212 };
52115213
52125214 const uav_gop = elf.uavs.getOrPutAssumeCapacity(uav_val);
52135215 const umi: Node.UavMapIndex = @fromBackingInt(@intCast(uav_gop.index));
52145216 if (!uav_gop.found_existing) {
52155217 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
5216 try shndx.ensureAligned(elf, resolved_align.toStdMem());
5218 try shndx.ensureAligned(elf, resolved_align);
52175219 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
52185220 .moved = true, // see assert at end of `genUav`
5219 .alignment = resolved_align.toStdMem(),
5221 .alignment = resolved_align,
52205222 });
52215223 var name_buf: [32]u8 = undefined;
52225224 const name = std.fmt.bufPrint(
......@@ -5226,7 +5228,7 @@ fn uavMapIndex(
52265228 ) catch unreachable;
52275229 uav_gop.value_ptr.* = .{
52285230 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5229 .node = node,
5231 .node = .wrap(node),
52305232 .name = try elf.string(.strtab, name),
52315233 .value = 0,
52325234 .size = 0,
......@@ -5239,11 +5241,11 @@ fn uavMapIndex(
52395241 elf.const_prog_node.increaseEstimatedTotalItems(1);
52405242 elf.pending_uavs.appendAssumeCapacity(umi);
52415243 } else {
5242 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
5243 const shndx = elf.getNode(node.parent(&elf.mf)).section;
5244 try shndx.ensureAligned(elf, resolved_align.toStdMem());
5245 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
5246 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{});
5244 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node.unwrap().?;
5245 const shndx = elf.getNode(node.parent(&elf.mf).unwrap().?).section;
5246 try shndx.ensureAligned(elf, resolved_align);
5247 if (resolved_align.order(node.alignment(&elf.mf)).compare(.gt)) {
5248 try node.realign(&elf.mf, gpa, resolved_align, .{});
52475249 }
52485250 }
52495251 return umi;
......@@ -5459,7 +5461,7 @@ fn loadObject(
54595461 .member = if (member) |m| try gpa.dupe(u8, m) else null,
54605462 .extra = undefined,
54615463 };
5462 if (elf.ni.elf != MappedFile.Node.Index.root) {
5464 if (elf.ni.elf != .root) {
54635465 try elf.nodes.ensureUnusedCapacity(gpa, 1);
54645466 input.extra = .{ .node = try elf.mf.addLastChildNode(gpa, .root, .{
54655467 .size = fl.size + @sizeOf(std.elf.ar_hdr),
......@@ -5640,7 +5642,7 @@ fn loadObject(
56405642 .node_fixed = true,
56415643 },
56425644 };
5643 const need_align: std.mem.Alignment = .fromByteUnits(
5645 const need_align: Alignment = .fromByteUnits(
56445646 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),
56455647 );
56465648 try opts.shndx.ensureAligned(elf, need_align);
......@@ -5754,7 +5756,7 @@ fn loadObject(
57545756 ),
57555757 .LOCAL => {
57565758 const lsi = elf.addLocalSymbolAssumeCapacity(.{
5757 .node = input_section_node,
5759 .node = .wrap(input_section_node),
57585760 .name = try elf.string(.strtab, name),
57595761 .value = input_sym.value,
57605762 .size = input_sym.size,
......@@ -5765,7 +5767,7 @@ fn loadObject(
57655767 },
57665768 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {
57675769 si.* = elf.addGlobalSymbolAssumeCapacity(.{
5768 .node = input_section_node,
5770 .node = .wrap(input_section_node),
57695771 .name = try .string(elf, name),
57705772 .value = input_sym.value,
57715773 .size = input_sym.size,
......@@ -5893,7 +5895,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
58935895 return diags.failParse(path, "bad machine", .{});
58945896 if (ehdr.shnum > 0) try fr.seekTo(ehdr.shoff);
58955897 // We're going to need to know the alignment of every section later.
5896 const section_aligns = try gpa.alloc(std.mem.Alignment, ehdr.shnum);
5898 const section_aligns = try gpa.alloc(Alignment, ehdr.shnum);
58975899 defer gpa.free(section_aligns);
58985900 const dynamic_sh: ElfN.Shdr, const dynsym_sh: ElfN.Shdr = sh: {
58995901 var dynamic_sh: ?ElfN.Shdr = null;
......@@ -5999,7 +6001,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
59996001
60006002 // We need to guess the worst-case alignment of the symbol. Yes, I know this seems
60016003 // insane---refer to the doc comment on `alignment` in `Elf.dso_globals`.
6002 const sym_align: std.mem.Alignment = switch (sym.value) {
6004 const sym_align: Alignment = switch (sym.value) {
60036005 0 => section_aligns[sym.shndx],
60046006 else => section_aligns[sym.shndx].min(@fromBackingInt(@intCast(@ctz(sym.value)))),
60056007 };
......@@ -6158,7 +6160,7 @@ fn createInitFiniArraySection(
61586160) Error!void {
61596161 assert(shndx.* == .UNDEF);
61606162 const gpa = elf.base.comp.gpa;
6161 const addr_align: std.mem.Alignment = switch (elf.identClass()) {
6163 const addr_align: Alignment = switch (elf.identClass()) {
61626164 .NONE, _ => unreachable,
61636165 .@"32" => .@"4",
61646166 .@"64" => .@"8",
......@@ -6178,14 +6180,14 @@ fn createInitFiniArraySection(
61786180 const start_sym_name = try elf.string(.strtab, "__" ++ name ++ "_start");
61796181 const end_sym_name = try elf.string(.strtab, "__" ++ name ++ "_end");
61806182 elf.setGlobalSymbolValue(start_sym_name, elf.globals.strong_def.getPtr(start_sym_name).?, .{
6181 .node = shndx.get(elf).ni,
6183 .node = .wrap(shndx.get(elf).ni),
61826184 .value = shndx.vaddr(elf),
61836185 .size = 0,
61846186 .type = .NOTYPE,
61856187 .shndx = shndx.*,
61866188 });
61876189 elf.setGlobalSymbolValue(end_sym_name, elf.globals.strong_def.getPtr(end_sym_name).?, .{
6188 .node = shndx.get(elf).ni,
6190 .node = .wrap(shndx.get(elf).ni),
61896191 .value = shndx.vaddr(elf),
61906192 .size = 0,
61916193 .type = .NOTYPE,
......@@ -6218,7 +6220,7 @@ fn prelinkInner(elf: *Elf) Error!void {
62186220 const comp = elf.base.comp;
62196221 const gpa = comp.gpa;
62206222
6221 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == MappedFile.Node.Index.root) {
6223 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == .root) {
62226224 // We're using self-hosted codegen---add an input representing the Zig "object".
62236225 try elf.ensureUnusedSymbolCapacity(1, .all_local);
62246226 try elf.inputs.ensureUnusedCapacity(gpa, 1);
......@@ -6388,9 +6390,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
63886390 size: std.elf.Xword = 0,
63896391 link: std.elf.Word = 0,
63906392 info: std.elf.Word = 0,
6391 addralign: std.mem.Alignment = .@"1",
6393 addralign: Alignment = .@"1",
63926394 entsize: std.elf.Word = 0,
6393 node_align: std.mem.Alignment = .@"1",
6395 node_align: Alignment = .@"1",
63946396 fixed: bool = false,
63956397}) Error!Section.Index {
63966398 switch (opts.type) {
......@@ -6447,7 +6449,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
64476449 });
64486450 const addr = elf.computeNodeVAddr(ni);
64496451 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{
6450 .node = ni,
6452 .node = .wrap(ni),
64516453 .name = .empty,
64526454 .value = addr,
64536455 .size = 0,
......@@ -6499,7 +6501,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
64996501
65006502 assert(elf.section_by_name.count() == elf.shdrs.items.len);
65016503 try elf.section_by_name.ensureUnusedCapacity(gpa, 1);
6502 const rela_shndx = try elf.addSection(.none, .{
6504 const rela_shndx = try elf.addSection(elf.ni.elf, .{
65036505 .name = rela_name,
65046506 .type = .RELA,
65056507 .link = @backingInt(Section.Index.symtab),
......@@ -6546,7 +6548,6 @@ fn addRelocAssumeCapacity(
65466548 addend: i64,
65476549 @"type": MachineRelocType,
65486550) (Error || error{ UnknownRelocation, NonStaticRelocation, UnimplementedRelocation })!void {
6549 assert(node != .none);
65506551 switch (elf.ehdrType()) {
65516552 .REL => {
65526553 const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx;
......@@ -6894,7 +6895,6 @@ fn addSymbolRelocAssumeCapacity(
68946895 @"type": SymbolReloc.Type,
68956896) Error!void {
68966897 assert(elf.ehdrType() != .REL);
6897 assert(node != .none);
68986898
68996899 const rela_index: Section.RelaIndex.Optional = r: {
69006900 if (elf.shndx.dynamic == .UNDEF) break :r .none;
......@@ -7089,7 +7089,7 @@ fn addGotRelocAssumeCapacity(
70897089 }
70907090
70917091 elf.got_relocs.appendAssumeCapacity(.{
7092 .node = node,
7092 .node = .wrap(node),
70937093 .offset = offset,
70947094 .target = target,
70957095 .addend = addend,
......@@ -7111,7 +7111,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
71117111 .tpoff => |sym_id| val: {
71127112 // Only the executable's per-module TLS block is at a known offset from the TLS pointer.
71137113 if (elf.base.comp.config.output_mode == .Exe and elf.classifySymbolValue(sym_id) != .dynamic) {
7114 const tls_phndx = elf.getNode(elf.ni.tls).segment;
7114 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
71157115 const tls_size: u64 = switch (elf.phdrSlice()) {
71167116 inline else => |phdr| tls_size: {
71177117 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
......@@ -7336,7 +7336,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
73367336 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
73377337
73387338 const nmi = try elf.navMapIndex(zcu, nav_index);
7339 const ni = nmi.symbol(elf).index().ptr(elf).node;
7339 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
73407340 elf.resetNodeRelocs(ni);
73417341
73427342 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
......@@ -7392,7 +7392,7 @@ fn updateFuncInner(
73927392
73937393 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
73947394 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
7395 const ni = nmi.symbol(elf).index().ptr(elf).node;
7395 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
73967396 elf.resetNodeRelocs(ni);
73977397
73987398 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
......@@ -7677,7 +7677,7 @@ fn idleProgNode(
76777677 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
76787678 ii.path(elf).fmtEscapeString(),
76797679 fmtMemberString(ii.member(elf)),
7680 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),
7680 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
76817681 }) catch &name;
76827682 },
76837683 .nav => |nmi| {
......@@ -7737,7 +7737,7 @@ fn genUav(
77377737 const gpa = comp.gpa;
77387738
77397739 const uav_val = umi.uavValue(elf);
7740 const ni = umi.symbol(elf).index().ptr(elf).node;
7740 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;
77417741 elf.resetNodeRelocs(ni);
77427742
77437743 var nw: MappedFile.Node.Writer = undefined;
......@@ -7766,7 +7766,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
77667766 const gpa = zcu.gpa;
77677767
77687768 const lazy = lmr.lazySymbol(elf);
7769 const ni = lmr.symbol(elf).index().ptr(elf).node;
7769 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;
77707770 elf.resetNodeRelocs(ni);
77717771
77727772 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
......@@ -7842,7 +7842,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
78427842 fr.seekTo(file_loc.offset) catch |err| switch (err) {
78437843 error.Canceled => |e| return e,
78447844 else => |e| return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
7845 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),
7845 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
78467846 path.fmtEscapeString(),
78477847 fmtMemberString(ii.member(elf)),
78487848 e,
......@@ -7853,7 +7853,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
78537853 defer nw.deinit();
78547854 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {
78557855 error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
7856 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),
7856 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
78577857 path.fmtEscapeString(),
78587858 fmtMemberString(ii.member(elf)),
78597859 fr.err orelse (fr.seek_err orelse fr.size_err.?),
......@@ -7861,7 +7861,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
78617861 error.WriteFailed => return nw.err.?,
78627862 };
78637863 if (n_bytes != file_loc.size) return diags.fail("failed to read input section '{s}' from \"{f}{f}\": unexpected eof", .{
7864 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),
7864 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
78657865 path.fmtEscapeString(),
78667866 fmtMemberString(ii.member(elf)),
78677867 });
......@@ -7994,7 +7994,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
79947994 const ii = isi.input(elf);
79957995 var lsi, const end_lsi = ii.localSymbolRange(elf);
79967996 while (lsi != end_lsi) : (lsi = @fromBackingInt(@backingInt(lsi) + 1)) {
7997 if (lsi.index().ptr(elf).node != ni) continue;
7997 if (lsi.index().ptr(elf).node != ni.toOptional()) continue;
79987998 const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) {
79997999 inline else => |sym| elf.targetLoad(&sym.other).visibility,
80008000 };
......@@ -8079,7 +8079,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
80798079/// moving or resizing of a segment could reorder them and thereby affect how we handle *future*
80808080/// changes to segments.
80818081fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Error!void {
8082 const segment_ni = elf.phdrs.items[orig_phndx];
8082 const segment_ni = elf.phdrs.items[orig_phndx].unwrap().?;
80838083 assert(elf.getNode(segment_ni).segment == orig_phndx);
80848084 const page_align = elf.targetPageAlign();
80858085 const node_align = segment_ni.alignment(&elf.mf);
......@@ -8165,7 +8165,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
81658165 const next_ni = elf.phdrs.items[next_phndx];
81668166 elf.phdrs.items[phndx] = next_ni;
81678167 elf.nodes.items(.data)[@backingInt(next_ni)] = .{ .segment = phndx };
8168 elf.phdrs.items[next_phndx] = segment_ni;
8168 elf.phdrs.items[next_phndx] = .wrap(segment_ni);
81698169 elf.nodes.items(.data)[@backingInt(segment_ni)] = .{ .segment = @intCast(next_phndx) };
81708170 phndx = @intCast(next_phndx);
81718171 }
......@@ -8203,7 +8203,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
82038203 .shdr => {},
82048204 .segment => |phndx| switch (elf.phdrSlice()) {
82058205 inline else => |phdr| {
8206 assert(elf.phdrs.items[phndx] == ni);
8206 assert(elf.phdrs.items[phndx].unwrap().? == ni);
82078207 const ph = &phdr[phndx];
82088208 elf.targetStore(&ph.filesz, @intCast(size));
82098209 switch (elf.targetLoad(&ph.type)) {
......@@ -8301,51 +8301,45 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
83018301 break :member_offset switch (tag) {
83028302 else => unreachable,
83038303 .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true },
8304 .elf, .input_member => .{ offset, switch (ni.prev(&elf.mf)) {
8305 .none => unreachable,
8306 else => |prev_ni| !prev_ni.hasNextMoved(&elf.mf),
8307 } },
8304 .elf, .input_member => .{ offset, !ni.prev(&elf.mf).unwrap().?.hasNextMoved(&elf.mf) },
83088305 };
83098306 };
8310 const member_size = member_end: switch (ni.next(&elf.mf)) {
8311 else => |next_ni| {
8312 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
8313 const next_member_size = next_member_end: switch (next_ni.next(&elf.mf)) {
8314 else => |next_next_ni| {
8315 const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf);
8316 break :next_member_end next_next_offset - @sizeOf(std.elf.ar_hdr);
8317 },
8318 .none => {
8319 _, const parent_size =
8320 ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf);
8321 break :next_member_end parent_size;
8322 },
8323 } - next_offset;
8324 const ar_hdr = elf.arHdrPtr(next_ni);
8325 var name_buf: [16]u8 = undefined;
8326 _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{
8327 switch (elf.getNode(next_ni)) {
8328 else => unreachable,
8329 .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}),
8330 .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{
8331 std.fs.path.basename(ii.path(elf).sub_path),
8332 }),
8333 } catch @panic("TODO: long archive member names"),
8334 }) catch @panic("TODO: long archive member names");
8335 ar_hdr.ar_date = "0 ".*;
8336 ar_hdr.ar_uid = "0 ".*;
8337 ar_hdr.ar_gid = "0 ".*;
8338 ar_hdr.ar_mode = "644 ".*;
8339 _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch
8340 @panic("archive member too large");
8341 ar_hdr.ar_fmag = std.elf.ARFMAG.*;
8342 break :member_end next_offset - @sizeOf(std.elf.ar_hdr);
8343 },
8344 .none => {
8345 _, const parent_size = ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf);
8346 break :member_end parent_size;
8347 },
8348 } - member_offset;
8307 const member_size = if (ni.next(&elf.mf).unwrap()) |next_ni| member_size: {
8308 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
8309 const next_member_size = if (next_ni.next(&elf.mf).unwrap()) |next_next_ni| next_member_size: {
8310 const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf);
8311 const next_member_end = next_next_offset - @sizeOf(std.elf.ar_hdr);
8312 break :next_member_size next_member_end - next_offset;
8313 } else next_member_size: {
8314 _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf);
8315 const next_member_end = parent_size;
8316 break :next_member_size next_member_end - next_offset;
8317 };
8318 const ar_hdr = elf.arHdrPtr(next_ni);
8319 var name_buf: [16]u8 = undefined;
8320 _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{
8321 switch (elf.getNode(next_ni)) {
8322 else => unreachable,
8323 .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}),
8324 .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{
8325 std.fs.path.basename(ii.path(elf).sub_path),
8326 }),
8327 } catch @panic("TODO: long archive member names"),
8328 }) catch @panic("TODO: long archive member names");
8329 ar_hdr.ar_date = "0 ".*;
8330 ar_hdr.ar_uid = "0 ".*;
8331 ar_hdr.ar_gid = "0 ".*;
8332 ar_hdr.ar_mode = "644 ".*;
8333 _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch
8334 @panic("archive member too large");
8335 ar_hdr.ar_fmag = std.elf.ARFMAG.*;
8336 const member_end = next_offset - @sizeOf(std.elf.ar_hdr);
8337 break :member_size member_end - member_offset;
8338 } else member_size: {
8339 _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf);
8340 const member_end = parent_size;
8341 break :member_size member_end - member_offset;
8342 };
83498343 if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{
83508344 member_size,
83518345 }) catch @panic("archive member too large");
......@@ -8775,12 +8769,13 @@ fn updateExportInner(
87758769 // only emitting this error if the symbol we're conflicting with comes from an input
87768770 // section (as opposed to the ZCU).
87778771 const conflicting_global = elf.globalByName(try elf.string(.strtab, name)).?;
8778 const conflicting_node = conflicting_global.symtab_index.ptr(elf).node;
8779 if (elf.getNode(conflicting_node) == .input_section) {
8780 return elf.base.comp.link_diags.fail(
8781 "multiple definitions of '{s}'",
8782 .{name},
8783 );
8772 if (conflicting_global.symtab_index.ptr(elf).node.unwrap()) |conflicting_node| {
8773 if (elf.getNode(conflicting_node) == .input_section) {
8774 return elf.base.comp.link_diags.fail(
8775 "multiple definitions of '{s}'",
8776 .{name},
8777 );
8778 }
87848779 }
87858780 },
87868781 };
......@@ -8842,7 +8837,7 @@ pub fn printNode(
88428837 try w.print("({f}{f}, {s})", .{
88438838 ii.path(elf).fmtEscapeString(),
88448839 fmtMemberString(ii.member(elf)),
8845 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),
8840 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
88468841 });
88478842 },
88488843 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),
......@@ -8916,14 +8911,14 @@ pub fn printNode(
89168911 }
89178912}
89188913
8919fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignment) Error!void {
8914fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error!void {
89208915 const gpa = elf.base.comp.gpa;
89218916 // We need to loop through parent nodes because segments may be nested (e.g. a PT_TLS segment
89228917 // inside a PT_LOAD segment).
89238918 var phndx = start_phndx;
89248919 while (true) {
89258920 // Align the actual node
8926 const seg_ni = elf.phdrs.items[phndx];
8921 const seg_ni = elf.phdrs.items[phndx].unwrap().?;
89278922 if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) {
89288923 try seg_ni.realign(&elf.mf, gpa, min_align, .{});
89298924 }
......@@ -8948,7 +8943,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen
89488943 },
89498944 }
89508945 // Continue on to the parent segment, if any
8951 switch (elf.getNode(seg_ni.parent(&elf.mf))) {
8946 switch (elf.getNode(seg_ni.parent(&elf.mf).unwrap().?)) {
89528947 .segment => |parent_phndx| phndx = parent_phndx,
89538948 .elf => return,
89548949 else => unreachable,
......@@ -8959,7 +8954,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen
89598954/// Must be called deterministically after any call to `MappedFile.Node.Index.resize`
89608955/// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`.
89618956fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void {
8962 if (elf.ni.elf == MappedFile.Node.Index.root) return;
8957 if (elf.ni.elf == .root) return;
89638958 var child_it = elf.ni.elf.reverseChildren(&elf.mf);
89648959 const last_end = if (child_it.next()) |last_ni| last_end: {
89658960 const last_offset, const last_size = last_ni.location(&elf.mf).resolve(&elf.mf);
src/link/MappedFile.zig+298-187
......@@ -13,14 +13,14 @@ const windows = std.os.windows;
1313
1414io: Io,
1515flags: packed struct {
16 block_size: std.mem.Alignment,
16 block_size: Alignment,
1717 copy_file_range_unsupported: bool,
1818 fallocate_punch_hole_unsupported: bool,
1919 fallocate_insert_range_unsupported: bool,
2020},
2121memory_map: Io.File.MemoryMap,
2222nodes: std.ArrayList(Node),
23free_ni: Node.Index,
23free_ni: Node.Index.Optional,
2424large: std.ArrayList(u64),
2525updates: std.ArrayList(Node.Index),
2626/// This progress node's estimated total items is increased once for each node appended to `updates`.
......@@ -62,6 +62,94 @@ pub const Error = Allocator.Error || Io.Cancelable || error{
6262 MappedFileIo,
6363};
6464
65/// This separate `Alignment` type exists because neither of the other options is really suitable:
66///
67/// * `std.mem.Alignment` is based on `usize`, which---while technically okay since the file is
68/// memory-mapped---is in practice very annoying to work with in linker implementations
69///
70/// * `InternPool.Alignment` is based on `u64`, which is better, but it has the value `.none`, which
71/// is also really annoying to handle, because no alignment is ever nullable in this API
72///
73/// At some point we should probably just change `InternPool.Alignment` to be non-optional, and add
74/// a new `InternPool.Alignment.Optional` type for the case where it can actually be `.none`. At
75/// that point we can transition this code to using `InternPool.Alignment` (although it should
76/// probably be namespaced elsewhere, it has nothing to do with the `InternPool`!).
77pub const Alignment = enum(u6) {
78 @"1" = 0,
79 @"2" = 1,
80 @"4" = 2,
81 @"8" = 3,
82 @"16" = 4,
83 @"32" = 5,
84 @"64" = 6,
85 _,
86
87 pub fn fromIp(a: @import("../InternPool.zig").Alignment) Alignment {
88 assert(a != .none);
89 return @bitCast(a);
90 }
91
92 pub fn toLog2Units(a: Alignment) u6 {
93 return @backingInt(a);
94 }
95
96 pub fn fromLog2Units(a: u6) Alignment {
97 return @fromBackingInt(a);
98 }
99
100 pub fn toByteUnits(a: Alignment) u64 {
101 return @as(u64, 1) << @backingInt(a);
102 }
103
104 pub fn fromByteUnits(n: u64) Alignment {
105 assert(std.math.isPowerOfTwo(n));
106 return @fromBackingInt(@intCast(@ctz(n)));
107 }
108
109 pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {
110 return std.math.order(@backingInt(lhs), @backingInt(rhs));
111 }
112
113 pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
114 return std.math.compare(@backingInt(lhs), op, @backingInt(rhs));
115 }
116
117 pub fn max(lhs: Alignment, rhs: Alignment) Alignment {
118 return @fromBackingInt(@max(@backingInt(lhs), @backingInt(rhs)));
119 }
120
121 pub fn min(lhs: Alignment, rhs: Alignment) Alignment {
122 return @fromBackingInt(@min(@backingInt(lhs), @backingInt(rhs)));
123 }
124
125 pub inline fn of(comptime T: type) Alignment {
126 return comptime .fromByteUnits(@alignOf(T));
127 }
128
129 /// Given that a base address is known to be aligned to `a`, computes the known alignment of
130 /// that base address plus `off`.
131 pub fn offset(a: Alignment, off: u64) Alignment {
132 return .fromLog2Units(@min(a.toLog2Units(), @ctz(off)));
133 }
134
135 /// Align an address forwards to this alignment.
136 pub fn forward(a: Alignment, addr: u64) u64 {
137 const x = (@as(u64, 1) << @backingInt(a)) - 1;
138 return (addr + x) & ~x;
139 }
140
141 /// Align an address backwards to this alignment.
142 pub fn backward(a: Alignment, addr: u64) u64 {
143 const x = (@as(u64, 1) << @backingInt(a)) - 1;
144 return addr & ~x;
145 }
146
147 /// Check if an address is aligned to this amount.
148 pub fn check(a: Alignment, addr: u64) bool {
149 return @ctz(addr) >= @backingInt(a);
150 }
151};
152
65153pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancelable || IoError)!MappedFile {
66154 var mf: MappedFile = .{
67155 .io = io,
......@@ -101,7 +189,7 @@ pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancel
101189 .alignment = mf.flags.block_size,
102190 .fixed = true,
103191 } });
104 assert(root_ni == Node.Index.root);
192 assert(root_ni == .root);
105193 try mf.ensureTotalCapacityInner(@intCast(size));
106194 return mf;
107195}
......@@ -117,17 +205,17 @@ pub fn deinit(mf: *MappedFile, gpa: Allocator) void {
117205}
118206
119207pub const Node = extern struct {
120 parent: Node.Index,
121 prev: Node.Index,
122 next: Node.Index,
123 first: Node.Index,
124 last: Node.Index,
208 parent: Node.Index.Optional,
209 prev: Node.Index.Optional,
210 next: Node.Index.Optional,
211 first: Node.Index.Optional,
212 last: Node.Index.Optional,
125213 flags: Flags,
126214 location_payload: Location.Payload,
127215
128216 pub const Flags = packed struct(u32) {
129217 location_tag: Location.Tag,
130 alignment: std.mem.Alignment,
218 alignment: Alignment,
131219 /// Whether this node can be moved.
132220 fixed: bool,
133221 /// Whether this node has been moved.
......@@ -142,7 +230,7 @@ pub const Node = extern struct {
142230 bubbles_moved: bool,
143231 /// Whether `next_moved` events are reported in `updates`.
144232 enable_next_moved: bool,
145 unused: @Int(.unsigned, 32 - @bitSizeOf(std.mem.Alignment) - 8) = 0,
233 unused: u18 = 0,
146234 };
147235
148236 pub const Location = union(enum(u1)) {
......@@ -180,46 +268,62 @@ pub const Node = extern struct {
180268 };
181269
182270 pub const Index = enum(u32) {
183 none,
271 root,
184272 _,
185273
186 pub const root: Node.Index = .none;
274 pub const Optional = enum(u32) {
275 none = std.math.maxInt(u32),
276 _,
277
278 pub fn unwrap(oi: Optional) ?Index {
279 return switch (oi) {
280 _ => @fromBackingInt(@backingInt(oi)),
281 .none => null,
282 };
283 }
284 pub fn wrap(i: Index) Optional {
285 const oi: Optional = @bitCast(i);
286 assert(oi != .none);
287 return oi;
288 }
289 };
187290
188291 fn get(ni: Node.Index, mf: *const MappedFile) *Node {
189292 return &mf.nodes.items[@backingInt(ni)];
190293 }
191294
192 pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index {
295 /// Alias for `Optional.wrap`, provided for convenience when a result type is not available.
296 pub const toOptional = Optional.wrap;
297
298 pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
193299 return ni.get(mf).parent;
194300 }
195301
196 pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index {
302 pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
197303 return ni.get(mf).next;
198304 }
199305 fn setNext(
200306 prev_ni: Node.Index,
201307 gpa: Allocator,
202 next_ni: Node.Index,
308 next_ni: Node.Index.Optional,
203309 mf: *MappedFile,
204310 ) Allocator.Error!void {
205 assert(prev_ni != .none);
206311 const prev_next = &prev_ni.get(mf).next;
207312 if (prev_next.* == next_ni) return;
208313 prev_next.* = next_ni;
209314 try prev_ni.nextMoved(gpa, mf);
210315 }
211316
212 pub fn prev(ni: Node.Index, mf: *const MappedFile) Node.Index {
317 pub fn prev(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
213318 return ni.get(mf).prev;
214319 }
215320
216321 pub fn ChildIterator(comptime direction: enum { prev, next }) type {
217322 return struct {
218323 mf: *const MappedFile,
219 ni: Node.Index,
324 ni: Node.Index.Optional,
220325 pub fn next(it: *@This()) ?Node.Index {
221 const ni = it.ni;
222 if (ni == .none) return null;
326 const ni = it.ni.unwrap() orelse return null;
223327 it.ni = @field(ni.get(it.mf), @tagName(direction));
224328 return ni;
225329 }
......@@ -233,20 +337,20 @@ pub const Node = extern struct {
233337 }
234338
235339 pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {
236 var child_ni = ni.get(mf).last;
237 while (child_ni != .none) {
340 var child_oni = ni.get(mf).last;
341 while (child_oni.unwrap()) |child_ni| {
238342 try child_ni.moved(gpa, mf);
239 child_ni = child_ni.get(mf).prev;
343 child_oni = child_ni.get(mf).prev;
240344 }
241345 }
242346
243347 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
244348 var parent_ni = ni;
245 while (parent_ni != Node.Index.root) {
349 while (parent_ni != .root) {
246350 const parent_node = parent_ni.get(mf);
247351 if (!parent_node.flags.bubbles_moved) break;
248352 if (parent_node.flags.moved) return true;
249 parent_ni = parent_node.parent;
353 parent_ni = parent_node.parent.unwrap().?;
250354 }
251355 return false;
252356 }
......@@ -263,9 +367,8 @@ pub const Node = extern struct {
263367 if (ni.hasMoved(mf)) return;
264368 const node = ni.get(mf);
265369 node.flags.moved = true;
266 switch (node.prev) {
267 .none => {},
268 else => |prev_ni| prev_ni.nextMovedAssumeCapacity(mf),
370 if (node.prev.unwrap()) |prev_ni| {
371 prev_ni.nextMovedAssumeCapacity(mf);
269372 }
270373 if (node.flags.resized or node.flags.next_moved) return;
271374 mf.updates.appendAssumeCapacity(ni);
......@@ -314,7 +417,7 @@ pub const Node = extern struct {
314417 mf.update_prog_node.increaseEstimatedTotalItems(1);
315418 }
316419
317 pub fn alignment(ni: Node.Index, mf: *const MappedFile) std.mem.Alignment {
420 pub fn alignment(ni: Node.Index, mf: *const MappedFile) Alignment {
318421 return ni.get(mf).flags.alignment;
319422 }
320423
......@@ -361,8 +464,11 @@ pub const Node = extern struct {
361464 while (true) {
362465 const parent_node = parent_ni.get(mf);
363466 if (set_has_content) parent_node.flags.has_content = true;
364 if (parent_ni == .none) break;
365 parent_ni = parent_node.parent;
467 if (parent_ni == .root) {
468 assert(parent_node.parent == .none);
469 break;
470 }
471 parent_ni = parent_node.parent.unwrap().?;
366472 const parent_offset, _ = parent_ni.location(mf).resolve(mf);
367473 offset += parent_offset;
368474 }
......@@ -402,12 +508,12 @@ pub const Node = extern struct {
402508 };
403509
404510 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.
405 /// Asserts that `ni` is not `Node.Index.root`.
511 /// Asserts that `ni` is not `.root`.
406512 pub fn realign(
407513 ni: Node.Index,
408514 mf: *MappedFile,
409515 gpa: Allocator,
410 new_alignment: std.mem.Alignment,
516 new_alignment: Alignment,
411517 opts: RealignNodeOptions,
412518 ) Error!void {
413519 mf.realignNode(gpa, ni, new_alignment, opts) catch |err| switch (err) {
......@@ -590,9 +696,9 @@ pub const Node = extern struct {
590696};
591697
592698fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
593 parent: Node.Index = .none,
594 prev: Node.Index = .none,
595 next: Node.Index = .none,
699 parent: Node.Index.Optional = .none,
700 prev: Node.Index.Optional = .none,
701 next: Node.Index.Optional = .none,
596702 offset: u64 = 0,
597703 add_node: AddNodeOptions,
598704}) (Allocator.Error || Io.Cancelable || IoError)!Node.Index {
......@@ -605,22 +711,32 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
605711 defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 });
606712 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };
607713 };
608 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {
609 .none => .{ @fromBackingInt(@intCast(mf.nodes.items.len)), mf.nodes.addOneAssumeCapacity() },
610 else => |free_ni| {
611 const free_node = free_ni.get(mf);
612 mf.free_ni = free_node.next;
613 break :free .{ free_ni, free_node };
614 },
714
715 const free_ni: Node.Index, const free_node: *Node = if (mf.free_ni.unwrap()) |free_ni| free: {
716 const free_node = free_ni.get(mf);
717 mf.free_ni = free_node.next;
718 break :free .{ free_ni, free_node };
719 } else .{
720 @fromBackingInt(@intCast(mf.nodes.items.len)),
721 mf.nodes.addOneAssumeCapacity(),
615722 };
616 switch (opts.prev) {
617 .none => opts.parent.get(mf).first = free_ni,
618 else => |prev_ni| try prev_ni.setNext(gpa, free_ni, mf),
723
724 if (opts.prev.unwrap()) |prev_ni| {
725 try prev_ni.setNext(gpa, .wrap(free_ni), mf);
726 } else if (opts.parent.unwrap()) |parent_ni| {
727 parent_ni.get(mf).first = .wrap(free_ni);
728 } else {
729 assert(free_ni == .root);
619730 }
620 switch (opts.next) {
621 .none => opts.parent.get(mf).last = free_ni,
622 else => |next_ni| next_ni.get(mf).prev = free_ni,
731
732 if (opts.next.unwrap()) |next_ni| {
733 next_ni.get(mf).prev = .wrap(free_ni);
734 } else if (opts.parent.unwrap()) |parent_ni| {
735 parent_ni.get(mf).last = .wrap(free_ni);
736 } else {
737 assert(free_ni == .root);
623738 }
739
624740 free_node.* = .{
625741 .parent = opts.parent,
626742 .prev = opts.prev,
......@@ -659,7 +775,7 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
659775
660776pub const AddNodeOptions = struct {
661777 size: u64 = 0,
662 alignment: std.mem.Alignment = .@"1",
778 alignment: Alignment = .@"1",
663779 fixed: bool = false,
664780 moved: bool = false,
665781 resized: bool = false,
......@@ -678,7 +794,7 @@ pub fn addOnlyChildNode(
678794 const parent = parent_ni.get(mf);
679795 assert(parent.first == .none and parent.last == .none);
680796 return mf.addNode(gpa, .{
681 .parent = parent_ni,
797 .parent = .wrap(parent_ni),
682798 .add_node = opts,
683799 }) catch |err| switch (err) {
684800 error.OutOfMemory,
......@@ -700,7 +816,7 @@ pub fn addFirstChildNode(
700816 try mf.nodes.ensureUnusedCapacity(gpa, 1);
701817 const parent = parent_ni.get(mf);
702818 return mf.addNode(gpa, .{
703 .parent = parent_ni,
819 .parent = .wrap(parent_ni),
704820 .next = parent.first,
705821 .add_node = opts,
706822 }) catch |err| switch (err) {
......@@ -723,14 +839,12 @@ pub fn addLastChildNode(
723839 try mf.nodes.ensureUnusedCapacity(gpa, 1);
724840 const parent = parent_ni.get(mf);
725841 return mf.addNode(gpa, .{
726 .parent = parent_ni,
842 .parent = .wrap(parent_ni),
727843 .prev = parent.last,
728 .offset = offset: switch (parent.last) {
729 .none => 0,
730 else => |last_ni| {
731 const last_offset, const last_size = last_ni.location(mf).resolve(mf);
732 break :offset last_offset + last_size;
733 },
844 .offset = offset: {
845 const last_ni = parent.last.unwrap() orelse break :offset 0;
846 const last_offset, const last_size = last_ni.location(mf).resolve(mf);
847 break :offset last_offset + last_size;
734848 },
735849 .add_node = opts,
736850 }) catch |err| switch (err) {
......@@ -750,13 +864,12 @@ pub fn addNodeAfter(
750864 prev_ni: Node.Index,
751865 opts: AddNodeOptions,
752866) Error!Node.Index {
753 assert(prev_ni != .none);
754867 try mf.nodes.ensureUnusedCapacity(gpa, 1);
755868 const prev = prev_ni.get(mf);
756869 const prev_offset, const prev_size = prev.location().resolve(mf);
757870 return mf.addNode(gpa, .{
758871 .parent = prev.parent,
759 .prev = prev_ni,
872 .prev = .wrap(prev_ni),
760873 .next = prev.next,
761874 .offset = prev_offset + prev_size,
762875 .add_node = opts,
......@@ -783,10 +896,10 @@ fn shrinkNode(
783896 const old_offset, _ = node.location().resolve(mf);
784897
785898 // This would require unmapping first
786 assert(ni != Node.Index.root);
899 assert(ni != .root);
787900
788 if (node.last != .none) {
789 const last = node.last.get(mf);
901 if (node.last.unwrap()) |last_ni| {
902 const last = last_ni.get(mf);
790903 const last_offset, const last_size = last.location().resolve(mf);
791904 assert(last_offset + last_size > size);
792905 }
......@@ -795,15 +908,16 @@ fn shrinkNode(
795908 try mf.updates.ensureUnusedCapacity(gpa, 4);
796909
797910 ni.setLocationAssumeCapacity(mf, old_offset, size);
798 if (!shift_next or node.next == .none) return;
911 if (!shift_next) return;
912 const next_ni = node.next.unwrap() orelse return;
799913
800 const next = node.next.get(mf);
914 const next = next_ni.get(mf);
801915 const old_next_offset, const next_size = next.location().resolve(mf);
802916 const padding = old_next_offset - (old_offset + size);
803917 const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding));
804918
805919 if (next.flags.has_content and new_next_offset < old_next_offset) {
806 const old_file_offset = node.next.fileLocation(mf, false).offset;
920 const old_file_offset = next_ni.fileLocation(mf, false).offset;
807921 const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset;
808922 @memmove(
809923 mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(next_size)],
......@@ -812,7 +926,7 @@ fn shrinkNode(
812926 @memset(mf.memory_map.memory[@intCast(new_file_offset + next_size)..@intCast(old_file_offset + next_size)], 0);
813927 }
814928
815 node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size);
929 next_ni.setLocationAssumeCapacity(mf, new_next_offset, next_size);
816930}
817931
818932fn resizeNode(
......@@ -828,7 +942,8 @@ fn resizeNode(
828942 const new_size = node.flags.alignment.forward(@intCast(requested_size));
829943
830944 // Resize the entire file
831 if (ni == Node.Index.root) {
945 const parent_ni = node.parent.unwrap() orelse {
946 assert(ni == .root);
832947 try mf.ensureCapacityForSetLocation(gpa);
833948 mf.memory_map.write(io) catch |err| switch (err) {
834949 error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking
......@@ -839,15 +954,13 @@ fn resizeNode(
839954 try mf.ensureTotalCapacityInner(@intCast(new_size));
840955 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
841956 return;
842 }
843 const parent = node.parent.get(mf);
957 };
958 const parent = parent_ni.get(mf);
844959 _, var old_parent_size = parent.location().resolve(mf);
845 const trailing_end = trailing_end: switch (node.next) {
846 .none => old_parent_size,
847 else => |next_ni| {
848 const next_offset, _ = next_ni.location(mf).resolve(mf);
849 break :trailing_end next_offset;
850 },
960 const trailing_end = trailing_end: {
961 const next_ni = node.next.unwrap() orelse break :trailing_end old_parent_size;
962 const next_offset, _ = next_ni.location(mf).resolve(mf);
963 break :trailing_end next_offset;
851964 };
852965 assert(old_offset + old_size <= trailing_end);
853966 if (old_offset + new_size <= trailing_end) {
......@@ -877,7 +990,7 @@ fn resizeNode(
877990 else => |e| return e,
878991 };
879992 // Ask the filesystem driver to insert extents into the file without copying any data
880 const last_offset, const last_size = parent.last.location(mf).resolve(mf);
993 const last_offset, const last_size = parent.last.unwrap().?.location(mf).resolve(mf);
881994 const last_end = last_offset + last_size;
882995 assert(last_end <= old_parent_size);
883996 _, const file_size = Node.Index.root.location(mf).resolve(mf);
......@@ -900,13 +1013,13 @@ fn resizeNode(
9001013 enclosing.location().resolve(mf);
9011014 const new_enclosing_size = old_enclosing_size + range_size;
9021015 enclosing_ni.setLocationAssumeCapacity(mf, enclosing_offset, new_enclosing_size);
903 if (enclosing_ni == Node.Index.root) {
1016 if (enclosing_ni == .root) {
9041017 assert(enclosing_offset == 0);
9051018 try mf.ensureTotalCapacityInner(@intCast(new_enclosing_size));
9061019 break;
9071020 }
908 var after_ni = enclosing.next;
909 while (after_ni != .none) {
1021 var after_oni = enclosing.next;
1022 while (after_oni.unwrap()) |after_ni| {
9101023 try mf.ensureCapacityForSetLocation(gpa);
9111024 const after = after_ni.get(mf);
9121025 const after_offset, const after_size = after.location().resolve(mf);
......@@ -915,9 +1028,9 @@ fn resizeNode(
9151028 range_size + after_offset,
9161029 after_size,
9171030 );
918 after_ni = after.next;
1031 after_oni = after.next;
9191032 }
920 enclosing_ni = enclosing.parent;
1033 enclosing_ni = enclosing.parent.unwrap().?;
9211034 }
9221035 return;
9231036 },
......@@ -939,32 +1052,33 @@ fn resizeNode(
9391052 if (node.next == .none) {
9401053 // As this is the last node, we simply need more space in the parent
9411054 const new_parent_size = old_offset + new_size;
942 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);
1055 try mf.resizeNode(gpa, parent_ni, new_parent_size +| new_parent_size / growth_factor);
9431056 try mf.ensureCapacityForSetLocation(gpa);
9441057 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
9451058 return;
9461059 }
9471060 if (!node.flags.fixed) {
9481061 // Make space at the end of the parent for this floating node
949 const last = parent.last.get(mf);
1062 const last = parent.last.unwrap().?.get(mf);
9501063 const last_offset, const last_size = last.location().resolve(mf);
9511064 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));
9521065 const new_parent_size = new_offset + new_size;
9531066 if (new_parent_size > old_parent_size)
954 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);
1067 try mf.resizeNode(gpa, parent_ni, new_parent_size +| new_parent_size / growth_factor);
9551068 try mf.ensureCapacityForSetLocation(gpa);
956 const next_ni = node.next;
1069 const next_ni = node.next.unwrap().?;
9571070 next_ni.get(mf).prev = node.prev;
958 switch (node.prev) {
959 .none => parent.first = next_ni,
960 else => |prev_ni| try prev_ni.setNext(gpa, next_ni, mf),
1071 if (node.prev.unwrap()) |prev_ni| {
1072 try prev_ni.setNext(gpa, .wrap(next_ni), mf);
1073 } else {
1074 parent.first = .wrap(next_ni);
9611075 }
962 try parent.last.setNext(gpa, ni, mf);
1076 try parent.last.unwrap().?.setNext(gpa, .wrap(ni), mf);
9631077 node.prev = parent.last;
9641078 try ni.setNext(gpa, .none, mf);
965 parent.last = ni;
1079 parent.last = .wrap(ni);
9661080 if (node.flags.has_content) {
967 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
1081 const parent_file_offset = parent_ni.fileLocation(mf, false).offset;
9681082 try mf.moveRange(
9691083 parent_file_offset + old_offset,
9701084 parent_file_offset + new_offset,
......@@ -976,94 +1090,89 @@ fn resizeNode(
9761090 }
9771091 // Search for the first floating node following this fixed node
9781092 var last_fixed_ni = ni;
979 var first_floating_ni = node.next;
1093 var first_floating_oni = node.next;
9801094 var shift = new_size - old_size;
981 var max_shift_align: std.mem.Alignment = .@"1";
1095 var max_shift_align: Alignment = .@"1";
9821096 var direction: enum { forward, reverse } = .forward;
9831097 while (true) {
984 assert(last_fixed_ni != .none);
9851098 const last_fixed = last_fixed_ni.get(mf);
9861099 assert(last_fixed.flags.fixed);
9871100 const old_last_fixed_offset, const last_fixed_size = last_fixed.location().resolve(mf);
9881101 const new_last_fixed_offset = old_last_fixed_offset + shift;
989 make_space: switch (first_floating_ni) {
990 else => {
991 const first_floating = first_floating_ni.get(mf);
992 const old_first_floating_offset, const first_floating_size =
993 first_floating.location().resolve(mf);
994 assert(old_last_fixed_offset + last_fixed_size <= old_first_floating_offset);
995 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)
996 break :make_space;
997 assert(direction == .forward);
998 max_shift_align = max_shift_align.max(first_floating.flags.alignment.max(last_fixed.flags.alignment));
999 if (first_floating.flags.fixed) {
1000 shift = max_shift_align.forward(@intCast(
1001 @max(shift, first_floating_size),
1002 ));
1003
1004 // Not enough space, try the next node
1005 last_fixed_ni = first_floating_ni;
1006 first_floating_ni = first_floating.next;
1007 continue;
1008 }
1009 // Move the found floating node to make space for preceding fixed nodes
1010 const last = parent.last.get(mf);
1011 const last_offset, const last_size = last.location().resolve(mf);
1012 const new_first_floating_offset = max_shift_align.forward(
1013 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),
1102 if (first_floating_oni.unwrap()) |first_floating_ni| make_space: {
1103 const first_floating = first_floating_ni.get(mf);
1104 const old_first_floating_offset, const first_floating_size =
1105 first_floating.location().resolve(mf);
1106 assert(old_last_fixed_offset + last_fixed_size <= old_first_floating_offset);
1107 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)
1108 break :make_space;
1109 assert(direction == .forward);
1110 max_shift_align = max_shift_align.max(first_floating.flags.alignment.max(last_fixed.flags.alignment));
1111 if (first_floating.flags.fixed) {
1112 shift = max_shift_align.forward(@intCast(
1113 @max(shift, first_floating_size),
1114 ));
1115
1116 // Not enough space, try the next node
1117 last_fixed_ni = first_floating_ni;
1118 first_floating_oni = first_floating.next;
1119 continue;
1120 }
1121 // Move the found floating node to make space for preceding fixed nodes
1122 const last = parent.last.unwrap().?.get(mf);
1123 const last_offset, const last_size = last.location().resolve(mf);
1124 const new_first_floating_offset = max_shift_align.forward(
1125 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),
1126 );
1127 const new_parent_size = new_first_floating_offset + first_floating_size;
1128 if (new_parent_size > old_parent_size) {
1129 try mf.resizeNode(
1130 gpa,
1131 parent_ni,
1132 new_parent_size +| new_parent_size / growth_factor,
10141133 );
1015 const new_parent_size = new_first_floating_offset + first_floating_size;
1016 if (new_parent_size > old_parent_size) {
1017 try mf.resizeNode(
1018 gpa,
1019 node.parent,
1020 new_parent_size +| new_parent_size / growth_factor,
1021 );
1022 _, old_parent_size = parent.location().resolve(mf);
1023 }
1024 try mf.ensureCapacityForSetLocation(gpa);
1025 if (parent.last != first_floating_ni) {
1026 const old_last = parent.last;
1027 first_floating.prev = old_last;
1028 parent.last = first_floating_ni;
1029 try old_last.setNext(gpa, first_floating_ni, mf);
1030 try last_fixed_ni.setNext(gpa, first_floating.next, mf);
1031 switch (first_floating.next) {
1032 .none => {},
1033 else => |next_ni| next_ni.get(mf).prev = last_fixed_ni,
1034 }
1035 try first_floating_ni.setNext(gpa, .none, mf);
1036 }
1037 if (first_floating.flags.has_content) {
1038 const parent_file_offset =
1039 node.parent.fileLocation(mf, false).offset;
1040 try mf.moveRange(
1041 parent_file_offset + old_first_floating_offset,
1042 parent_file_offset + new_first_floating_offset,
1043 first_floating_size,
1044 );
1134 _, old_parent_size = parent.location().resolve(mf);
1135 }
1136 try mf.ensureCapacityForSetLocation(gpa);
1137 if (parent.last.unwrap().? != first_floating_ni) {
1138 const old_last = parent.last.unwrap().?;
1139 first_floating.prev = .wrap(old_last);
1140 parent.last = .wrap(first_floating_ni);
1141 try old_last.setNext(gpa, .wrap(first_floating_ni), mf);
1142 try last_fixed_ni.setNext(gpa, first_floating.next, mf);
1143 if (first_floating.next.unwrap()) |next_ni| {
1144 next_ni.get(mf).prev = .wrap(last_fixed_ni);
10451145 }
1046 first_floating_ni.setLocationAssumeCapacity(
1047 mf,
1048 new_first_floating_offset,
1146 try first_floating_ni.setNext(gpa, .none, mf);
1147 }
1148 if (first_floating.flags.has_content) {
1149 const parent_file_offset =
1150 parent_ni.fileLocation(mf, false).offset;
1151 try mf.moveRange(
1152 parent_file_offset + old_first_floating_offset,
1153 parent_file_offset + new_first_floating_offset,
10491154 first_floating_size,
10501155 );
1051 // Continue the search after the just-moved floating node
1052 first_floating_ni = last_fixed.next;
1053 continue;
1054 },
1055 .none => {
1056 assert(direction == .forward);
1057 const new_parent_size = new_last_fixed_offset + last_fixed_size;
1058 if (new_parent_size > old_parent_size) {
1059 try mf.resizeNode(
1060 gpa,
1061 node.parent,
1062 new_parent_size +| new_parent_size / growth_factor,
1063 );
1064 _, old_parent_size = parent.location().resolve(mf);
1065 }
1066 },
1156 }
1157 first_floating_ni.setLocationAssumeCapacity(
1158 mf,
1159 new_first_floating_offset,
1160 first_floating_size,
1161 );
1162 // Continue the search after the just-moved floating node
1163 first_floating_oni = last_fixed.next;
1164 continue;
1165 } else {
1166 assert(direction == .forward);
1167 const new_parent_size = new_last_fixed_offset + last_fixed_size;
1168 if (new_parent_size > old_parent_size) {
1169 try mf.resizeNode(
1170 gpa,
1171 parent_ni,
1172 new_parent_size +| new_parent_size / growth_factor,
1173 );
1174 _, old_parent_size = parent.location().resolve(mf);
1175 }
10671176 }
10681177 try mf.ensureCapacityForSetLocation(gpa);
10691178 if (last_fixed_ni == ni) {
......@@ -1077,7 +1186,7 @@ fn resizeNode(
10771186 }
10781187 // Move a fixed node into trailing free space
10791188 if (last_fixed.flags.has_content) {
1080 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
1189 const parent_file_offset = parent_ni.fileLocation(mf, false).offset;
10811190 try mf.moveRange(
10821191 parent_file_offset + old_last_fixed_offset,
10831192 parent_file_offset + new_last_fixed_offset,
......@@ -1086,8 +1195,8 @@ fn resizeNode(
10861195 }
10871196 last_fixed_ni.setLocationAssumeCapacity(mf, new_last_fixed_offset, last_fixed_size);
10881197 // Retry the previous nodes now that there is enough space
1089 first_floating_ni = last_fixed_ni;
1090 last_fixed_ni = last_fixed.prev;
1198 first_floating_oni = .wrap(last_fixed_ni);
1199 last_fixed_ni = last_fixed.prev.unwrap().?;
10911200 direction = .reverse;
10921201 }
10931202}
......@@ -1096,7 +1205,7 @@ fn realignNode(
10961205 mf: *MappedFile,
10971206 gpa: Allocator,
10981207 ni: Node.Index,
1099 new_alignment: std.mem.Alignment,
1208 new_alignment: Alignment,
11001209 opts: Node.Index.RealignNodeOptions,
11011210) (Allocator.Error || Io.Cancelable || IoError)!void {
11021211 mf.nodes_lock.assertUnlocked();
......@@ -1109,25 +1218,27 @@ fn realignNode(
11091218 }
11101219
11111220 const old_offset, const size = node.location().resolve(mf);
1112 if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size);
1221 const parent_ni = node.parent.unwrap() orelse {
1222 assert(ni == .root);
1223 return mf.resizeNode(gpa, ni, size);
1224 };
11131225
11141226 const new_size = new_alignment.forward(@intCast(size));
11151227 if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size);
11161228
1117 _, const parent_size = node.parent.location(mf).resolve(mf);
1118 const trailing_end = trailing_end: switch (node.next) {
1119 .none => parent_size,
1120 else => |next_ni| {
1121 const next_offset, _ = next_ni.location(mf).resolve(mf);
1122 break :trailing_end next_offset;
1123 },
1229 _, const parent_size = parent_ni.location(mf).resolve(mf);
1230 const trailing_end = trailing_end: {
1231 const next_ni = node.next.unwrap() orelse break :trailing_end parent_size;
1232 const next_offset, _ = next_ni.location(mf).resolve(mf);
1233 break :trailing_end next_offset;
11241234 };
11251235
11261236 if (opts.try_backwards) {
11271237 const backward_offset = new_alignment.backward(@intCast(old_offset));
1128 const prev_end = if (node.prev == .none) 0 else prev: {
1129 const prev_offset, const prev_size = node.prev.location(mf).resolve(mf);
1130 break :prev prev_offset + prev_size;
1238 const prev_end = prev_end: {
1239 const prev_ni = node.prev.unwrap() orelse break :prev_end 0;
1240 const prev_offset, const prev_size = prev_ni.location(mf).resolve(mf);
1241 break :prev_end prev_offset + prev_size;
11311242 };
11321243
11331244 if (backward_offset >= prev_end) {
......@@ -1399,7 +1510,7 @@ fn verify(mf: *MappedFile) void {
13991510 assert(root.parent == .none);
14001511 assert(root.prev == .none);
14011512 assert(root.next == .none);
1402 mf.verifyNode(Node.Index.root);
1513 mf.verifyNode(.root);
14031514}
14041515
14051516fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void {
......@@ -1517,7 +1628,7 @@ test {
15171628 try testVerifyContent(&mf, d, 0xdd, d_init_size);
15181629 }
15191630
1520 const child_init: []const struct { std.mem.Alignment, usize } = &.{
1631 const child_init: []const struct { Alignment, usize } = &.{
15211632 .{ .@"16", 16 },
15221633 .{ .@"1", 1 },
15231634 .{ .@"1", 19 },