diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 9a34d3ebdbf7be956d066caf98a71933afabf137..943a092b38dab0197e55d830e9e45ed79215f826 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -861,6 +861,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { log.debug("tracking failed for %{d}", .{old_inst}); tracked_inst.inst = .lost; try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index }); + try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .lost_tracking = tracked_inst_index }); continue; }; tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst); @@ -981,7 +982,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { /// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies /// that the file's namespace is scanned, discovering declarations. /// -/// Typical Zig compilations begin by claling this function on the root source file of the standard +/// Typical Zig compilations begin by calling this function on the root source file of the standard /// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in /// that file, which is queued for analysis, and everything goes from there. pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void { diff --git a/src/link.zig b/src/link.zig index 4f179e3ac7e7bc0e366262da3817c529b20c0ad7..6c2899ab94c3efc7d9ce394c073fab890a463cdb 100644 --- a/src/link.zig +++ b/src/link.zig @@ -878,12 +878,11 @@ pub const File = struct { const inst = file.zir.?.instructions.get(@backingInt(ti.inst)); assert(inst.tag == .declaration); } - switch (base.tag) { .lld => unreachable, + .plan9 => unreachable, .spirv => {}, - .plan9 => unreachable, - .elf2, .coff2 => {}, + .coff2 => {}, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); @@ -891,6 +890,19 @@ pub const File = struct { } } + fn lostTracking(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) Error!void { + assert(base.comp.zcu.?.llvm_object == null); + switch (base.tag) { + .lld => unreachable, + .plan9 => unreachable, + else => {}, + inline .elf2 => |tag| { + dev.check(tag.devFeature()); + return @as(*tag.Type(), @fieldParentPtr("base", base)).lostTracking(pt, ti_id); + }, + } + } + pub fn releaseLock(base: *File) void { const comp = base.comp; const io = comp.io; @@ -1441,6 +1453,7 @@ pub const ZcuTask = union(enum) { success: bool, }, debug_update_line_number: InternPool.TrackedInst.Index, + lost_tracking: InternPool.TrackedInst.Index, }; pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { @@ -1713,6 +1726,19 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void } break :nav null; }, + .lost_tracking => |ti| nav: { + const nav_prog_node = comp.link_prog_node.start("Lost tracking", 0); + defer nav_prog_node.end(); + if (pt.zcu.llvm_object == null) { + if (comp.bin_file) |lf| { + lf.lostTracking(pt, ti) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + else => |e| log.err("lost tracking failed: {s}", .{@errorName(e)}), + }; + } + } + break :nav null; + }, }; if (timer.finish(io)) |ns_link| report_time: { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 5ba57bee9d7ba76c6588f7c3320accc84e0a9c91..7d04b80e8d2a39b47a54b4a6dd15c4d71cbf0997 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -536,7 +536,7 @@ pub const Member = struct { const new_size = Alignment.@"4".forward(old_size + name.len + 1); assert(new_size < comptime try std.math.powi(u64, 10, max_name_len - 1)); - try Node.known.longnames_member.resizeLeaf(&coff.mf, gpa, new_size); + try Node.known.longnames_member.resizeLeaf(gpa, &coff.mf, new_size); const name_table_slice = Node.known.longnames_member.slice(&coff.mf); const name_slice = name_table_slice[@intCast(old_size)..][0 .. name.len + 1]; @memcpy(name_slice[0..name.len], name); @@ -1840,13 +1840,13 @@ fn initHeaders( coff.nodes.appendAssumeCapacity(.file); const header_ni = Node.known.header; - assert(header_ni == try Node.known.file.addOnlyHeaderChild(&coff.mf, gpa, .{ + assert(header_ni == try Node.known.file.addOnlyHeaderChild(gpa, &coff.mf, .{ .alignment = coff.mf.flags.block_size, })); coff.nodes.appendAssumeCapacity(.header); const coff_parent_ni: MappedFile.Node.Index = if (is_archive) parent: { - assert(try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .wrap(header_ni), .{ + assert(try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .wrap(header_ni), .{ .size = std.coff.archive_signature.len, .alignment = .@"4", }) == Node.known.signature); @@ -1879,7 +1879,7 @@ fn initHeaders( const zcu_member = zcu_mi.get(coff); try zcu_member.initHeader(coff, zcu.main_mod.fully_qualified_name, timestamp); - assert(try zcu_member.content_ni.addOnlyHeaderChild(&coff.mf, gpa, .{ + assert(try zcu_member.content_ni.addOnlyHeaderChild(gpa, &coff.mf, .{ .size = @sizeOf(std.coff.Header), .alignment = .@"4", }) == Node.known.coff_header); @@ -1894,13 +1894,13 @@ fn initHeaders( // no other members then the last linker member (longnames) needs to expand // to fill the padding at the end of the file. while (coff.nodes.len < Node.known_count) { - _ = try Node.known.header.addHeaderChildAfter(&coff.mf, gpa, .none, .{}); + _ = try Node.known.header.addHeaderChildAfter(gpa, &coff.mf, .none, .{}); coff.nodes.appendAssumeCapacity(.placeholder); } return; } else parent: { - assert(try header_ni.addOnlyHeaderChild(&coff.mf, gpa, .{ + assert(try header_ni.addOnlyHeaderChild(gpa, &coff.mf, .{ .size = if (is_image) msdos_stub.len + std.coff.pe_signature.len else 0, .alignment = .@"4", }) == Node.known.signature); @@ -1913,12 +1913,12 @@ fn initHeaders( // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types? while (true) { - const placeholder_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .none, .{}); + const placeholder_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .none, .{}); coff.nodes.appendAssumeCapacity(.placeholder); if (placeholder_ni == Node.known.zcu_member) break; } - assert(try header_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(Node.known.signature), .{ + assert(try header_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(Node.known.signature), .{ .size = @sizeOf(std.coff.Header), .alignment = .@"4", }) == Node.known.coff_header); @@ -1949,7 +1949,7 @@ fn initHeaders( } const optional_header_ni = Node.known.optional_header; - assert(optional_header_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(Node.known.coff_header), .{ + assert(optional_header_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(Node.known.coff_header), .{ .size = optional_header_size, .alignment = .@"4", })); @@ -2060,7 +2060,7 @@ fn initHeaders( } const data_directories_ni = Node.known.data_directories; - assert(data_directories_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(optional_header_ni), .{ + assert(data_directories_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(optional_header_ni), .{ .size = data_directories_size, .alignment = .@"4", })); @@ -2075,7 +2075,7 @@ fn initHeaders( } const section_table_ni = Node.known.section_table; - assert(section_table_ni == try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(data_directories_ni), .{ + assert(section_table_ni == try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(data_directories_ni), .{ .alignment = .@"4", })); coff.nodes.appendAssumeCapacity(.section_table); @@ -2084,13 +2084,13 @@ fn initHeaders( if (!is_image) { // TODO: These two nodes could be inside one movable node? - coff.symbol_table.ni = try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(section_table_ni), .{ + coff.symbol_table.ni = try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(section_table_ni), .{ .alignment = .@"2", .moved = true, }); coff.nodes.appendAssumeCapacity(.symbol_table); - coff.symbol_table.strings_ni = try coff_parent_ni.addHeaderChildAfter(&coff.mf, gpa, .wrap(coff.symbol_table.ni), .{ + coff.symbol_table.strings_ni = try coff_parent_ni.addHeaderChildAfter(gpa, &coff.mf, .wrap(coff.symbol_table.ni), .{ .size = @sizeOf(u32), .resized = true, }); @@ -2143,7 +2143,7 @@ fn initHeaders( coff.mf.flags.block_size, .{ .read = true, .initialized = true }, )).symbol(coff).node(coff); - coff.import_table.ni = try import_table_parent_ni.addFloatingChild(&coff.mf, gpa, .{ + coff.import_table.ni = try import_table_parent_ni.addFloatingChild(gpa, &coff.mf, .{ .alignment = .@"4", }); coff.nodes.appendAssumeCapacity(.import_directory_table); @@ -2154,7 +2154,7 @@ fn initHeaders( .{ .read = true, .initialized = true }, )).symbol(coff).node(coff); - coff.export_table.export_directory_table_ni = try coff.export_table.ni.addHeaderChildAfter(&coff.mf, gpa, coff.export_table.ni.last(&coff.mf), .{ + coff.export_table.export_directory_table_ni = try coff.export_table.ni.addHeaderChildAfter(gpa, &coff.mf, coff.export_table.ni.last(&coff.mf), .{ .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1, .moved = true, }); @@ -2165,7 +2165,7 @@ fn initHeaders( @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]); @memset(table_slice[name_index + file_name.len ..], 0); - const export_address_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{ + const export_address_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{ .alignment = .of(std.coff.ExportAddressTableEntry), .moved = true, }); @@ -2181,19 +2181,19 @@ fn initHeaders( export_address_table_sym.section_number = coff.getNode(coff.export_table.ni).pseudo_section.symbol(coff).get(coff).section_number; - coff.export_table.name_pointer_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{ + coff.export_table.name_pointer_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{ .alignment = .of(std.coff.ExportNamePointerTableEntry), .moved = true, }); coff.nodes.appendAssumeCapacity(.export_name_pointer_table); - coff.export_table.ordinal_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{ + coff.export_table.ordinal_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{ .alignment = .of(std.coff.ExportOrdinalTableEntry), .moved = true, }); coff.nodes.appendAssumeCapacity(.export_ordinal_table); - coff.export_table.name_table_ni = try coff.export_table.ni.addFloatingChild(&coff.mf, gpa, .{ + coff.export_table.name_table_ni = try coff.export_table.ni.addFloatingChild(gpa, &coff.mf, .{ .alignment = .of(u8), .moved = true, }); @@ -2286,7 +2286,7 @@ pub fn initBuiltins(coff: *Coff) !void { const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data }); const list_len_sym = list_len_si.get(coff); list_len_sym.setExtra(.{ .size = addr_info.size }); - list_len_sym.ni = .wrap(try start_sym.ni.unwrap().?.addHeaderChildAfter(&coff.mf, gpa, .none, .{ + list_len_sym.ni = .wrap(try start_sym.ni.unwrap().?.addHeaderChildAfter(gpa, &coff.mf, .none, .{ .size = addr_info.size, })); coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si }); @@ -2307,7 +2307,7 @@ pub fn initBuiltins(coff: *Coff) !void { const list_end_si = coff.addSymbolAssumeCapacity(); const list_end_sym = list_end_si.get(coff); list_end_sym.setExtra(.{ .size = addr_info.size }); - list_end_sym.ni = .wrap(try end_sym.ni.unwrap().?.addHeaderChildAfter(&coff.mf, gpa, .none, .{ + list_end_sym.ni = .wrap(try end_sym.ni.unwrap().?.addHeaderChildAfter(gpa, &coff.mf, .none, .{ .size = addr_info.size, })); coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si }); @@ -2723,7 +2723,7 @@ fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !Symbo const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1]; string_gop.value_ptr.* = @fromBackingInt(@intCast(string_index)); - try coff.symbol_table.strings_ni.resizeLeaf(&coff.mf, gpa, string_index + name.len + 1); + try coff.symbol_table.strings_ni.resizeLeaf(gpa, &coff.mf, string_index + name.len + 1); const slice = coff.symbol_table.strings_ni.slice(&coff.mf); @memcpy(slice[@intCast(string_index)..][0..name.len], name); slice[@intCast(string_index + name.len)] = 0; @@ -2948,7 +2948,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind, const comp = coff.base.comp; const gpa = comp.gpa; - const header_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, Node.known.file.last(&coff.mf), .{ + const header_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, Node.known.file.last(&coff.mf), .{ .size = @sizeOf(std.coff.ArchiveMemberHeader), .alignment = .@"2", .moved = true, @@ -2960,7 +2960,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind, .first_linker, .second_linker, .longnames, .coff => .@"4", else => .@"2", }; - const content_ni = try Node.known.file.addHeaderChildAfter(&coff.mf, gpa, .wrap(header_ni), .{ + const content_ni = try Node.known.file.addHeaderChildAfter(gpa, &coff.mf, .wrap(header_ni), .{ .alignment = content_align, .size = content_align.forward(size), .resized = size > 0, @@ -2989,7 +2989,7 @@ fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind, const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1]; const old_header_size = new_num_members * @sizeOf(u32); const trailing_size: usize = @intCast(old_size - old_header_size); - try Node.known.second_linker_member.resizeLeaf(&coff.mf, gpa, old_size + @sizeOf(u32)); + try Node.known.second_linker_member.resizeLeaf(gpa, &coff.mf, old_size + @sizeOf(u32)); const slice = Node.known.second_linker_member.slice(&coff.mf); @memmove( @@ -3060,7 +3060,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { { const old_header_size: usize = @intCast(@sizeOf(u32) + @backingInt(mfli) * @sizeOf(u32)); const new_header_size: usize = @intCast(old_header_size + @sizeOf(u32)); - try Node.known.first_linker_member.resizeLeaf(&coff.mf, gpa, Alignment.@"4".forward(new_header_size + new_string_table_size)); + try Node.known.first_linker_member.resizeLeaf(gpa, &coff.mf, Alignment.@"4".forward(new_header_size + new_string_table_size)); const slice = Node.known.first_linker_member.slice(&coff.mf); @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); @@ -3074,7 +3074,7 @@ fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @backingInt(mfli) * @sizeOf(u16); const new_header_size = old_header_size + @sizeOf(u16); - try Node.known.second_linker_member.resizeLeaf(&coff.mf, gpa, Alignment.@"4".forward(new_header_size + new_string_table_size)); + try Node.known.second_linker_member.resizeLeaf(gpa, &coff.mf, Alignment.@"4".forward(new_header_size + new_string_table_size)); const old_needs_sort = coff.pending_members.get(Member.Index.second) != null; const needs_sort = old_needs_sort or (if (coff.lib_string_table.items.len > 0) @@ -3181,7 +3181,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32) !void { const new_num_symbols = old_num_symbols + 1 + num_aux_symbols; coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols); - try coff.symbol_table.ni.resizeLeaf(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf()); + try coff.symbol_table.ni.resizeLeaf(gpa, &coff.mf, new_num_symbols * std.coff.Symbol.sizeOf()); sti.* = .wrap(old_num_symbols); si.flushSymbolTableIndex(coff); @@ -3317,7 +3317,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void { try fr.seekTo(file_loc.offset); var nw: MappedFile.Node.Writer = undefined; const si = isi.symbol(coff); - si.node(coff).writer(&coff.mf, gpa, &nw); + si.node(coff).writer(gpa, &coff.mf, &nw); defer nw.deinit(); log.debug("flushInputSection({f}{f}, {s}, {d}, n{d})", .{ path, @@ -3345,12 +3345,12 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S const section_table_len = section_index + 1; coff.targetStore(&coff_header.number_of_sections, section_table_len); try Node.known.section_table.resizeLeaf( + gpa, &coff.mf, - gpa, @sizeOf(std.coff.SectionHeader) * section_table_len, ); - const ni = try coff.sectionParent().addFloatingChild(&coff.mf, gpa, .{ + const ni = try coff.sectionParent().addFloatingChild(gpa, &coff.mf, .{ .alignment = coff.mf.flags.block_size, .moved = true, .bubbles_moved = false, @@ -3486,7 +3486,7 @@ fn pseudoSectionMapIndex( try coff.nodes.ensureUnusedCapacity(gpa, 1); try coff.symbols.ensureUnusedCapacity(gpa, 1); - const ni = try parent.node(coff).addFloatingChild(&coff.mf, gpa, .{ .alignment = alignment }); + const ni = try parent.node(coff).addFloatingChild(gpa, &coff.mf, .{ .alignment = alignment }); const si = coff.addSymbolAssumeCapacity(); pseudo_section_gop.value_ptr.* = si; const sym = si.get(coff); @@ -3560,7 +3560,7 @@ fn objectSectionMapIndex( } } } - const ni = try parent_ni.addHeaderChildAfter(&coff.mf, gpa, prev_oni, .{ + const ni = try parent_ni.addHeaderChildAfter(gpa, &coff.mf, prev_oni, .{ .alignment = alignment, }); const si = coff.addSymbolAssumeCapacity(); @@ -3579,13 +3579,13 @@ fn objectSectionMapIndex( const parent_alignment = parent_ni.alignment(&coff.mf); if (alignment.compare(.gt, parent_alignment)) { log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); - try parent_ni.realign(&coff.mf, gpa, alignment); + try parent_ni.realign(gpa, &coff.mf, alignment); } const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf); if (alignment.compare(.gt, old_alignment)) { log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment }); - try sym.ni.unwrap().?.realign(&coff.mf, gpa, alignment); + try sym.ni.unwrap().?.realign(gpa, &coff.mf, alignment); } try coff.verifyParentSectionAttributes( @@ -3742,9 +3742,9 @@ fn addRelocAssumeCapacity( coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations); if (section.relocation_table_ni.unwrap()) |relocation_table_ni| { - try relocation_table_ni.resizeLeaf(&coff.mf, gpa, new_size); + try relocation_table_ni.resizeLeaf(gpa, &coff.mf, new_size); } else { - section.relocation_table_ni = .wrap(try coff.sectionParent().addFloatingChild(&coff.mf, gpa, .{ + section.relocation_table_ni = .wrap(try coff.sectionParent().addFloatingChild(gpa, &coff.mf, .{ .size = new_size, .alignment = .@"2", .moved = true, @@ -4094,7 +4094,7 @@ fn loadObject( { // TODO: This should be deferred to an idle task (but resize it here!) var nw: MappedFile.Node.Writer = undefined; - member.content_ni.writer(&coff.mf, gpa, &nw); + member.content_ni.writer(gpa, &coff.mf, &nw); defer nw.deinit(); try fr.seekTo(fl.offset); @@ -4653,7 +4653,7 @@ fn loadObject( if (section.parent_si == .null) continue; const alignment: Alignment = .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1); - const ni = try section.parent_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ + const ni = try section.parent_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .size = alignment.forward(section.header.size_of_raw_data), .alignment = alignment, .moved = true, @@ -5447,7 +5447,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const sec_si = try coff.navSection(zcu, nav.resolved.?); try coff.nodes.ensureUnusedCapacity(gpa, 1); if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); - const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ + const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .alignment = .fromIp(zcu.navAlignment(nav_index)), .moved = true, }); @@ -5469,7 +5469,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde { var nw: MappedFile.Node.Writer = undefined; - ni.writer(&coff.mf, gpa, &nw); + ni.writer(gpa, &coff.mf, &nw); defer nw.deinit(); codegen.generateSymbol( &coff.base, @@ -5486,7 +5486,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde } if (nav.resolved.?.@"linksection".unwrap()) |_| { - try ni.resizeLeaf(&coff.mf, gpa, si.get(coff).extra.size); + try ni.resizeLeaf(gpa, &coff.mf, si.get(coff).extra.size); } // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. @@ -5596,7 +5596,7 @@ fn updateFuncInner( if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const mod = zcu.navFileScope(func.owner_nav).mod.?; const target = &mod.resolved_target.result; - const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ + const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .debug, @@ -5625,7 +5625,7 @@ fn updateFuncInner( }; var nw: MappedFile.Node.Writer = undefined; - ni.writer(&coff.mf, gpa, &nw); + ni.writer(gpa, &coff.mf, &nw); defer nw.deinit(); codegen.emitFunction( &coff.base, @@ -5904,8 +5904,8 @@ pub fn flush( const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols); coff.symbol_table.ni.resizeLeaf( - &coff.mf, comp.gpa, + &coff.mf, number_of_symbols * std.coff.Symbol.sizeOf(), ) catch |err| switch (err) { else => |e| return e, @@ -6072,17 +6072,18 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { }; break :task; } - while (coff.mf.updates.pop()) |ni| { + while (coff.mf.updates.pop()) |ni| : (coff.mf.update_prog_node.completeOne()) { + if (ni.pendingDelete(&coff.mf)) continue; const clean_moved = ni.cleanMoved(&coff.mf); const clean_resized = ni.cleanResized(&coff.mf); - if (clean_moved or clean_resized) { - const sub_prog_node = - coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni)); - defer sub_prog_node.end(); - if (clean_moved) try coff.flushMoved(ni); - if (clean_resized) try coff.flushResized(ni); - break :task; - } else coff.mf.update_prog_node.completeOne(); + const clean_next_moved = ni.cleanNextMoved(&coff.mf); + if (!clean_moved and !clean_resized and !clean_next_moved) continue; + const sub_prog_node = + coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni)); + defer sub_prog_node.end(); + if (clean_moved) try coff.flushMoved(ni); + if (clean_resized) try coff.flushResized(ni); + break :task; } while (coff.pending_members.pop()) |pending_mi| { const sub_prog_node = coff.idleProgNode( @@ -6210,7 +6211,7 @@ fn genUav( try coff.nodes.ensureUnusedCapacity(gpa, 1); if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const sym = si.get(coff); - const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ + const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .alignment = .fromIp(uav_align), .moved = true, }); @@ -6239,7 +6240,7 @@ fn genUav( }; var nw: MappedFile.Node.Writer = undefined; - ni.writer(&coff.mf, gpa, &nw); + ni.writer(gpa, &coff.mf, &nw); defer nw.deinit(); codegen.generateSymbol( &coff.base, @@ -6503,19 +6504,19 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { if (!gop.found_existing) { errdefer _ = coff.import_table.entries.pop(); try coff.import_table.ni.resizeLeaf( - &coff.mf, gpa, + &coff.mf, @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), ); const import_hint_name_table_len = import_hint_name_align.forward(lib_name.len + ".dll".len + 1); const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?; - const import_lookup_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{ + const import_lookup_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{ .size = addr_info.size * 2, .alignment = addr_info.alignment, .moved = true, }); - const import_address_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{ + const import_address_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{ .size = addr_info.size * 2, .alignment = addr_info.alignment, .moved = true, @@ -6529,7 +6530,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { import_address_table_sym.section_number = coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number; } - const import_hint_name_table_ni = try idata_section_ni.addFloatingChild(&coff.mf, gpa, .{ + const import_hint_name_table_ni = try idata_section_ni.addFloatingChild(gpa, &coff.mf, .{ .size = import_hint_name_table_len, .alignment = import_hint_name_align, .moved = true, @@ -6585,9 +6586,9 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { gop.value_ptr.len = import_symbol_index + 1; const new_symbol_table_size = addr_info.size * (import_symbol_index + 2); - try gop.value_ptr.import_lookup_table_ni.resizeLeaf(&coff.mf, gpa, new_symbol_table_size); + try gop.value_ptr.import_lookup_table_ni.resizeLeaf(gpa, &coff.mf, new_symbol_table_size); const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); - try import_address_table_ni.resizeLeaf(&coff.mf, gpa, new_symbol_table_size); + try import_address_table_ni.resizeLeaf(gpa, &coff.mf, new_symbol_table_size); const opt_imp_name = import.name.toSlice(coff); const opt_import_hint_name_index = if (opt_imp_name) |imp_name| blk: { @@ -6595,7 +6596,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { gop.value_ptr.hint_name_len = @intCast( import_hint_name_align.forward(import_hint_name_index + 2 + imp_name.len + 1), ); - try gop.value_ptr.import_hint_name_table_ni.resizeLeaf(&coff.mf, gpa, gop.value_ptr.hint_name_len); + try gop.value_ptr.import_hint_name_table_ni.resizeLeaf(gpa, &coff.mf, gop.value_ptr.hint_name_len); break :blk import_hint_name_index; } else null; @@ -6670,7 +6671,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { else => |tag| @panic(@tagName(tag)), .AMD64 => { const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; - const ni = try parent_sym.ni.unwrap().?.addFloatingChild(&coff.mf, gpa, .{ + const ni = try parent_sym.ni.unwrap().?.addFloatingChild(gpa, &coff.mf, .{ .alignment = alignment, .size = alignment.forward(init.len), }); @@ -6823,7 +6824,7 @@ fn genLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { .code => .text, .const_data => .rdata, }; - const ni = try sec_si.node(coff).addFloatingChild(&coff.mf, gpa, .{ .moved = true }); + const ni = try sec_si.node(coff).addFloatingChild(gpa, &coff.mf, .{ .moved = true }); coff.nodes.appendAssumeCapacity(switch (lazy.kind) { .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) }, .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) }, @@ -6843,7 +6844,7 @@ fn genLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { var required_alignment: InternPool.Alignment = .none; var nw: MappedFile.Node.Writer = undefined; - ni.writer(&coff.mf, gpa, &nw); + ni.writer(gpa, &coff.mf, &nw); defer nw.deinit(); codegen.generateLazySymbol( &coff.base, @@ -7479,7 +7480,7 @@ fn updateExportInner( if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); - try coff.export_table.name_table_ni.resizeLeaf(&coff.mf, gpa, new_name_table_size); + try coff.export_table.name_table_ni.resizeLeaf(gpa, &coff.mf, new_name_table_size); const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); @@ -7503,20 +7504,20 @@ fn updateExportInner( // TODO: These should all be resized ahead of time to fit all exports // after https://github.com/ziglang/zig/issues/23616 try coff.export_table.export_address_table_si.node(coff).resizeLeaf( - &coff.mf, gpa, + &coff.mf, export_count * @sizeOf(std.coff.ExportAddressTableEntry), ); try coff.export_table.name_pointer_table_ni.resizeLeaf( - &coff.mf, gpa, + &coff.mf, export_count * @sizeOf(std.coff.ExportNamePointerTableEntry), ); try coff.export_table.ordinal_table_ni.resizeLeaf( - &coff.mf, gpa, + &coff.mf, export_count * @sizeOf(std.coff.ExportOrdinalTableEntry), ); diff --git a/src/link/Dwarf2.zig b/src/link/Dwarf2.zig index af41355ef552b3168c2e8d1c159f37d1120f1929..e51525bc3de9ae3913d2aca2e747edad6f088813 100644 --- a/src/link/Dwarf2.zig +++ b/src/link/Dwarf2.zig @@ -8,7 +8,7 @@ units: std.array_hash_map.Auto(*Module, Unit), /// Indices are `link.ConstPool.Index`. values: std.ArrayList(Value), globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global), -funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func), +funcs: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Func), debug_abbrev: Abbrev, frame: Frame, @@ -123,6 +123,7 @@ pub const Global = struct { }; pub const Func = struct { + owner_nav: InternPool.Nav.Index, fde_ni: MappedFile.Node.Index.Optional, debug_info_ni: MappedFile.Node.Index.Optional, debug_line_ni: MappedFile.Node.Index.Optional, @@ -130,7 +131,7 @@ pub const Func = struct { pub const Index = enum(u32) { _, - pub fn nav(fi: Func.Index, dwarf: *Dwarf) InternPool.Nav.Index { + pub fn srcInst(fi: Func.Index, dwarf: *Dwarf) InternPool.TrackedInst.Index { return dwarf.funcs.keys()[@backingInt(fi)]; } @@ -195,7 +196,7 @@ pub const Str = struct { ); if (!gop.found_existing) { gop.key_ptr.* = s.offset; - try ni.ensureMinimumSize(mf, gpa, s.offset + str.len + 1); + try ni.ensureMinimumSize(gpa, mf, s.offset + str.len + 1); const slice_mut = ni.slice(mf); @memcpy(slice_mut[s.offset..][0..str.len], str); s.offset += str.len; @@ -635,9 +636,15 @@ pub const WipNav = struct { const dwarf = debug.wip_nav.dwarf; const zcu = debug.pt.zcu; const ip = &zcu.intern_pool; - const nav = ip.getNav(zcu.funcInfo(debug.wip_nav.func).owner_nav); + const func = zcu.funcInfo(debug.wip_nav.func); + const inst_info = ip.getNav(func.owner_nav).srcInst(ip).resolveFull(ip).?; + const decl = zcu.fileByIndex(inst_info.file).zir.?.getDeclaration(inst_info.inst); + const nav = ip.getNav(func.owner_nav); const diw = &debug.info_writer.interface; try diw.writeUleb128(try dwarf.refAbbrevCode(.decl_func)); + try diw.writeInt(u32, decl.src_line + 1, dwarf.endian); + try diw.writeUleb128(decl.src_column + 1); + try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private); try debug.strp(nav.name.toSlice(ip)); try debug.strp(nav.fqn.toSlice(ip)); try dwarf.symbolAddress(&debug.info_writer, debug.wip_nav.func_si, 0); @@ -657,9 +664,8 @@ pub const WipNav = struct { const zcu = debug.pt.zcu; const ip = &zcu.intern_pool; const func = zcu.funcInfo(debug.wip_nav.func); - const zfi = zcu.navFileScopeIndex(func.owner_nav); - const zf = zcu.fileByIndex(zfi); const inst_info = ip.getNav(func.owner_nav).srcInst(ip).resolveFull(ip).?; + const zf = zcu.fileByIndex(inst_info.file); const decl = zf.zir.?.getDeclaration(inst_info.inst); const dlw = &debug.line_writer.interface; try dlw.writeByte(DW.LNS.extended_op); @@ -678,7 +684,7 @@ pub const WipNav = struct { try dwarf.symbolAddress(&debug.line_writer, debug.wip_nav.func_si, 0); const unit = dwarf.getUnit(zf.mod.?); - _, const fi = try unit.get(dwarf).getFile(zcu.gpa, unit, zfi); + _, const fi = try unit.get(dwarf).getFile(zcu.gpa, unit, inst_info.file); try dlw.writeByte(DW.LNS.set_file); try dlw.writeUleb128(@backingInt(fi)); @@ -928,7 +934,7 @@ pub const WipNav = struct { } fn leaveBlockInner(debug: *Debug, code_off: usize) link.EmitError!void { const dwarf = debug.wip_nav.dwarf; - const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block)); + const block_bytes = comptime uleb128Size(@backingInt(AbbrevCode.block)); const block = debug.blocks.pop().?; if (debug.any_children) try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null)) @@ -1000,7 +1006,7 @@ pub const WipNav = struct { code_off: usize, ) link.EmitError!void { const dwarf = debug.wip_nav.dwarf; - const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func)); + const inlined_func_bytes = comptime uleb128Size(@backingInt(AbbrevCode.inlined_func)); const block = debug.blocks.pop().?; const diw = &debug.info_writer.interface; if (debug.any_children) @@ -1029,14 +1035,14 @@ pub const WipNav = struct { } fn setInlineFuncInner(debug: *Debug, func: InternPool.Index) link.EmitError!void { const zcu = debug.pt.zcu; + const ip = &zcu.intern_pool; const dwarf = debug.wip_nav.dwarf; if (debug.wip_nav.func == func) return; - const new_func_info = zcu.funcInfo(func); - + const new_owner_nav = zcu.funcInfo(func).owner_nav; const dlw = &debug.line_writer.interface; if (zcu.comp.config.incremental) { - const new_func = try dwarf.getFunc(new_func_info.owner_nav); + const new_func = try dwarf.getFunc(new_owner_nav); try dlw.writeByte(DW.LNS.extended_op); try dlw.writeUleb128(1 + dwarf.sectionOffsetSize()); try dlw.writeByte(DW.LNE.ZIG_set_decl); @@ -1048,19 +1054,22 @@ pub const WipNav = struct { return; } - const old_func_info = zcu.funcInfo(debug.wip_nav.func); - const old_zfi = zcu.navFileScopeIndex(old_func_info.owner_nav); - const new_zfi = zcu.navFileScopeIndex(new_func_info.owner_nav); - if (old_zfi != new_zfi) { - const new_ui = dwarf.getUnit(zcu.fileByIndex(new_zfi).mod.?); - _, const new_fi = try debug.wip_nav.unit.get(dwarf).getFile(zcu.gpa, new_ui, new_zfi); + const old_owner_nav = zcu.funcInfo(debug.wip_nav.func).owner_nav; + const old_inst_info = ip.getNav(old_owner_nav).srcInst(ip).resolveFull(ip).?; + const old_file = zcu.fileByIndex(old_inst_info.file); + const new_inst_info = ip.getNav(new_owner_nav).srcInst(ip).resolveFull(ip).?; + const new_file = zcu.fileByIndex(new_inst_info.file); + if (old_inst_info.file != new_inst_info.file) { + const new_ui = dwarf.getUnit(new_file.mod.?); + _, const new_fi = + try debug.wip_nav.unit.get(dwarf).getFile(zcu.gpa, new_ui, new_inst_info.file); try dlw.writeByte(DW.LNS.set_file); try dlw.writeUleb128(@backingInt(new_fi)); } - const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); - const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); + const old_src_line: i33 = old_file.zir.?.getDeclaration(old_inst_info.inst).src_line; + const new_src_line: i33 = new_file.zir.?.getDeclaration(new_inst_info.inst).src_line; if (new_src_line != old_src_line) { try dlw.writeByte(DW.LNS.advance_line); try dlw.writeSleb128(new_src_line - old_src_line); @@ -1435,10 +1444,12 @@ pub fn deinit(dwarf: *Dwarf) void { } pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { - try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count()); + try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count() - dwarf.units.count()); for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, root| if (root.unwrap()) |root_zfi| { + if (!zcu.alive_files.contains(root_zfi)) continue; + assert(zcu.fileByIndex(root_zfi).mod != null); const unit_gop = dwarf.units.getOrPutAssumeCapacity(mod); - assert(!unit_gop.found_existing); + if (unit_gop.found_existing) continue; unit_gop.value_ptr.* = .{ .dirs = .empty, .files = .empty, @@ -1468,8 +1479,12 @@ pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index { pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.Index { const comp = dwarf.lf.comp; const gpa = comp.gpa; - const func_gop = try dwarf.funcs.getOrPut(gpa, owner_nav); + const zcu = comp.zcu.?; + const ip = &zcu.intern_pool; + const src_inst = ip.getNav(owner_nav).srcInst(ip); + const func_gop = try dwarf.funcs.getOrPut(gpa, src_inst); if (!func_gop.found_existing) func_gop.value_ptr.* = .{ + .owner_nav = owner_nav, .fde_ni = .none, .debug_info_ni = .none, .debug_line_ni = .none, @@ -1479,17 +1494,18 @@ pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.I const elf = dwarf.lf.cast(.elf2).?; try elf.nodes.ensureUnusedCapacity(gpa, 1); try elf.dwarf_funcs.ensureUnusedCapacity(gpa, 1); - const unit = dwarf.getUnit(comp.zcu.?.navFileScope(owner_nav).mod.?).get(dwarf); - func_gop.value_ptr.debug_info_ni = - .wrap(unit.debug_info_ni.unwrap().?.addFloatingChild(&elf.mf, gpa, .{ + const unit = dwarf.getUnit(zcu.fileByIndex(src_inst.resolveFile(ip)).mod.?).get(dwarf); + func_gop.value_ptr.debug_info_ni = .wrap(elf.addNodeAssumeCapacity( + unit.debug_info_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{ .enable_next_moved = true, }) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{ elf.mf.io_err.?, }), - }); - elf.nodes.appendAssumeCapacity(.{ .func_debug_info = fi }); + }, + .{ .func_debug_info = fi }, + )); elf.dwarf_funcs.addOneAssumeCapacity().* = .{ .frame_fde_first_symbol_reloc = .none, .frame_fde_first_node_reloc = .none, @@ -1503,7 +1519,9 @@ pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) link.Error!Func.I return fi; } pub fn getFuncIfExists(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) ?Func.Index { - return @fromBackingInt(@intCast(dwarf.funcs.getIndex(owner_nav) orelse return null)); + const ip = &dwarf.lf.comp.zcu.?.intern_pool; + return @fromBackingInt(@intCast(dwarf.funcs.getIndex(ip.getNav(owner_nav).srcInst(ip)) orelse + return null)); } pub fn unitLengthSize(dwarf: *Dwarf) usize { @@ -1797,20 +1815,20 @@ pub fn genDebugLineHeader( try dlhw.writeUleb128(DW.FORM.line_strp); try dlhw.writeUleb128(unit.files.count()); for (unit.files.keys()) |zfi| { - const zcu_file = zcu.fileByIndex(zfi); - try dwarf.strp(&dwarf.debug_line_str, dlh_nw, zcu_file.sub_file_path); + const zf = zcu.fileByIndex(zfi); + try dwarf.strp(&dwarf.debug_line_str, dlh_nw, zf.sub_file_path); switch (directory_index_form) { else => unreachable, .data1 => try dlhw.writeByte(0), .data2 => try dlhw.writeInt(u16, 0, dwarf.endian), .udata => try dlhw.writeUleb128(0), } - try dlhw.writeInt(i64, @truncate(zcu_file.stat.mtime.nanoseconds), dwarf.endian); - try dlhw.writeInt(u64, zcu_file.stat.size, dwarf.endian); + try dlhw.writeInt(i64, @truncate(zf.stat.mtime.nanoseconds), dwarf.endian); + try dlhw.writeInt(u64, zf.stat.size, dwarf.endian); try dwarf.strp( &dwarf.debug_line_str, dlh_nw, - if (zcu_file.is_builtin) zcu_file.source.? else "", + if (zf.is_builtin) zf.source.? else "", ); } switch (dwarf.format) { @@ -1892,6 +1910,18 @@ pub fn genDebugRnglists( try drw.writeByte(DW.RLE.end_of_list); } +pub fn updateLineNumber( + dwarf: *Dwarf, + zcu: *Zcu, + src_inst: InternPool.TrackedInst.Index, + debug_info: []u8, +) void { + const inst_info = src_inst.resolveFull(&zcu.intern_pool).?; + assert(inst_info.inst != .main_struct_inst); + const src_line = zcu.fileByIndex(inst_info.file).zir.?.getDeclaration(inst_info.inst).src_line; + std.mem.writeInt(u32, debug_info[AbbrevCode.decl_bytes..][0..4], src_line + 1, dwarf.endian); +} + fn refAbbrevCodeIfExists( dwarf: *Dwarf, abbrev_code: AbbrevCode, @@ -1911,7 +1941,7 @@ fn refAbbrevCode( const elf = dwarf.lf.cast(.elf2).?; const comp = elf.base.comp; var nw: MappedFile.Node.Writer = undefined; - dwarf.debug_abbrev.ni.unwrap().?.writer(&elf.mf, comp.gpa, &nw); + dwarf.debug_abbrev.ni.unwrap().?.writer(comp.gpa, &elf.mf, &nw); defer nw.deinit(); const abbrev = AbbrevCode.abbrevs.get(abbrev_code); const daw = &nw.interface; @@ -2133,11 +2163,11 @@ pub const AbbrevCode = enum { comptime_value_elem_runtime_bits, comptime_value_elem_comptime_state, - const decl_bytes = uleb128Bytes(@backingInt(AbbrevCode.decl_instance_extern_func)); + const decl_bytes = uleb128Size(@backingInt(AbbrevCode.decl_instance_extern_func)); comptime { - assert(uleb128Bytes(@backingInt(AbbrevCode.pad_1)) == 1); - assert(uleb128Bytes(@backingInt(AbbrevCode.pad_n)) == 1); - assert(uleb128Bytes(@backingInt(AbbrevCode.decl_alias)) == decl_bytes); + assert(uleb128Size(@backingInt(AbbrevCode.pad_1)) == 1); + assert(uleb128Size(@backingInt(AbbrevCode.pad_n)) == 1); + assert(uleb128Size(@backingInt(AbbrevCode.decl_alias)) == decl_bytes); } const Attr = struct { @@ -2145,7 +2175,7 @@ pub const AbbrevCode = enum { DeclValEnum(DW.FORM), }; const decl_abbrev_common_attrs = &[_]Attr{ - .{ .ZIG_parent, .ref_addr }, + //.{ .ZIG_parent, .ref_addr }, .{ .decl_line, .data4 }, .{ .decl_column, .udata }, .{ .accessibility, .data1 }, @@ -2292,7 +2322,7 @@ pub const AbbrevCode = enum { .decl_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_abbrev_common_attrs[4..] ++ .{ + .attrs = decl_abbrev_common_attrs ++ .{ .{ .linkage_name, .strp }, //.{ .type, .ref_addr }, .{ .low_pc, .addr }, @@ -3197,14 +3227,14 @@ pub const AbbrevCode = enum { }); }; -pub fn uleb128Bytes(value: anytype) u32 { +pub fn uleb128Size(value: anytype) u32 { var buf: [64]u8 = undefined; var dw: Writer.Discarding = .init(&buf); dw.writer.writeUleb128(value) catch unreachable; return @intCast(dw.fullCount()); } -pub fn sleb128Bytes(value: anytype) u32 { +pub fn sleb128Size(value: anytype) u32 { var buf: [64]u8 = undefined; var dw: Writer.Discarding = .init(&buf); dw.writer.writeSleb128(value) catch unreachable; diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 184f9aac4358180ad37e12faeb75d05880cb154c..4d17c1c6af9d51e8cb8ae51c4cc2dba19f8d96c6 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -253,6 +253,8 @@ input_prog_node: std.Progress.Node, const Error = link.Error || error{MappedFileIo}; const Node = union(enum) { + deleted, + /// Only used when emitting a static library. /// /// Contains a header node which is an `.archive_header`. @@ -642,7 +644,7 @@ const Section = struct { } const ni = shndx.get(elf).ni; if (min_align.compare(.gt, ni.alignment(&elf.mf))) { - try ni.realign(&elf.mf, elf.base.comp.gpa, min_align); + try ni.realign(elf.base.comp.gpa, &elf.mf, min_align); } switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { .elf => {}, @@ -675,7 +677,7 @@ const Section = struct { break :need_size cur_size + need_additional * ent_size; }, }; - try node.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, need_size); + try node.ensureMinimumSize(elf.base.comp.gpa, &elf.mf, need_size); } /// Asserts that `rela_shndx` is a `SHT_RELA` section and deletes the `ElfN.Rela` entry at @@ -2094,7 +2096,7 @@ fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) { inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), }; - try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size); + try Section.Index.symtab.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_node_size); } switch (kind) { @@ -2117,7 +2119,7 @@ fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size)); const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size; - try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size); + try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, dynsym_need_size); try elf.ensureDynsymHashCapacity(dynsym_cur_len + len); @@ -2150,7 +2152,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { // We don't need to add any buckets, but we still need to make sure the section is large // enough to fit `max_dynsym_count` chains. const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4; - try elf.shndx.hash.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size); + try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); return; } // We need more buckets, so we'll have to rebuild the hash table. @@ -2162,7 +2164,7 @@ fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { { const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4; - try elf.shndx.hash.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size); + try elf.shndx.hash.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); } elf.mf.nodes_lock.lock(); @@ -2306,19 +2308,19 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { // Ensure the `.plt` section's node is big enough: { const need_size: usize = plt.entry_size * (1 + need_plt_count); - try elf.shndx.plt.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size); + try elf.shndx.plt.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); } // If there is a `.got.plt` section, ensure its node is big enough if (plt.got_plt) |got_plt| { const need_size: usize = elf.targetPtrSize() * (got_plt.header_entries + need_plt_count); - try elf.shndx.got_plt.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size); + try elf.shndx.got_plt.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); } // If there is a `.plt.sec` section, ensure its node is big enough if (plt.plt_sec) |plt_sec| { const need_size: usize = plt_sec.entry_size * need_plt_count; - try elf.shndx.plt_sec.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_size); + try elf.shndx.plt_sec.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_size); } } /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at @@ -3244,6 +3246,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { + .deleted, .archive, .archive_header, .archive_input_member, @@ -3305,7 +3308,13 @@ fn lazySymbolInner(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol) Err .code => .{ .text, .FUNC }, .const_data => .{ .rodata, .OBJECT }, }; - const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{}); + const node = elf.addNodeAssumeCapacity( + try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), + switch (lazy.kind) { + .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) }, + .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) }, + }, + ); var name_buf: [std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})]u8 = undefined; const name = std.mem.print(&name_buf, "__lazy_{t}_{d}", .{ lazy.kind, gop.index }) catch unreachable; @@ -3321,10 +3330,6 @@ fn lazySymbolInner(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol) Err .first_symbol_reloc = .none, .first_got_reloc = .none, }; - elf.nodes.appendAssumeCapacity(switch (lazy.kind) { - .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) }, - .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) }, - }); elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1); } const s: Symbol.Id = .local(gop.value_ptr.lsi); @@ -3583,7 +3588,7 @@ const StringTable = struct { break :size .{ old_size, new_size }; }, }; - try ni.ensureMinimumSize(&elf.mf, gpa, new_size); + try ni.ensureMinimumSize(gpa, &elf.mf, new_size); const slice = ni.slice(&elf.mf)[old_size..]; @memcpy(slice[0..key.len], key); slice[key.len] = 0; @@ -4014,21 +4019,21 @@ fn initHeaders( try elf.symtab.ensureTotalCapacity(gpa, 1); if (is_archive) { - elf.nodes.appendAssumeCapacity(.archive); + const archive_ni = elf.addNodeAssumeCapacity(.root, .archive); - const archive_ni: MappedFile.Node.Index = .root; - - const archive_header_ni = try archive_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ - // We intentionally do not set `.alignment = .@"2"` here, because the string table data - // in this node does not need to have an aligned length. (This node's offset is aligned - // regardless by virtue of it being a header.) - .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), - // The archive header uses 'next_moved' events to resize the "//" member, so that it - // absorbs all padding between `archive_header_ni` and the actual object file members. - .enable_next_moved = true, - .next_moved = true, - }); - elf.nodes.appendAssumeCapacity(.archive_header); + const archive_header_ni = elf.addNodeAssumeCapacity( + try archive_ni.addOnlyHeaderChild(gpa, &elf.mf, .{ + // We intentionally do not set `.alignment = .@"2"` here, because the string table data + // in this node does not need to have an aligned length. (This node's offset is aligned + // regardless by virtue of it being a header.) + .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), + // The archive header uses 'next_moved' events to resize the "//" member, so that it + // absorbs all padding between `archive_header_ni` and the actual object file members. + .enable_next_moved = true, + .next_moved = true, + }), + .archive_header, + ); const archive_header_slice = archive_header_ni.slice(&elf.mf); @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG); const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]); @@ -4042,18 +4047,19 @@ fn initHeaders( .ar_fmag = std.elf.ARFMAG.*, }; - elf.ni.elf = try archive_ni.addOnlyFooterChild(&elf.mf, gpa, .{ + elf.ni.elf = elf.addNodeAssumeCapacity(try archive_ni.addOnlyFooterChild(gpa, &elf.mf, .{ .alignment = node_block_align.max(.@"2"), .bubbles_moved = false, .resized = true, // ensure that this node's `ar_hdr.ar_size` is updated at least once - }); - elf.nodes.appendAssumeCapacity(.elf); + }), .elf); - const elf_ar_hdr_ni = try archive_ni.addFooterChildBefore(&elf.mf, gpa, .wrap(elf.ni.elf), .{ - .alignment = .@"2", - .size = @sizeOf(std.elf.ar_hdr), - }); - elf.nodes.appendAssumeCapacity(.archive_elf_member_header); + const elf_ar_hdr_ni = elf.addNodeAssumeCapacity( + try archive_ni.addFooterChildBefore(gpa, &elf.mf, .wrap(elf.ni.elf), .{ + .alignment = .@"2", + .size = @sizeOf(std.elf.ar_hdr), + }), + .archive_elf_member_header, + ); // Must be populated before we call `populateArchiveMemberName` below. elf.archive = .{ @@ -4079,10 +4085,7 @@ fn initHeaders( defer gpa.free(zcu_member_name); // After this call returns, `elf_ar_hdr` is invalidated. try elf.populateArchiveMemberName(elf_ar_hdr, zcu_member_name); - } else { - elf.ni.elf = .root; - elf.nodes.appendAssumeCapacity(.elf); - } + } else elf.ni.elf = elf.addNodeAssumeCapacity(.root, .elf); const entsize: struct { ph: u32, sh: u32 } = switch (class) { .NONE, _ => unreachable, @@ -4098,69 +4101,65 @@ fn initHeaders( if (@"type" != .REL) { // This node will contain the ehdr, which must be at the start of the ELF file, so this // node must itself be a header of the `.elf` node. - elf.ni.rodata = try elf.ni.elf.addOnlyHeaderChild(&elf.mf, gpa, .{ + elf.ni.rodata = elf.addNodeAssumeCapacity(try elf.ni.elf.addOnlyHeaderChild(gpa, &elf.mf, .{ // Must be at least `addr_align` for `elf.ni.phdr` to be placed inside this node .alignment = node_block_align.max(addr_align), .moved = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata }); + }), .{ .segment = phndx.rodata }); elf.phdrs.items[phndx.rodata] = .wrap(elf.ni.rodata); - elf.ni.phdr = try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{ + elf.ni.phdr = elf.addNodeAssumeCapacity(try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{ .size = @as(u64, phnum) * entsize.ph, .alignment = addr_align, // keep in sync with `elf.ni.rodata` alignment above .moved = true, .resized = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr }); + }), .{ .segment = phndx.phdr }); elf.phdrs.items[phndx.phdr] = .wrap(elf.ni.phdr); - elf.ni.text = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{ + elf.ni.text = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{ .alignment = node_block_align, .moved = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text }); + }), .{ .segment = phndx.text }); elf.phdrs.items[phndx.text] = .wrap(elf.ni.text); - elf.ni.data = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{ + elf.ni.data = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{ // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node .alignment = node_block_align.max(addr_align), .moved = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data }); + }), .{ .segment = phndx.data }); elf.phdrs.items[phndx.data] = .wrap(elf.ni.data); - if (plt.got_plt == null) { - const plt_ni = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{ + if (plt.got_plt == null) elf.phdrs.items[phndx.plt] = .wrap(elf.addNodeAssumeCapacity( + try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{ .alignment = node_block_align, .moved = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt }); - elf.phdrs.items[phndx.plt] = .wrap(plt_ni); - } + }), + .{ .segment = phndx.plt }, + )); - elf.ni.data_rel_ro = try elf.ni.data.addFloatingChild(&elf.mf, gpa, .{ + elf.ni.data_rel_ro = elf.addNodeAssumeCapacity(try elf.ni.data.addFloatingChild(gpa, &elf.mf, .{ // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above. .alignment = node_block_align.max(addr_align), .moved = true, .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro }); + }), .{ .segment = phndx.relro }); elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro); if (comp.config.any_non_single_threaded) { - elf.ni.tls = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{ - .alignment = node_block_align, - .moved = true, - .bubbles_moved = false, - })); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls }); + elf.ni.tls = .wrap(elf.addNodeAssumeCapacity( + try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{ + .alignment = node_block_align, + .moved = true, + .bubbles_moved = false, + }), + .{ .segment = phndx.tls }, + )); elf.phdrs.items[phndx.tls] = elf.ni.tls; } @@ -4184,11 +4183,10 @@ fn initHeaders( .REL => elf.ni.elf, .DYN, .EXEC => elf.ni.rodata, }; - elf.ni.ehdr = try parent_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ + elf.ni.ehdr = elf.addNodeAssumeCapacity(try parent_ni.addOnlyHeaderChild(gpa, &elf.mf, .{ .size = @sizeOf(ElfN.Ehdr), .alignment = addr_align, - }); - elf.nodes.appendAssumeCapacity(.ehdr); + }), .ehdr); const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); ehdr.ident = .{ @@ -4238,13 +4236,12 @@ fn initHeaders( }, } - elf.ni.shdr = try elf.ni.elf.addFloatingChild(&elf.mf, gpa, .{ + elf.ni.shdr = elf.addNodeAssumeCapacity(try elf.ni.elf.addFloatingChild(gpa, &elf.mf, .{ .size = node_block_align.forward(1 * entsize.sh), // as above, only the SHN_UNDEF initially .alignment = addr_align.max(node_block_align), .moved = true, .resized = true, - }); - elf.nodes.appendAssumeCapacity(.shdr); + }), .shdr); switch (class) { .NONE, _ => unreachable, @@ -4298,18 +4295,16 @@ fn initHeaders( .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()), }; - if (maybe_interp) |_| { - phdr[phndx.interp] = .{ - .type = .INTERP, - .offset = 0, - .vaddr = 0, - .paddr = 0, - .filesz = 0, - .memsz = 0, - .flags = .{ .R = true }, - .@"align" = 1, - }; - } + if (maybe_interp) |_| phdr[phndx.interp] = .{ + .type = .INTERP, + .offset = 0, + .vaddr = 0, + .paddr = 0, + .filesz = 0, + .memsz = 0, + .flags = .{ .R = true }, + .@"align" = 1, + }; phdr[phndx.rodata] = .{ .type = .NULL, @@ -4567,13 +4562,15 @@ fn initHeaders( .node_align = node_block_align, }); if (maybe_interp) |interp| { - const interp_ni = try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{ - .size = interp.len + 1, - .moved = true, - .resized = true, - .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp }); + const interp_ni = elf.addNodeAssumeCapacity( + try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{ + .size = interp.len + 1, + .moved = true, + .resized = true, + .bubbles_moved = false, + }), + .{ .segment = phndx.interp }, + ); elf.phdrs.items[phndx.interp] = .wrap(interp_ni); const sec_interp_shndx = try elf.addSection(interp_ni, .{ @@ -4588,12 +4585,14 @@ fn initHeaders( } if (have_dynamic) { assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align)); - const dynamic_ni = try elf.ni.data_rel_ro.addFloatingChild(&elf.mf, gpa, .{ - .alignment = addr_align, - .moved = true, - .bubbles_moved = false, - }); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic }); + const dynamic_ni = elf.addNodeAssumeCapacity( + try elf.ni.data_rel_ro.addFloatingChild(gpa, &elf.mf, .{ + .alignment = addr_align, + .moved = true, + .bubbles_moved = false, + }), + .{ .segment = phndx.dynamic }, + ); elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni); const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{ @@ -4778,13 +4777,15 @@ fn initHeaders( } } if (have_eh_frame) { - elf.ni.gnu_eh_frame = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{ - .size = @sizeOf(Dwarf.EhFrameHdr), - .alignment = .@"4", - .moved = true, - .bubbles_moved = false, - })); - elf.nodes.appendAssumeCapacity(.{ .segment = phndx.gnu_eh_frame }); + elf.ni.gnu_eh_frame = .wrap(elf.addNodeAssumeCapacity( + try elf.ni.rodata.addFloatingChild(gpa, &elf.mf, .{ + .size = @sizeOf(Dwarf.EhFrameHdr), + .alignment = .@"4", + .moved = true, + .bubbles_moved = false, + }), + .{ .segment = phndx.gnu_eh_frame }, + )); elf.phdrs.items[phndx.gnu_eh_frame] = elf.ni.gnu_eh_frame; elf.shndx.eh_frame_hdr = try elf.addSection(elf.ni.gnu_eh_frame.unwrap().?, .{ @@ -5106,6 +5107,7 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { /// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data. fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { return switch (elf.getNode(ni)) { + .deleted, .archive, .archive_header, .archive_input_member, @@ -5142,6 +5144,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { } fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { return switch (elf.getNode(ni)) { + .deleted, .archive, .archive_header, .archive_input_member, @@ -5179,7 +5182,12 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { const parent_ni = ni.parent(&elf.mf).unwrap().?; const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) { - .archive, .archive_header, .archive_input_member, .archive_elf_member_header => unreachable, + .deleted, + .archive, + .archive_header, + .archive_input_member, + .archive_elf_member_header, + => unreachable, .elf => return 0, .ehdr, .shdr => unreachable, .segment => |phndx| switch (elf.phdrSlice()) { @@ -5229,6 +5237,7 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { skip_node_relocs: MappedFile.Node.Index.Optional = .none, first_got_reloc: ?*GotReloc.Index = null, } = switch (elf.getNode(ni)) { + .deleted, .archive, .archive_header, .archive_input_member, @@ -5284,8 +5293,8 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { }, .func_debug_info => |fi| .{ .first_symbol_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_symbol_reloc, - .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav| - nav.lsi.index().ptr(elf).node + .skip_symbol_relocs = if (elf.navs.getPtr(fi.get(&elf.dwarf).owner_nav)) |owner_nav| + owner_nav.lsi.index().ptr(elf).node else .none, .first_node_reloc = &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_node_reloc, @@ -5875,9 +5884,9 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node }, }; try shndx.ensureAligned(elf, alignment); - const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ .alignment = alignment, - }); + }), .{ .nav = nmi }); nav_gop.value_ptr.* = .{ .lsi = elf.addLocalSymbolAssumeCapacity(.{ .node = .wrap(node), @@ -5890,7 +5899,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node .first_symbol_reloc = .none, .first_got_reloc = .none, }; - elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); } return nmi; } @@ -5919,10 +5927,10 @@ fn uavMapIndex( if (!uav_gop.found_existing) { const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs try shndx.ensureAligned(elf, resolved_align); - const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + const node = elf.addNodeAssumeCapacity(try shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ .moved = true, // see assert at end of `genUav` .alignment = resolved_align, - }); + }), .{ .uav = umi }); var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined; const name = std.mem.print(&name_buf, "__anon_{d}", .{umi}) catch unreachable; uav_gop.value_ptr.* = .{ @@ -5936,7 +5944,6 @@ fn uavMapIndex( }), .first_symbol_reloc = .none, }; - elf.nodes.appendAssumeCapacity(.{ .uav = umi }); elf.const_prog_node.increaseEstimatedTotalItems(1); elf.pending_uavs.appendAssumeCapacity(umi); } else { @@ -5944,7 +5951,7 @@ fn uavMapIndex( const shndx = elf.getNode(node.parent(&elf.mf).unwrap().?).section; try shndx.ensureAligned(elf, resolved_align); if (resolved_align.order(node.alignment(&elf.mf)).compare(.gt)) { - try node.realign(&elf.mf, gpa, resolved_align); + try node.realign(gpa, &elf.mf, resolved_align); } } return umi; @@ -6173,11 +6180,13 @@ fn loadObject( }; try elf.nodes.ensureUnusedCapacity(gpa, 1); - const new_member_ni = try archive.ni.addFooterChildBefore(&elf.mf, gpa, first_member_oni, .{ - .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size), - .alignment = .@"2", - }); - elf.nodes.appendAssumeCapacity(.{ .archive_input_member = input_index }); + const new_member_ni = elf.addNodeAssumeCapacity( + try archive.ni.addFooterChildBefore(gpa, &elf.mf, first_member_oni, .{ + .size = Alignment.@"2".forward(@sizeOf(std.elf.ar_hdr) + fl.size), + .alignment = .@"2", + }), + .{ .archive_input_member = input_index }, + ); input.extra = .{ .node = new_member_ni }; elf.input_prog_node.increaseEstimatedTotalItems(1); @@ -6391,22 +6400,20 @@ fn loadObject( .alignment = need_align, .moved = true, // see assert at end of `flushInputSection` }; - const ni = if (opts.node_fixed) ni: { - const shndx_ni = opts.shndx.get(elf).ni; - const after_oni: MappedFile.Node.Index.Optional = after: { - const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none; - break :after switch (last_ni.position(&elf.mf)) { - .header => .wrap(last_ni), - .footer, .floating => .none, + const ni = elf.addNodeAssumeCapacity( + if (opts.node_fixed) ni: { + const shndx_ni = opts.shndx.get(elf).ni; + const after_oni: MappedFile.Node.Index.Optional = after: { + const last_ni = shndx_ni.last(&elf.mf).unwrap() orelse break :after .none; + break :after switch (last_ni.position(&elf.mf)) { + .header => .wrap(last_ni), + .footer, .floating => .none, + }; }; - }; - break :ni try shndx_ni.addHeaderChildAfter(&elf.mf, gpa, after_oni, add_node_opts); - } else ni: { - break :ni try opts.shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, add_node_opts); - }; - elf.nodes.appendAssumeCapacity(.{ - .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)), - }); + break :ni try shndx_ni.addHeaderChildAfter(gpa, &elf.mf, after_oni, add_node_opts); + } else try opts.shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, add_node_opts), + .{ .input_section = @fromBackingInt(@intCast(elf.input_sections.items.len)) }, + ); section.isi = @fromBackingInt(@intCast(elf.input_sections.items.len)); elf.input_sections.addOneAssumeCapacity().* = .{ .input = input_index, @@ -6659,7 +6666,7 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n // We set the size of the archive header node exactly, because we want padding bytes to go into // the root `.archive` node. That way, those bytes could still be used to grow the string table // if necessary, but they could also be used for new archive members. - try archive_header_ni.resizeLeaf(&elf.mf, gpa, old_archive_header_size + member_name.len + 2); + try archive_header_ni.resizeLeaf(gpa, &elf.mf, old_archive_header_size + member_name.len + 2); const dest_slice = archive_header_ni.slice(&elf.mf)[@intCast(old_archive_header_size)..]; @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name); @@ -6811,8 +6818,12 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars // We have a copy relocation for this global, but the amount of space we // reserved for it could be too small or underaligned! try Section.Index.data.ensureAligned(elf, gop.value_ptr.alignment); - try copied_global.node.resizeLeaf(&elf.mf, gpa, gop.value_ptr.alignment.forward(gop.value_ptr.size)); - try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment); + try copied_global.node.resizeLeaf( + gpa, + &elf.mf, + gop.value_ptr.alignment.forward(gop.value_ptr.size), + ); + try copied_global.node.realign(gpa, &elf.mf, gop.value_ptr.alignment); const global_ptr = elf.globalByName(name).?; switch (elf.symPtr(global_ptr.symtab_index)) { inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), @@ -7034,49 +7045,25 @@ fn prelinkInner(elf: *Elf) Error!void { .extra = .{ .file_symbol = zcu_file_symbol }, }; elf.input_pending_index += 1; - } -} -pub fn zcuFilesReady(elf: *Elf, zcu: *Zcu) link.Error!void { - elf.zcuFilesReadyInner(zcu) catch |err| switch (err) { - else => |e| return e, - error.MappedFileIo => return elf.base.comp.link_diags.fail( - "failed to write output file: {t}", - .{elf.mf.io_err.?}, - ), - }; -} -fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { - const gpa = zcu.gpa; + try elf.nodes.ensureUnusedCapacity(gpa, 4 + 5); - if (elf.dwarf.units.count() == 0) { - try elf.dwarf.initUnits(zcu); - try elf.nodes.ensureUnusedCapacity(gpa, 4 + 5 + 5 * elf.dwarf.units.count()); - try elf.dwarf_units.appendNTimes(gpa, .{ - .frame_cie_first_target_reloc = .none, - .debug_info_header_first_target_reloc = .none, - .debug_info_header_first_node_reloc = .none, - .debug_line_header_first_target_reloc = .none, - .debug_line_header_first_node_reloc = .none, - .debug_rnglists_first_target_reloc = .none, - .debug_rnglists_symbol_relocs = .empty, - }, elf.dwarf.units.count()); - - elf.dwarf.debug_abbrev.ni = - .wrap(try elf.shndx.debug_abbrev.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); - elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_abbrev }); - - elf.dwarf.debug_line_str.ni = - .wrap(try elf.shndx.debug_line_str.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); - elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_line_str }); - - elf.dwarf.debug_str.ni = - .wrap(try elf.shndx.debug_str.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); - elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_str }); - - elf.dwarf.debug_str_offsets.ni = - .wrap(try elf.shndx.debug_str_offsets.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); - elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_str_offsets }); + elf.dwarf.debug_abbrev.ni = .wrap(elf.addNodeAssumeCapacity( + try elf.shndx.debug_abbrev.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), + .{ .debug_shared = .debug_abbrev }, + )); + elf.dwarf.debug_line_str.ni = .wrap(elf.addNodeAssumeCapacity( + try elf.shndx.debug_line_str.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), + .{ .debug_shared = .debug_line_str }, + )); + elf.dwarf.debug_str.ni = .wrap(elf.addNodeAssumeCapacity( + try elf.shndx.debug_str.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), + .{ .debug_shared = .debug_str }, + )); + elf.dwarf.debug_str_offsets.ni = .wrap(elf.addNodeAssumeCapacity( + try elf.shndx.debug_str_offsets.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{}), + .{ .debug_shared = .debug_str_offsets }, + )); for ([5]Section.Index{ elf.shndx.eh_frame, @@ -7089,18 +7076,20 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { const debug_ni = debug_shndx.get(elf).ni; _ = debug_ni.last(&elf.mf).unwrap() orelse continue; const frame_format = debug_shndx.debugFrameFormat(elf); - const unit_padding_ni = try debug_ni.addFloatingChild(&elf.mf, gpa, .{ - .alignment = if (frame_format) |_| switch (elf.identClass()) { - .NONE, _ => unreachable, - .@"32" => .@"4", - .@"64" => .@"8", - } else .@"1", - .next_moved = true, - .enable_next_moved = true, - }); - elf.nodes.appendAssumeCapacity(.unit_padding); + const unit_padding_ni = elf.addNodeAssumeCapacity( + try debug_ni.addFloatingChild(gpa, &elf.mf, .{ + .alignment = if (frame_format) |_| switch (elf.identClass()) { + .NONE, _ => unreachable, + .@"32" => .@"4", + .@"64" => .@"8", + } else .@"1", + .next_moved = true, + .enable_next_moved = true, + }), + .unit_padding, + ); var debug_nw: MappedFile.Node.Writer = undefined; - unit_padding_ni.writer(&elf.mf, gpa, &debug_nw); + unit_padding_ni.writer(gpa, &elf.mf, &debug_nw); defer debug_nw.deinit(); (if (frame_format) |format| elf.dwarf.genDebugFrameCie(&debug_nw.interface, null, format) @@ -7109,88 +7098,121 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { error.WriteFailed => return debug_nw.err.?, }; } + } +} - for (0.., elf.dwarf.units.values()) |unit_index, *unit| { - const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index)); - switch (elf.shndx.debug_info) { - .UNDEF => {}, - else => |debug_info_shndx| { - const debug_info_ni = - try debug_info_shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ - .alignment = elf.mf.flags.block_size, - .enable_next_moved = true, - }); - unit.debug_info_ni = .wrap(debug_info_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_debug_info = ui }); +pub fn zcuFilesReady(elf: *Elf, zcu: *Zcu) link.Error!void { + elf.zcuFilesReadyInner(zcu) catch |err| switch (err) { + else => |e| return e, + error.MappedFileIo => return elf.base.comp.link_diags.fail( + "failed to write output file: {t}", + .{elf.mf.io_err.?}, + ), + }; +} +fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { + const gpa = zcu.gpa; - unit.debug_info_header_ni = - .wrap(try debug_info_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ - .next_moved = true, - .enable_next_moved = true, - })); - elf.nodes.appendAssumeCapacity(.{ .unit_debug_info_header = ui }); - }, - } - switch (elf.shndx.debug_line) { - .UNDEF => {}, - else => |debug_line_shndx| { - const debug_line_ni = - try debug_line_shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ - .alignment = elf.mf.flags.block_size, - .enable_next_moved = true, - }); - unit.debug_line_ni = .wrap(debug_line_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_debug_line = ui }); + try elf.dwarf.initUnits(zcu); + const old_units_len = elf.dwarf_units.items.len; + const new_units_len = elf.dwarf.units.count(); + try elf.dwarf_units.appendNTimes(gpa, .{ + .frame_cie_first_target_reloc = .none, + .debug_info_header_first_target_reloc = .none, + .debug_info_header_first_node_reloc = .none, + .debug_line_header_first_target_reloc = .none, + .debug_line_header_first_node_reloc = .none, + .debug_rnglists_first_target_reloc = .none, + .debug_rnglists_symbol_relocs = .empty, + }, new_units_len - old_units_len); + try elf.nodes.ensureUnusedCapacity(gpa, 5 * (new_units_len - old_units_len)); - unit.debug_line_header_ni = - .wrap(try debug_line_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ - // Idle tasks are going to try to keep this up to date before we are able to - // write out the full header, so just reserve space for them to do so. - .size = elf.dwarf.unitLengthSize(), - .enable_next_moved = true, - })); - elf.nodes.appendAssumeCapacity(.{ .unit_debug_line_header = ui }); - }, - } - switch (elf.shndx.debug_rnglists) { - .UNDEF => {}, - else => |debug_rnglists_shndx| { - unit.debug_rnglists_ni = - .wrap(try debug_rnglists_shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ - .next_moved = true, - .enable_next_moved = true, - })); - elf.nodes.appendAssumeCapacity(.{ .unit_debug_rnglists = ui }); - }, - } + for (old_units_len.., elf.dwarf.units.values()[old_units_len..]) |unit_index, *unit| { + const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index)); + switch (elf.shndx.debug_info) { + .UNDEF => {}, + else => |debug_info_shndx| { + const debug_info_ni = elf.addNodeAssumeCapacity( + try debug_info_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ + .alignment = elf.mf.flags.block_size, + .enable_next_moved = true, + }), + .{ .unit_debug_info = ui }, + ); + unit.debug_info_ni = .wrap(debug_info_ni); + + unit.debug_info_header_ni = .wrap(elf.addNodeAssumeCapacity( + try debug_info_ni.addOnlyHeaderChild(gpa, &elf.mf, .{ + .next_moved = true, + .enable_next_moved = true, + }), + .{ .unit_debug_info_header = ui }, + )); + }, } + switch (elf.shndx.debug_line) { + .UNDEF => {}, + else => |debug_line_shndx| { + const debug_line_ni = elf.addNodeAssumeCapacity( + try debug_line_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ + .alignment = elf.mf.flags.block_size, + .enable_next_moved = true, + }), + .{ .unit_debug_line = ui }, + ); + unit.debug_line_ni = .wrap(debug_line_ni); - for (elf.dwarf.units.keys(), elf.dwarf.units.values()) |mod, *unit| { - var drh_nw: MappedFile.Node.Writer = undefined; - unit.debug_rnglists_ni.unwrap().?.writer(&elf.mf, gpa, &drh_nw); - defer drh_nw.deinit(); - const debug_rnglists_offsets_table_offset = - elf.dwarf.genDebugRnglistsHeader(unit, &drh_nw) catch |err| switch (err) { - else => |e| return e, - error.WriteFailed => return drh_nw.err.?, - }; + unit.debug_line_header_ni = .wrap(elf.addNodeAssumeCapacity( + try debug_line_ni.addOnlyHeaderChild(gpa, &elf.mf, .{ + // Idle tasks are going to try to keep this up to date before we are able to + // write out the full header, so just reserve space for them to do so. + .size = elf.dwarf.unitLengthSize(), + .enable_next_moved = true, + }), + .{ .unit_debug_line_header = ui }, + )); + }, + } + switch (elf.shndx.debug_rnglists) { + .UNDEF => {}, + else => |debug_rnglists_shndx| unit.debug_rnglists_ni = .wrap(elf.addNodeAssumeCapacity( + try debug_rnglists_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ + .next_moved = true, + .enable_next_moved = true, + }), + .{ .unit_debug_rnglists = ui }, + )), + } + } - var dih_nw: MappedFile.Node.Writer = undefined; - const debug_info_header_ni = unit.debug_info_header_ni.unwrap().?; - debug_info_header_ni.writer(&elf.mf, gpa, &dih_nw); - defer dih_nw.deinit(); - elf.resetNodeRelocs(debug_info_header_ni); - elf.dwarf.genDebugInfoHeader( - mod, - unit, - &dih_nw, - debug_rnglists_offsets_table_offset, - zcu, - ) catch |err| switch (err) { + for ( + elf.dwarf.units.keys()[old_units_len..], + elf.dwarf.units.values()[old_units_len..], + ) |mod, *unit| { + var drh_nw: MappedFile.Node.Writer = undefined; + unit.debug_rnglists_ni.unwrap().?.writer(gpa, &elf.mf, &drh_nw); + defer drh_nw.deinit(); + const debug_rnglists_offsets_table_offset = + elf.dwarf.genDebugRnglistsHeader(unit, &drh_nw) catch |err| switch (err) { else => |e| return e, - error.WriteFailed => return dih_nw.err.?, + error.WriteFailed => return drh_nw.err.?, }; - } + + var dih_nw: MappedFile.Node.Writer = undefined; + const debug_info_header_ni = unit.debug_info_header_ni.unwrap().?; + debug_info_header_ni.writer(gpa, &elf.mf, &dih_nw); + defer dih_nw.deinit(); + elf.resetNodeRelocs(debug_info_header_ni); + elf.dwarf.genDebugInfoHeader( + mod, + unit, + &dih_nw, + debug_rnglists_offsets_table_offset, + zcu, + ) catch |err| switch (err) { + else => |e| return e, + error.WriteFailed => return dih_nw.err.?, + }; } } @@ -7203,7 +7225,7 @@ fn flushFiles(elf: *Elf) Error!void { try debug_line_header_ni.moved(gpa, &elf.mf); try debug_line_header_ni.nextMoved(gpa, &elf.mf); var dlh_nw: MappedFile.Node.Writer = undefined; - debug_line_header_ni.writer(&elf.mf, gpa, &dlh_nw); + debug_line_header_ni.writer(gpa, &elf.mf, &dlh_nw); defer dlh_nw.deinit(); elf.resetNodeRelocs(debug_line_header_ni); elf.dwarf.genDebugLineHeader(mod, unit, &dlh_nw, elf.base.comp.zcu.?) catch |err| switch (err) { @@ -7235,7 +7257,7 @@ fn prepareDynamic(elf: *Elf) Error!void { const dynamic_size = dynamic_len * 2 * elf.targetPtrSize(); - try elf.shndx.dynamic.get(elf).ni.resizeLeaf(&elf.mf, comp.gpa, dynamic_size); + try elf.shndx.dynamic.get(elf).ni.resizeLeaf(comp.gpa, &elf.mf, dynamic_size); switch (elf.shdrPtr(elf.shndx.dynamic)) { inline else => |shdr| elf.targetStore(&shdr.size, @intCast(dynamic_size)), } @@ -7405,17 +7427,20 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; }, }; - try elf.ni.shdr.ensureMinimumSize(&elf.mf, gpa, new_shdr_size); + try elf.ni.shdr.ensureMinimumSize(gpa, &elf.mf, new_shdr_size); const parent_ni = switch (elf.ehdrType()) { .REL => elf.ni.elf, .EXEC, .DYN => segment_ni, }; assert(opts.addralign.check(opts.size)); - const ni = try parent_ni.addFloatingChild(&elf.mf, gpa, .{ + const ni = elf.addNodeAssumeCapacity(try parent_ni.addFloatingChild(gpa, &elf.mf, .{ .size = opts.node_align.forward(opts.size), .alignment = opts.addralign.max(opts.node_align), .resized = opts.size > 0, .bubbles_moved = opts.flags.ALLOC, + }), switch (opts.manual_size) { + false => .{ .section = shndx }, + true => .{ .section_manual_size = shndx }, }); const addr = elf.computeNodeVAddr(ni); const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{ @@ -7431,10 +7456,6 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { .RELA => .{ .free_head = .none }, else => .{ .shndx = .UNDEF }, } }); - elf.nodes.appendAssumeCapacity(switch (opts.manual_size) { - false => .{ .section = shndx }, - true => .{ .section_manual_size = shndx }, - }); switch (elf.shdrPtr(shndx)) { inline else => |shdr, class| { shdr.* = .{ @@ -7505,7 +7526,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) .NONE, _ => unreachable, inline else => |ct_class| (elf.got.count() + new_got_entries) * @sizeOf(ct_class.ElfN().Addr), }; - try elf.shndx.got.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_got_size); + try elf.shndx.got.get(elf).ni.ensureMinimumSize(gpa, &elf.mf, need_got_size); if (elf.shndx.dynamic != .UNDEF) { try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, new_got_entries); @@ -8100,6 +8121,7 @@ fn addGotRelocAssumeCapacity( ) void { assert(elf.ehdrType() != .REL); switch (elf.getNode(node)) { + .deleted, .archive, .archive_header, .archive_input_member, @@ -8361,14 +8383,13 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { try Section.Index.data.ensureAligned(elf, dso_global.alignment); try elf.nodes.ensureUnusedCapacity(gpa, 1); - const node = try Section.Index.data.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + const node = try Section.Index.data.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ .size = dso_global.alignment.forward(dso_global.size), .alignment = dso_global.alignment, }); errdefer comptime unreachable; const vaddr = elf.computeNodeVAddr(node); - elf.nodes.appendAssumeCapacity(.{ .copied_global = global_name }); const rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ .type = .copy(elf), .offset = vaddr, @@ -8423,7 +8444,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) { var nw: MappedFile.Node.Writer = undefined; - ni.writer(&elf.mf, gpa, &nw); + ni.writer(gpa, &elf.mf, &nw); defer nw.deinit(); elf.resetNodeRelocs(ni); codegen.generateSymbol( @@ -8549,16 +8570,16 @@ fn updateFuncInner( { var nw: MappedFile.Node.Writer = undefined; - ni.writer(&elf.mf, gpa, &nw); + ni.writer(gpa, &elf.mf, &nw); defer nw.deinit(); var debug_output_buf: Dwarf.WipNav.Debug = undefined; const debug_output: link.File.DebugInfoOutput, const dwarf_func = debug_output: { if (elf.ehdrMachine() != .X86_64) break :debug_output .{ .none, undefined }; const dwarf = &elf.dwarf; - const mod = zcu.navFileScope(func.owner_nav).mod.?; + const mod = zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?; if (mod.strip and mod.unwind_tables == .none) break :debug_output .{ .none, undefined }; - try elf.nodes.ensureUnusedCapacity(gpa, 5); + try elf.nodes.ensureUnusedCapacity(gpa, 4); const dwarf_fi = try dwarf.getFunc(func.owner_nav); const wip_nav = &debug_output_buf.wip_nav; @@ -8586,27 +8607,28 @@ fn updateFuncInner( .@"64" => .@"8", }; const frame_ni = unit.frame_ni.unwrap() orelse frame_ni: { - const frame_ni = try switch (wip_nav.frame_format) { + const frame_ni = elf.addNodeAssumeCapacity(try switch (wip_nav.frame_format) { .debug_frame => elf.shndx.debug_frame, .eh_frame => elf.shndx.eh_frame, - }.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + }.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ .alignment = frame_align.max(elf.mf.flags.block_size), .enable_next_moved = true, - }); + }), .{ .unit_frame = wip_nav.unit }); unit.frame_ni = .wrap(frame_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_frame = wip_nav.unit }); break :frame_ni frame_ni; }; _ = unit.cie_ni.unwrap() orelse { - const cie_ni = try frame_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ - .alignment = frame_align, - .next_moved = true, - .enable_next_moved = true, - }); + const cie_ni = elf.addNodeAssumeCapacity( + try frame_ni.addOnlyHeaderChild(gpa, &elf.mf, .{ + .alignment = frame_align, + .next_moved = true, + .enable_next_moved = true, + }), + .{ .unit_frame_cie = wip_nav.unit }, + ); unit.cie_ni = .wrap(cie_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_frame_cie = wip_nav.unit }); var cie_nw: MappedFile.Node.Writer = undefined; - cie_ni.writer(&elf.mf, gpa, &cie_nw); + cie_ni.writer(gpa, &elf.mf, &cie_nw); defer cie_nw.deinit(); dwarf.genDebugFrameCie(&cie_nw.interface, switch (elf.ehdrMachine()) { else => unreachable, @@ -8621,7 +8643,7 @@ fn updateFuncInner( try fde_ni.nextMoved(gpa, &elf.mf); break :fde_ni fde_ni; } else fde_ni: { - const fde_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{ + const fde_ni = try frame_ni.addFloatingChild(gpa, &elf.mf, .{ .alignment = frame_align, .moved = true, .next_moved = true, @@ -8630,7 +8652,7 @@ fn updateFuncInner( dwarf_func.fde_ni = .wrap(fde_ni); break :fde_ni fde_ni; }; - fde_ni.writer(&elf.mf, gpa, &wip_nav.fde_writer); + fde_ni.writer(gpa, &elf.mf, &wip_nav.fde_writer); if (mod.strip) break :debug_output .{ .{ .eh_frame = wip_nav }, dwarf_func }; @@ -8642,20 +8664,21 @@ fn updateFuncInner( const debug_info_ni = dwarf_func.debug_info_ni.unwrap().?; try debug_info_ni.moved(gpa, &elf.mf); try debug_info_ni.nextMoved(gpa, &elf.mf); - debug_info_ni.writer(&elf.mf, gpa, &debug.info_writer); + debug_info_ni.writer(gpa, &elf.mf, &debug.info_writer); const debug_line_ni = dwarf_func.debug_line_ni.unwrap() orelse debug_line_ni: { - const debug_line_ni = - try unit.debug_line_ni.unwrap().?.addFloatingChild(&elf.mf, gpa, .{ + const debug_line_ni = elf.addNodeAssumeCapacity( + try unit.debug_line_ni.unwrap().?.addFloatingChild(gpa, &elf.mf, .{ .moved = true, .next_moved = true, .enable_next_moved = true, - }); + }), + .{ .func_debug_line = dwarf_fi }, + ); dwarf_func.debug_line_ni = .wrap(debug_line_ni); - elf.nodes.appendAssumeCapacity(.{ .func_debug_line = dwarf_fi }); break :debug_line_ni debug_line_ni; }; - debug_line_ni.writer(&elf.mf, gpa, &debug.line_writer); + debug_line_ni.writer(gpa, &elf.mf, &debug.line_writer); break :debug_output .{ .{ .dwarf2 = debug }, dwarf_func }; }; @@ -8705,13 +8728,13 @@ fn updateFuncInner( .debug_frame => elf.shndx.debug_frame, .eh_frame => elf.shndx.eh_frame, }.get(elf).ni; - try frame_ni.trimStart(&elf.mf, gpa); + try frame_ni.trimStart(gpa, &elf.mf); switch (wip_nav.frame_format) { .debug_frame => {}, .eh_frame => { const last_offset, const last_size = frame_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); - try frame_ni.ensureMinimumSize(&elf.mf, gpa, last_offset + last_size + 4); + try frame_ni.ensureMinimumSize(gpa, &elf.mf, last_offset + last_size + 4); }, } }, @@ -8721,18 +8744,18 @@ fn updateFuncInner( elf.shndx.debug_info, elf.shndx.debug_line, elf.shndx.debug_rnglists, - }) |debug_shndx| try debug_shndx.get(elf).ni.trimStart(&elf.mf, gpa); + }) |debug_shndx| try debug_shndx.get(elf).ni.trimStart(gpa, &elf.mf); const unit = debug.wip_nav.unit.get(debug.wip_nav.dwarf); { const debug_info_ni = unit.debug_info_ni.unwrap().?; const last_offset, const last_size = debug_info_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); - try debug_info_ni.ensureMinimumSize(&elf.mf, gpa, last_offset + last_size + - comptime Dwarf.uleb128Bytes(@backingInt(Dwarf.AbbrevCode.null)) * 2); + try debug_info_ni.ensureMinimumSize(gpa, &elf.mf, last_offset + last_size + + comptime Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) * 2); } { var dr_nw: MappedFile.Node.Writer = undefined; - unit.debug_rnglists_ni.unwrap().?.writer(&elf.mf, gpa, &dr_nw); + unit.debug_rnglists_ni.unwrap().?.writer(gpa, &elf.mf, &dr_nw); defer dr_nw.deinit(); const first_symbol_reloc = elf.symbol_relocs.items.len; debug.wip_nav.dwarf.genDebugRnglists( @@ -8764,6 +8787,25 @@ fn updateFuncInner( try elf.genPending(pt); } +pub fn updateLineNumber(elf: *Elf, pt: Zcu.PerThread, src_inst: InternPool.TrackedInst.Index) void { + const func = elf.dwarf.funcs.getPtr(src_inst) orelse return; + elf.dwarf.updateLineNumber(pt.zcu, src_inst, func.debug_info_ni.unwrap().?.slice(&elf.mf)); +} + +pub fn lostTracking( + elf: *Elf, + _: Zcu.PerThread, + src_inst: InternPool.TrackedInst.Index, +) std.mem.Allocator.Error!void { + const func = elf.dwarf.funcs.getPtr(src_inst) orelse return; + elf.resetNodeRelocs(func.fde_ni.unwrap().?); + elf.resetNodeRelocs(func.debug_info_ni.unwrap().?); + elf.resetNodeRelocs(func.debug_line_ni.unwrap().?); + try elf.deleteNode(&func.fde_ni); + try elf.deleteNode(&func.debug_info_ni); + try elf.deleteNode(&func.debug_line_ni); +} + pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void { try elf.updateConstInner( pt, @@ -8996,18 +9038,18 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { break :task; } - while (elf.mf.updates.pop()) |ni| { + while (elf.mf.updates.pop()) |ni| : (elf.mf.update_prog_node.completeOne()) { + if (ni.pendingDelete(&elf.mf)) continue; const clean_moved = ni.cleanMoved(&elf.mf); const clean_resized = ni.cleanResized(&elf.mf); const clean_next_moved = ni.cleanNextMoved(&elf.mf); - if (clean_moved or clean_resized or clean_next_moved) { - const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); - defer sub_prog_node.end(); - if (clean_moved) try elf.flushMoved(ni); - if (clean_resized) try elf.flushResized(ni); - if (clean_next_moved) try elf.flushNextMoved(ni); - break :task; - } else elf.mf.update_prog_node.completeOne(); + if (!clean_moved and !clean_resized and !clean_next_moved) continue; + const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); + defer sub_prog_node.end(); + if (clean_moved) try elf.flushMoved(ni); + if (clean_resized) try elf.flushResized(ni); + if (clean_next_moved) try elf.flushNextMoved(ni); + break :task; } } if (elf.input_sections.items.len > elf.input_section_pending_index) return true; @@ -9085,7 +9127,7 @@ fn idleProgNode( .func_debug_info => "debug", .func_debug_line => "line", }, - ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip), + ip.getNav(fi.get(&elf.dwarf).owner_nav).fqn.fmt(ip), }) catch &name; }, }, 0); @@ -9109,14 +9151,13 @@ fn genUav( pt: Zcu.PerThread, umi: Node.UavMapIndex, ) Error!void { - const comp = elf.base.comp; - const gpa = comp.gpa; + const gpa = elf.base.comp.gpa; const uav_val = umi.uavValue(elf); const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?; var nw: MappedFile.Node.Writer = undefined; - ni.writer(&elf.mf, gpa, &nw); + ni.writer(gpa, &elf.mf, &nw); defer nw.deinit(); elf.resetNodeRelocs(ni); codegen.generateSymbol( @@ -9150,7 +9191,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { var required_alignment: InternPool.Alignment = .none; var nw: MappedFile.Node.Writer = undefined; - ni.writer(&elf.mf, gpa, &nw); + ni.writer(gpa, &elf.mf, &nw); defer nw.deinit(); elf.resetNodeRelocs(ni); codegen.generateLazySymbol( @@ -9241,7 +9282,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { }), }; var nw: MappedFile.Node.Writer = undefined; - isi.node(elf).writer(&elf.mf, gpa, &nw); + isi.node(elf).writer(gpa, &elf.mf, &nw); defer nw.deinit(); const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) { error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{ @@ -9296,17 +9337,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void defer trace.end(); switch (elf.getNode(ni)) { - .archive => unreachable, - .archive_header => unreachable, - - .archive_input_member, - .archive_elf_member_header, - .elf, - => { + .deleted => unreachable, + .archive, .archive_header => unreachable, + .archive_input_member, .archive_elf_member_header, .elf => { assert(elf.archive != null); return; }, - .ehdr, .shdr => elf.flushElfOffset(ni), .segment => |phndx| { elf.flushElfOffset(ni); @@ -9570,7 +9606,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void }, .func_frame_fde => |fi| { const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; - const mod = elf.base.comp.zcu.?.navFileScope(fi.nav(&elf.dwarf)).mod.?; + const zcu = elf.base.comp.zcu.?; + const mod = zcu.fileByIndex(fi.srcInst(&elf.dwarf).resolveFile(&zcu.intern_pool)).mod.?; switch (mod.unwind_tables) { .none => {}, .sync, .async => { @@ -9594,8 +9631,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void } elf.flushMovedNodeRelocs(ni, elf.computeNodeVAddr(ni), .{ .first_symbol_reloc = dwarf_func.debug_info_first_symbol_reloc, - .skip_symbol_relocs = if (elf.navs.getPtr(fi.nav(&elf.dwarf))) |nav| - nav.lsi.index().ptr(elf).node + .skip_symbol_relocs = if (elf.navs.getPtr(fi.get(&elf.dwarf).owner_nav)) |owner_nav| + owner_nav.lsi.index().ptr(elf).node else .none, .first_node_reloc = dwarf_func.debug_info_first_node_reloc, @@ -9770,6 +9807,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo _, const size = ni.location(&elf.mf).resolve(&elf.mf); switch (elf.getNode(ni)) { + .deleted => unreachable, .archive, .archive_header => {}, .archive_input_member => unreachable, .archive_elf_member_header => unreachable, @@ -9869,6 +9907,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! defer trace.end(); switch (elf.getNode(ni)) { + .deleted, .archive, .archive_input_member, .archive_elf_member_header, @@ -10002,7 +10041,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! switch (tag) { else => unreachable, .unit_debug_info_header, .value_debug_info, .global_debug_info, .func_debug_info => { - comptime assert(Dwarf.uleb128Bytes(@backingInt(Dwarf.AbbrevCode.null)) == 1); + comptime assert(Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1); @memset(fw.unusedCapacitySlice(), @backingInt(Dwarf.AbbrevCode.null)); }, .unit_debug_line_header, .func_debug_line => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch @@ -10591,10 +10630,10 @@ pub fn printNode( .func_frame_fde, .func_debug_info, .func_debug_line => |fi| { const zcu = elf.base.comp.zcu.?; const ip = &zcu.intern_pool; - const nav = ip.getNav(fi.nav(&elf.dwarf)); + const owner_nav = ip.getNav(fi.get(&elf.dwarf).owner_nav); try w.print("({f}, {f})", .{ - Type.fromInterned(nav.resolved.?.type).fmt(.{ .zcu = zcu, .tid = tid }), - nav.fqn.fmt(ip), + Type.fromInterned(owner_nav.resolved.?.type).fmt(.{ .zcu = zcu, .tid = tid }), + owner_nav.fqn.fmt(ip), }); }, } @@ -10655,7 +10694,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error // Align the actual node const seg_ni = elf.phdrs.items[phndx].unwrap().?; if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) { - try seg_ni.realign(&elf.mf, gpa, min_align); + try seg_ni.realign(gpa, &elf.mf, min_align); } // Update the phdr `@"align"` field if necessary switch (elf.phdrSlice()) { @@ -10686,6 +10725,21 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error } } +pub fn addNodeAssumeCapacity(elf: *Elf, ni: MappedFile.Node.Index, node: Node) MappedFile.Node.Index { + if (elf.nodes.len - @backingInt(ni) > 0) { + assert(elf.getNode(ni) == .deleted); + elf.nodes.set(@backingInt(ni), node); + } else elf.nodes.appendAssumeCapacity(node); + return ni; +} + +fn deleteNode(elf: *Elf, node: *MappedFile.Node.Index.Optional) std.mem.Allocator.Error!void { + const ni = node.unwrap().?; + try ni.delete(elf.base.comp.gpa, &elf.mf); + elf.nodes.set(@backingInt(ni), .deleted); + node.* = .none; +} + /// If `sym` has a PLT entry, returns the address of that entry (specifically, the address which a /// branch to the PLT should target). If `sym` does not have a PLT entry, returns `null`. fn pltEntryTargetAddr(elf: *Elf, sym: Symbol.Id) ?u64 { diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index 4f7607632a9af7ab182aa785840f58c308292cac..a71cbbc001ff0035030b6182a77cbc2c9f0c6371 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -362,7 +362,7 @@ pub const Node = extern struct { } /// Adds a floating child node to `parent_ni`. Returns the index of the new child. - pub fn addFloatingChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index { + pub fn addFloatingChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index { return mf.addNode(gpa, .{ .add_options = opts, .position = .floating, @@ -373,11 +373,11 @@ pub const Node = extern struct { /// Adds a header child node to `parent_ni`. Returns the index of the new child. /// /// Asserts that `parent_ni` has no existing header children. - pub fn addOnlyHeaderChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index { + pub fn addOnlyHeaderChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index { if (parent_ni.first(mf).unwrap()) |first_ni| { assert(first_ni.position(mf) != .header); // `parent_ni` already has a header child } - return parent_ni.addHeaderChildAfter(mf, gpa, .none, opts); + return parent_ni.addHeaderChildAfter(gpa, mf, .none, opts); } /// Adds a header child node to `parent_ni`. Returns the index of the new child. /// @@ -386,7 +386,7 @@ pub const Node = extern struct { /// /// Otherwise, asserts that `prev_oni` is a header node and a child of `parent_ni`, and /// places the new child node immediately after `prev_oni`. - pub fn addHeaderChildAfter(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, prev_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index { + pub fn addHeaderChildAfter(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, prev_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index { return mf.addNode(gpa, .{ .add_options = opts, .position = .header, @@ -397,11 +397,11 @@ pub const Node = extern struct { /// Adds a footer child node to `parent_ni`. Returns the index of the new child. /// /// Asserts that `parent_ni` has no existing footer children. - pub fn addOnlyFooterChild(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, opts: AddOptions) Error!Node.Index { + pub fn addOnlyFooterChild(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, opts: AddOptions) Error!Node.Index { if (parent_ni.last(mf).unwrap()) |last_ni| { assert(last_ni.position(mf) != .footer); // `parent_ni` already has a footer child } - return parent_ni.addFooterChildBefore(mf, gpa, .none, opts); + return parent_ni.addFooterChildBefore(gpa, mf, .none, opts); } /// Adds a footer child node to `parent_ni`. Returns the index of the new child. /// @@ -410,7 +410,7 @@ pub const Node = extern struct { /// /// Otherwise, asserts that `next_oni` is a footer node and a child of `parent_ni`, and /// places the new child node immediately before `next_oni`. - pub fn addFooterChildBefore(parent_ni: Node.Index, mf: *MappedFile, gpa: Allocator, next_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index { + pub fn addFooterChildBefore(parent_ni: Node.Index, gpa: Allocator, mf: *MappedFile, next_oni: Node.Index.Optional, opts: AddOptions) Error!Node.Index { const prev_oni: Node.Index.Optional = prev: { const next_ni = next_oni.unwrap() orelse { break :prev parent_ni.last(mf); @@ -473,8 +473,8 @@ pub const Node = extern struct { fn setNext( ni: Node.Index, gpa: Allocator, + mf: *MappedFile, next_ni: Node.Index.Optional, - mf: *MappedFile, ) Allocator.Error!void { const next_ptr = &ni.get(mf).next; if (next_ptr.* == next_ni) return; @@ -571,7 +571,7 @@ pub const Node = extern struct { return ni.get(mf).flags.alignment; } - fn setLocation(ni: Node.Index, mf: *MappedFile, gpa: Allocator, offset: u64, size: u64) Allocator.Error!void { + fn setLocation(ni: Node.Index, gpa: Allocator, mf: *MappedFile, offset: u64, size: u64) Allocator.Error!void { try mf.large.ensureUnusedCapacity(gpa, 2); try mf.updates.ensureUnusedCapacity(gpa, 2); const node = ni.get(mf); @@ -646,19 +646,37 @@ pub const Node = extern struct { return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; } - pub fn trimStart(ni: Node.Index, mf: *MappedFile, gpa: Allocator) Allocator.Error!void { + pub fn delete(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { + const node = ni.get(mf); + assert(node.first == .none and node.last == .none); // has children + mf.removeNodesFromChildList(gpa, ni, ni); + const updated = node.flags.moved or node.flags.resized or node.flags.next_moved; + node.* = undefined; + node.next = ni.toOptional(); + if (!updated) assert(ni.pendingDelete(mf)); + } + + pub fn pendingDelete(ni: Node.Index, mf: *MappedFile) bool { + const node = ni.get(mf); + if (node.next != ni.toOptional()) return false; + node.next = mf.free_ni; + mf.free_ni = ni.toOptional(); + return true; + } + + pub fn trimStart(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void { mf.nodes_lock.assertUnlocked(); const node = ni.get(mf); const first_ni = node.first.unwrap() orelse return; const shift, _ = first_ni.location(mf).resolve(mf); if (shift == 0) return; const offset, const size = node.location().resolve(mf); - try ni.setLocation(mf, gpa, offset + shift, size - shift); + try ni.setLocation(gpa, mf, offset + shift, size - shift); var child_oni = node.first; while (child_oni.unwrap()) |child_ni| { const child_node = child_ni.get(mf); const child_offset, const child_size = child_node.location().resolve(mf); - try child_ni.setLocation(mf, gpa, child_offset - shift, child_size); + try child_ni.setLocation(gpa, mf, child_offset - shift, child_size); child_oni = child_node.next; } } @@ -666,7 +684,7 @@ pub const Node = extern struct { /// Ensures that the size of `ni` is at least `min_size`. Valid for any node. /// /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`). - pub fn ensureMinimumSize(ni: Node.Index, mf: *MappedFile, gpa: Allocator, min_size: u64) Error!void { + pub fn ensureMinimumSize(ni: Node.Index, gpa: Allocator, mf: *MappedFile, min_size: u64) Error!void { _, const current_size = ni.location(mf).resolve(mf); if (current_size >= min_size) return; const new_size = ni.alignment(mf).forward(min_size +| min_size / growth_factor); @@ -682,7 +700,7 @@ pub const Node = extern struct { /// Asserts that `ni` is a leaf node, i.e. has no children. /// /// Asserts that `size` is aligned to `ni.alignment(mf)`. - pub fn resizeLeaf(ni: Node.Index, mf: *MappedFile, gpa: Allocator, size: u64) Error!void { + pub fn resizeLeaf(ni: Node.Index, gpa: Allocator, mf: *MappedFile, size: u64) Error!void { assert(ni.first(mf) == .none); // The alignment of `size` is asserted by `shrinkLeafNode` and `growNode`. _, const old_size = ni.location(mf).resolve(mf); @@ -702,17 +720,12 @@ pub const Node = extern struct { /// If the node's current offset or size is not sufficiently aligned, it will be moved /// and/or resized to match the new alignment. The node's size may be increased by any /// amount, as if `ensureMinimumSize` were used. - pub fn realign( - ni: Node.Index, - mf: *MappedFile, - gpa: Allocator, - new_alignment: Alignment, - ) Error!void { + pub fn realign(ni: Node.Index, gpa: Allocator, mf: *MappedFile, new_alignment: Alignment) Error!void { try mf.realignNode(gpa, ni, new_alignment); mf.updateWriters(); } - pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: Allocator, w: *Writer) void { + pub fn writer(ni: Node.Index, gpa: Allocator, mf: *MappedFile, w: *Writer) void { w.* = .{ .gpa = gpa, .mf = mf, @@ -842,7 +855,7 @@ pub const Node = extern struct { ) Io.Writer.Error!void { _ = preserve; const w: *Writer = @fieldParentPtr("interface", interface); - w.ni.ensureMinimumSize(w.mf, w.gpa, interface.end + unused_capacity) catch |err| { + w.ni.ensureMinimumSize(w.gpa, w.mf, interface.end + unused_capacity) catch |err| { w.err = err; return error.WriteFailed; }; @@ -1014,7 +1027,7 @@ fn shrinkLeafNode( }, }; try mf.ensureTotalCapacityPrecise(@intCast(new_size)); - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); return; }; @@ -1022,7 +1035,7 @@ fn shrinkLeafNode( .header => { const shift = old_size - new_size; - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); // We need to shift backwards all header nodes following us. const next_header_ni = ni.next(mf).unwrap() orelse return; @@ -1031,7 +1044,7 @@ fn shrinkLeafNode( var header_ni = next_header_ni; while (true) { const old_header_off, const old_header_size = header_ni.location(mf).resolve(mf); - try header_ni.setLocation(mf, gpa, old_header_off - shift, old_header_size); + try header_ni.setLocation(gpa, mf, old_header_off - shift, old_header_size); const next_ni = header_ni.next(mf).unwrap() orelse break; if (next_ni.position(mf) != .header) break; @@ -1056,13 +1069,13 @@ fn shrinkLeafNode( ); }, .floating => { - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); }, .footer => { const shift = old_size - new_size; const new_offset = old_offset + shift; - try ni.setLocation(mf, gpa, new_offset, new_size); + try ni.setLocation(gpa, mf, new_offset, new_size); const prev_footers_size = prev_footers_size: { // We need to shift forwards all footer nodes preceding us. @@ -1076,7 +1089,7 @@ fn shrinkLeafNode( var footer_ni = prev_footer_ni; while (true) { const old_footer_off, const old_footer_size = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, old_footer_off + shift, old_footer_size); + try footer_ni.setLocation(gpa, mf, old_footer_off + shift, old_footer_size); const prev_ni = footer_ni.prev(mf).unwrap() orelse break; if (prev_ni.position(mf) != .footer) break; @@ -1159,7 +1172,7 @@ fn growNode( }, }; try mf.ensureTotalCapacityPrecise(@intCast(new_size)); - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); if (grow_options.move_footers) { // We need to move any footers to be at the *new* end of the file. if (ni.firstFooter(mf).unwrap()) |first_footer_ni| { @@ -1174,7 +1187,7 @@ fn growNode( var cur_ni = first_footer_ni; while (true) { const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf); - try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size); + try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size); cur_ni = cur_ni.next(mf).unwrap() orelse break; } } @@ -1233,8 +1246,8 @@ fn growNode( while (true) { const old_sub_footer_offset, const sub_footer_size = cur_ni.location(mf).resolve(mf); try cur_ni.setLocation( - mf, gpa, + mf, old_sub_footer_offset + (new_size - old_size), sub_footer_size, ); @@ -1249,8 +1262,8 @@ fn growNode( assert(moved_header_ni.position(mf) == .header); const moved_header_offset, const moved_header_size = moved_header_ni.location(mf).resolve(mf); try moved_header_ni.setLocation( - mf, gpa, + mf, moved_header_offset - old_size + new_size, moved_header_size, ); @@ -1259,7 +1272,7 @@ fn growNode( } // Finally, update our own size: - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); return; }, .floating => { @@ -1387,8 +1400,8 @@ fn growNode( // Update our own offset and size: try ni.setLocation( - mf, gpa, + mf, node.location().resolve(mf)[0] - shift, new_size, ); @@ -1399,7 +1412,7 @@ fn growNode( var footer_oni = first_sub_footer_oni; while (footer_oni.unwrap()) |footer_ni| : (footer_oni = footer_ni.next(mf)) { const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, old_footer_offset + shift, footer_size); + try footer_ni.setLocation(gpa, mf, old_footer_offset + shift, footer_size); } } @@ -1414,7 +1427,7 @@ fn growNode( while (footer_ni != ni) : (footer_ni = footer_ni.next(mf).unwrap().?) { moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content; const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, old_footer_offset - shift, footer_size); + try footer_ni.setLocation(gpa, mf, old_footer_offset - shift, footer_size); } } @@ -1466,8 +1479,8 @@ fn growNode( } try ni.setLocation( - mf, gpa, + mf, node.location().resolve(mf)[0], actual_new_size, ); @@ -1483,7 +1496,7 @@ fn growNode( assert(footer_ni.position(mf) == .footer); moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content; const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, footer_old_offset + shift, footer_size); + try footer_ni.setLocation(gpa, mf, footer_old_offset + shift, footer_size); } } @@ -1494,7 +1507,7 @@ fn growNode( assert(footer_ni.position(mf) == .footer); moved_has_content = moved_has_content or footer_ni.get(mf).flags.has_content; const footer_old_offset: u64, const footer_size: u64 = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, footer_old_offset + shift, footer_size); + try footer_ni.setLocation(gpa, mf, footer_old_offset + shift, footer_size); } } @@ -1566,7 +1579,7 @@ fn growFloatingNodeWithAlignment( break :grow_in_place; // the parent is not big enough } // Great, we can grow this node without changing its offset or moving any siblings. - try ni.setLocation(mf, gpa, old_offset, new_size); + try ni.setLocation(gpa, mf, old_offset, new_size); if (grow_options.move_footers) { // If we have any footers, we need to move them to the end of our new size, and update // their offsets accordingly. @@ -1576,7 +1589,7 @@ fn growFloatingNodeWithAlignment( while (true) { footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content; const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf); - try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size); + try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size); cur_ni = cur_ni.next(mf).unwrap() orelse break; } if (footers_have_content) { @@ -1713,7 +1726,7 @@ fn growFloatingNodeWithAlignment( footers_have_content = footers_have_content or cur_ni.get(mf).flags.has_content; const old_footer_offset, const footer_size = cur_ni.location(mf).resolve(mf); // Our footers' offsets must change to be at the end of our new size. - try cur_ni.setLocation(mf, gpa, old_footer_offset + (new_size - old_size), footer_size); + try cur_ni.setLocation(gpa, mf, old_footer_offset + (new_size - old_size), footer_size); cur_ni = cur_ni.next(mf).unwrap() orelse break; } @@ -1740,7 +1753,7 @@ fn growFloatingNodeWithAlignment( assert(!footers_have_content); } - try ni.setLocation(mf, gpa, new_loc.offset, new_size); + try ni.setLocation(gpa, mf, new_loc.offset, new_size); if (new_loc.prev != ni.toOptional()) { // We're potentially in a different place in `parent_ni`'s child list, so remove and re-add ourselves. @@ -1940,11 +1953,11 @@ fn growNodeViaInsertRange( if (cur_ni == .root) { try mf.ensureTotalCapacityPrecise(@intCast(this_old_size + range_size)); } - try cur_ni.setLocation(mf, gpa, this_offset, this_old_size + range_size); + try cur_ni.setLocation(gpa, mf, this_offset, this_old_size + range_size); while (cur_ni.next(mf).unwrap()) |next_ni| { const next_old_offset, const next_size = next_ni.location(mf).resolve(mf); - try next_ni.setLocation(mf, gpa, next_old_offset + range_size, next_size); + try next_ni.setLocation(gpa, mf, next_old_offset + range_size, next_size); cur_ni = next_ni; } @@ -1957,7 +1970,7 @@ fn growNodeViaInsertRange( var footer_ni = first_footer_ni; while (true) { const old_footer_offset, const footer_size = footer_ni.location(mf).resolve(mf); - try footer_ni.setLocation(mf, gpa, old_footer_offset + range_size, footer_size); + try footer_ni.setLocation(gpa, mf, old_footer_offset + range_size, footer_size); footer_ni = footer_ni.next(mf).unwrap() orelse break; } } @@ -2125,7 +2138,7 @@ fn ensureAdditionalHeaderCapacity( const old_offset, const old_size = cur_ni.location(mf).resolve(mf); const new_offset = old_offset - moving_offset + dest_offset; assert(cur_ni.alignment(mf).check(new_offset)); - try cur_ni.setLocation(mf, gpa, new_offset, old_size); + try cur_ni.setLocation(gpa, mf, new_offset, old_size); if (cur_ni == last_moving_ni) break; cur_ni = cur_ni.next(mf).unwrap().?; } @@ -2168,7 +2181,7 @@ fn removeNodesFromChildList( if (prev_oni.unwrap()) |prev_ni| { assert(prev_ni.next(mf).unwrap().? == first_remove_ni); - try prev_ni.setNext(gpa, next_oni, mf); + try prev_ni.setNext(gpa, mf, next_oni); } else { assert(parent_ni.first(mf).unwrap().? == first_remove_ni); parent_ni.get(mf).first = next_oni; @@ -2207,11 +2220,11 @@ fn addNodesToChildListBefore( }; first_add_ni.get(mf).prev = prev_oni; - try last_add_ni.setNext(gpa, next_oni, mf); + try last_add_ni.setNext(gpa, mf, next_oni); if (prev_oni.unwrap()) |prev_ni| { assert(prev_ni.next(mf) == next_oni); - try prev_ni.setNext(gpa, .wrap(first_add_ni), mf); + try prev_ni.setNext(gpa, mf, .wrap(first_add_ni)); } else { assert(parent_ni.first(mf) == next_oni); parent_ni.get(mf).first = .wrap(first_add_ni); @@ -2652,7 +2665,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void { for (1..n) |_| cur_ni = cur_ni.next(&mf).unwrap().?; break :prev_oni .wrap(cur_ni); }; - const new_ni = try parent_ni.addHeaderChildAfter(&mf, gpa, prev_oni, .{ + const new_ni = try parent_ni.addHeaderChildAfter(gpa, &mf, prev_oni, .{ .size = size, .alignment = alignment, }); @@ -2660,7 +2673,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void { break :new_ni new_ni; }, - .floating => try parent_ni.addFloatingChild(&mf, gpa, .{ + .floating => try parent_ni.addFloatingChild(gpa, &mf, .{ .size = size, .alignment = alignment, }), @@ -2674,7 +2687,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void { for (1..n) |_| cur_ni = cur_ni.prev(&mf).unwrap().?; break :next_oni .wrap(cur_ni); }; - const new_ni = try parent_ni.addFooterChildBefore(&mf, gpa, next_oni, .{ + const new_ni = try parent_ni.addFooterChildBefore(gpa, &mf, next_oni, .{ .size = size, .alignment = alignment, }); @@ -2708,13 +2721,13 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void { if (ni.first(&mf) == .none and smith.value(bool)) { // Since this is a leaf node, we can use `resizeLeaf`. const new_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights)); - try ni.resizeLeaf(&mf, gpa, new_size); + try ni.resizeLeaf(gpa, &mf, new_size); if (new_size == 0) { node_info.initialized = false; } } else { const min_size = alignment.forward(smith.valueWeighted(u64, initial_size_weights)); - try ni.ensureMinimumSize(&mf, gpa, min_size); + try ni.ensureMinimumSize(gpa, &mf, min_size); } if (ni.first(&mf) == .none) { @@ -2740,7 +2753,7 @@ fn fuzzOneNodeOperations(_: void, smith: *std.testing.Smith) anyerror!void { const new_alignment = smith.valueWeighted(Alignment, alignment_weights); if (new_alignment.compare(.gt, ni.alignment(&mf))) { _, const old_size = ni.location(&mf).resolve(&mf); - try ni.realign(&mf, gpa, new_alignment); + try ni.realign(gpa, &mf, new_alignment); if (ni.first(&mf) == .none and nodes.get(ni).?.initialized) { const slice = ni.slice(&mf); @memmove(slice[slice.len - 4 ..][0..4], slice[old_size - 4 ..][0..4]);