From e761d5200a0888e4c56e04a725979c70de457e71 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 11 Aug 2026 05:41:28 -0400 Subject: [PATCH] link: fix `@tagName` incremental bug --- src/Compilation.zig | 8 +- src/Zcu.zig | 2 +- src/codegen/aarch64/Select.zig | 10 +- src/codegen/c.zig | 5 +- src/codegen/llvm.zig | 6 +- src/codegen/loongarch/Mir.zig | 2 +- src/codegen/riscv64/CodeGen.zig | 4 +- src/codegen/sparc64/CodeGen.zig | 4 +- src/codegen/spirv/CodeGen.zig | 12 +- src/codegen/spork8/CodeGen.zig | 42 ++--- src/codegen/wasm/CodeGen.zig | 11 +- src/codegen/x86_64/CodeGen.zig | 2 +- src/codegen/x86_64/Emit.zig | 2 +- src/link.zig | 23 +-- src/link/C.zig | 28 +-- src/link/Coff.zig | 138 +++++++++----- src/link/ConstPool.zig | 15 +- src/link/Dwarf.zig | 4 +- src/link/Elf.zig | 4 +- src/link/Elf2.zig | 178 +++++++++++------- ...no_change_preserves_tag_names => tag_name} | 9 + 21 files changed, 281 insertions(+), 228 deletions(-) rename test/incremental/{no_change_preserves_tag_names => tag_name} (66%) diff --git a/src/Compilation.zig b/src/Compilation.zig index a8b12da5e9fcccdcf34d1e6f42c34caf35c7c900..532bad3ac8ff21197395c4c0b6ed664f6bfb5cd9 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2829,6 +2829,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE } const is_hit = man.hit(main_progress_node) catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, error.CacheCheckFailed => switch (man.diagnostic) { .none => unreachable, .manifest_create, .manifest_read, .manifest_lock => |e| return comp.setMiscFailure( @@ -2844,7 +2845,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE }); }, }, - error.OutOfMemory, error.Canceled => |e| return e, error.InvalidFormat => return comp.setMiscFailure( .check_whole_cache, "failed to check cache: invalid manifest file format", @@ -3283,8 +3283,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error .fuzz = comp.config.any_fuzz, .lto = comp.config.lto, }) catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => {}, - error.OutOfMemory => |e| return e, }; if (zcu_obj_path) |path| { @@ -3293,8 +3293,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error // `link.Queue` has not called `prelink` because it knew we would want to send that // final link input. It is *our* responsibility to call `prelink` now we're done. comp.bin_file.?.prelink() catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => return, - else => |e| return e, }; } } @@ -3308,8 +3308,8 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error }; // This is needed before reading the error flags. lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => return, - error.OutOfMemory, error.Canceled => |e| return e, }; } } diff --git a/src/Zcu.zig b/src/Zcu.zig index 1d309e0d599476fec9b3a5780b6ca1fe5615f5b0..31ea183e8959c7c02391715b34e8743e005129d7 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -4707,7 +4707,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) return .ok; } -pub const CodegenFailError = error{ +pub const CodegenFailError = Io.Cancelable || error{ /// Indicates the error message has been already stored at `Zcu.failed_codegen`. AlreadyReported, OutOfMemory, diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 3b8765e23a9f6ed943bbd73a95c812da364b2af1..81216ea24a0d5f05cecb1d1663cb4f6ff822be4a 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -896,7 +896,7 @@ pub fn finishAnalysis(isel: *Select) !void { } } -pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, AlreadyReported }!void { +pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void { const zcu = isel.pt.zcu; const ip = &zcu.intern_pool; const gpa = zcu.gpa; @@ -8024,7 +8024,7 @@ fn emitLiteral(isel: *Select, bytes: []const u8) !void { } } -fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +fn fail(isel: *Select, comptime format: []const u8, args: anytype) codegen.Error { @branchHint(.cold); return isel.pt.zcu.codegenFail(isel.nav_index, format, args); } @@ -10618,7 +10618,7 @@ pub const Value = struct { vi: Value.Index, ra: Register.Alias, - fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, AlreadyReported }!void { + fn finish(mat: Value.Materialize, isel: *Select) codegen.Error!void { const live_vi = isel.live_registers.getPtr(mat.ra); assert(live_vi.* == .allocating); var vi = mat.vi; @@ -11659,7 +11659,7 @@ fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index { return vi; } -fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool { +fn fill(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool { switch (dst_ra) { else => {}, Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false, @@ -11692,7 +11692,7 @@ fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReport return true; } -fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, AlreadyReported }!bool { +fn fillMemory(isel: *Select, dst_ra: Register.Alias) codegen.Error!bool { const dst_live_vi = isel.live_registers.getPtr(dst_ra); const dst_vi = switch (dst_live_vi.*) { _ => |dst_vi| dst_vi, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index f4d724d4d6f766bb58818c0c33dbba915c7f2251..b0144a7c54ba438fec756551cc611dad2e92a823 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -6,6 +6,7 @@ const log = std.log.scoped(.c); const Allocator = mem.Allocator; const Writer = std.Io.Writer; +const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); const link = @import("../link.zig"); const Zcu = @import("../Zcu.zig"); @@ -86,7 +87,7 @@ pub const Mir = struct { } }; -pub const Error = Writer.Error || Allocator.Error || error{AlreadyReported}; +pub const Error = codegen.Error || Writer.Error; pub const CType = @import("c/type.zig").CType; @@ -2251,7 +2252,7 @@ pub fn generate( func_index: InternPool.Index, air: *const Air, liveness: *const ?Air.Liveness, -) @import("../codegen.zig").Error!Mir { +) codegen.Error!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ec493f5540a0b55aa49cff29746dfd73c4859e29..29062dd7b199efded0558712cd2ca9150a033741 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -348,7 +348,7 @@ pub const Object = struct { lto: std.zig.LtoMode, }; - pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) error{ AlreadyReported, OutOfMemory }!void { + pub fn emit(o: *Object, pt: Zcu.PerThread, options: EmitOptions) link.Error!void { const zcu = o.zcu; const comp = zcu.comp; const io = comp.io; @@ -1141,7 +1141,7 @@ pub const Object = struct { } } - fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { + fn flushTypePool(o: *Object, pt: Zcu.PerThread) link.Error!void { try o.type_pool.flushPending(pt, .{ .llvm = o }); } @@ -1304,7 +1304,7 @@ pub const Object = struct { }, &o.builder); } - pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void { + pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) link.Error!void { _ = o.type_map.remove(ty); try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success); if (o.named_enum_map.get(ty)) |llvm_function| { diff --git a/src/codegen/loongarch/Mir.zig b/src/codegen/loongarch/Mir.zig index f81843ff4e24ce3c395cd250844e1bed9bb368cb..a0b90b0f730ac350723c3420f292ba5e128b9aae 100644 --- a/src/codegen/loongarch/Mir.zig +++ b/src/codegen/loongarch/Mir.zig @@ -115,7 +115,7 @@ pub fn emit( @fromBackingInt(ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})) else if (lf.cast(.elf2)) |elf| - elf.lazySymbol(lazy_reloc.symbol) catch |err| + elf.lazySymbol(pt, lazy_reloc.symbol) catch |err| return zcu.codegenFail(func.owner_nav, "emit lazy symbol: {t}", .{err}) else return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig index 450ef37e8eda3f8fd5d26584b8884b5049d554a6..9f971cddf23f8a15cf0abcbb17fae110c41066c2 100644 --- a/src/codegen/riscv64/CodeGen.zig +++ b/src/codegen/riscv64/CodeGen.zig @@ -8349,7 +8349,7 @@ fn wantSafety(func: *Func) bool { }; } -fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +fn fail(func: *const Func, comptime format: []const u8, args: anytype) codegen.Error { @branchHint(.cold); const zcu = func.pt.zcu; switch (func.owner) { @@ -8359,7 +8359,7 @@ fn fail(func: *const Func, comptime format: []const u8, args: anytype) error{ Ou return error.AlreadyReported; } -fn failMsg(func: *const Func, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } { +fn failMsg(func: *const Func, msg: *ErrorMsg) codegen.Error { @branchHint(.cold); const zcu = func.pt.zcu; switch (func.owner) { diff --git a/src/codegen/sparc64/CodeGen.zig b/src/codegen/sparc64/CodeGen.zig index c8a4b9ab5f163a3dfdcd696717c62bdccb86737b..a35ceb4fcbe8e18abd11ebef7c5852bca56b6bc3 100644 --- a/src/codegen/sparc64/CodeGen.zig +++ b/src/codegen/sparc64/CodeGen.zig @@ -3450,7 +3450,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) } } -fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +fn fail(self: *Self, comptime format: []const u8, args: anytype) codegen.Error { @branchHint(.cold); const zcu = self.pt.zcu; const func = zcu.funcInfo(self.func_index); @@ -3458,7 +3458,7 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) error{ OutOfMem return zcu.codegenFailMsg(func.owner_nav, msg); } -fn failMsg(self: *Self, msg: *ErrorMsg) error{ OutOfMemory, AlreadyReported } { +fn failMsg(self: *Self, msg: *ErrorMsg) codegen.Error { @branchHint(.cold); const zcu = self.pt.zcu; const func = zcu.funcInfo(self.func_index); diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig index db2ffcb30bcea0d4f48f912f6ba13bb991b85da8..57683c89553d73c83bc93a7145136f0730fd8f13 100644 --- a/src/codegen/spirv/CodeGen.zig +++ b/src/codegen/spirv/CodeGen.zig @@ -240,10 +240,7 @@ pub fn generate( }; defer cg.deinit(); - cg.genNav(true) catch |err| switch (err) { - error.AlreadyReported => return error.AlreadyReported, - error.OutOfMemory => return error.OutOfMemory, - }; + try cg.genNav(true); return cg.serializeToMir(gpa); } @@ -270,10 +267,7 @@ pub fn generateNav( }; defer cg.deinit(); - cg.genNav(false) catch |err| switch (err) { - error.AlreadyReported => return error.AlreadyReported, - error.OutOfMemory => return error.OutOfMemory, - }; + try cg.genNav(false); return cg.serializeToMir(gpa); } @@ -854,7 +848,7 @@ pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageC }; } -const Error = error{ AlreadyReported, OutOfMemory }; +const Error = codegen.Error; pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { const gpa = cg.gpa; diff --git a/src/codegen/spork8/CodeGen.zig b/src/codegen/spork8/CodeGen.zig index f163d9347e239495f1d5217bf522a859b9c608f4..94ed016dc40b72983234b61a5889eedad9ef0088 100644 --- a/src/codegen/spork8/CodeGen.zig +++ b/src/codegen/spork8/CodeGen.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const CodeGen = @This(); +const codegen = @import("../../codegen.zig"); const link = @import("../../link.zig"); const Spork8 = link.File.Spork8; const Zcu = @import("../../Zcu.zig"); @@ -133,37 +134,20 @@ pub fn generate( _ = bin_file; const zcu = pt.zcu; const gpa = zcu.gpa; - const cg = zcu.funcInfo(func_index); + const func = zcu.funcInfo(func_index); - var code_gen: CodeGen = .{ + var cg: CodeGen = .{ .gpa = gpa, .pt = pt, .air = air.*, .liveness = liveness.*.?, - .owner_nav = cg.owner_nav, + .owner_nav = func.owner_nav, .func_index = func_index, .mir_instructions = .empty, .mir_extra = .empty, }; - defer code_gen.deinit(); + defer cg.deinit(); - return generateInner(&code_gen) catch |err| switch (err) { - error.AlreadyReported, - error.OutOfMemory, - => |e| return e, - }; -} - -pub fn deinit(cg: *CodeGen) void { - cg.* = undefined; -} - -const InnerError = error{ - AlreadyReported, - OutOfMemory, -}; - -fn generateInner(cg: *CodeGen) InnerError!Mir { // Generate MIR for function body try cg.genBody(cg.air.getMainBody()); @@ -175,7 +159,11 @@ fn generateInner(cg: *CodeGen) InnerError!Mir { }; } -fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { +pub fn deinit(cg: *CodeGen) void { + cg.* = undefined; +} + +fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) codegen.Error!void { const zcu = cg.pt.zcu; const ip = &zcu.intern_pool; @@ -185,7 +173,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } } -fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { +fn genInst(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void { const air_tags = cg.air.instructions.items(.tag); return switch (air_tags[@backingInt(inst)]) { .inferred_alloc, .inferred_alloc_comptime => unreachable, @@ -444,17 +432,17 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { }; } -fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { +fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void { _ = cg; _ = inst; } -fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { +fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void { _ = inst; try cg.addTag(.halt); } -fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { +fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) codegen.Error!void { const unwrapped_asm = cg.air.unwrapAsm(inst); const outputs = unwrapped_asm.outputs; // const inputs = unwrapped_asm.inputs; @@ -538,7 +526,7 @@ pub fn addTagImm8(cg: *CodeGen, tag: Mir.Inst.Tag, imm8: u8) error{OutOfMemory}! try cg.addInst(.{ .tag = tag, .data = .{ .imm8 = imm8 } }); } -fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) codegen.Error { const zcu = cg.pt.zcu; const func = zcu.funcInfo(cg.func_index); return zcu.codegenFail(func.owner_nav, fmt, args); diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index 343d089209acbb63da92b17dc8a90857a8f22e31..e3997d0b2e806cadb750dde7feac93fc05bab31c 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -332,8 +332,7 @@ const ValueTable = std.array_hash_map.Auto(Air.Inst.Ref, WValue); const bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; -const InnerError = error{ - OutOfMemory, +const InnerError = Error || error{ /// An error occurred when trying to lower AIR to MIR. AlreadyReported, /// Compiler implementation could not handle a large integer. @@ -361,7 +360,7 @@ pub fn deinit(cg: *CodeGen) void { cg.* = undefined; } -pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error { const zcu = cg.pt.zcu; const func = zcu.funcInfo(cg.func_index); return zcu.codegenFail(func.owner_nav, fmt, args); @@ -760,11 +759,7 @@ fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { return .{ .local = .{ .value = initial_index, .references = 1 } }; } -pub const Error = error{ - OutOfMemory, - /// Indicates the error is already stored in Zcu `failed_codegen`. - AlreadyReported, -}; +pub const Error = codegen.Error; pub fn generate( bin_file: *link.File, diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index eeee3888956a5a3a5c6ea405986f7a2a96211302..e59e520c5cb4ee44ef14062bc030266a776711ae 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -182172,7 +182172,7 @@ fn resolveCallingConventionValues( return result; } -fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { +fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) codegen.Error { @branchHint(.cold); const zcu = cg.pt.zcu; return switch (cg.owner) { diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index 7196aca6ef02eee3b07bcdf58d84822ee550877d..f0961b6970a631a2e224b5f7cf71e4f52717cc75 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -138,7 +138,7 @@ pub fn emitMir(emit: *Emit) Error!void { return emit.fail("{s} creating lazy symbol", .{@errorName(err)}), )) else if (emit.bin_file.cast(.elf2)) |elf| - try elf.lazySymbol(lazy_sym) + try elf.lazySymbol(emit.pt, lazy_sym) else if (emit.bin_file.cast(.macho)) |macho_file| @fromBackingInt(@intCast(macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| return emit.fail("{s} creating lazy symbol", .{@errorName(err)}))) diff --git a/src/link.zig b/src/link.zig index 87c108a8613010dea91e3dcd498147b909cc202f..4f179e3ac7e7bc0e366262da3817c529b20c0ad7 100644 --- a/src/link.zig +++ b/src/link.zig @@ -838,7 +838,7 @@ pub const File = struct { switch (base.tag) { .lld => unreachable, else => {}, - inline .elf, .c => |tag| { + inline .elf, .elf2, .c, .coff2 => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success); }, @@ -1690,19 +1690,14 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void const name = Type.fromInterned(container_update.ty).containerTypeName(ip).toSlice(ip); const ty_prog_node = comp.link_prog_node.start(name, 0); defer ty_prog_node.end(); - if (zcu.llvm_object) |llvm_object| { - llvm_object.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) { - error.OutOfMemory => diags.setAllocFailure(), - }; - } else { - if (comp.bin_file) |lf| { - lf.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) { - error.OutOfMemory => diags.setAllocFailure(), - error.Canceled => io.recancel(), - error.AlreadyReported => {}, - }; - } - } + (if (zcu.llvm_object) |llvm_object| + llvm_object.updateContainerType(pt, container_update.ty, container_update.success) + else if (comp.bin_file) |lf| + lf.updateContainerType(pt, container_update.ty, container_update.success)) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + error.Canceled => io.recancel(), + error.AlreadyReported => {}, + }; break :nav null; }, .debug_update_line_number => |ti| nav: { diff --git a/src/link/C.zig b/src/link/C.zig index 94a53479639a156a88365cfac5d9d14ee4dfec42..a080687e40e369dc5d941b2484c8fa915e9e394c 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -498,7 +498,7 @@ pub fn updateFunc( pt: Zcu.PerThread, func_index: InternPool.Index, mir: *AnyMir, -) Allocator.Error!void { +) link.Error!void { const zcu = pt.zcu; const gpa = zcu.gpa; const nav = zcu.funcInfo(func_index).owner_nav; @@ -536,11 +536,7 @@ pub fn updateFunc( try c.type_pool.flushPending(pt, .{ .c = c }); } -pub fn updateNav( - c: *C, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, -) Allocator.Error!void { +pub fn updateNav(c: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { const tracy = trace(@src()); defer tracy.end(); @@ -603,7 +599,8 @@ pub fn updateNav( const start = aw.written().len; codegen.genDeclFwd(&dg, &aw.writer) catch |err| switch (err) { error.AlreadyReported => return, - error.WriteFailed, error.OutOfMemory => return error.OutOfMemory, + error.WriteFailed => return error.OutOfMemory, + error.Canceled, error.OutOfMemory => |e| return e, }; break :fwd_decl .{ .start = @intCast(start), @@ -617,7 +614,8 @@ pub fn updateNav( const start = aw.written().len; codegen.genDecl(&dg, &aw.writer) catch |err| switch (err) { error.AlreadyReported => return, - error.WriteFailed, error.OutOfMemory => return error.OutOfMemory, + error.WriteFailed => return error.OutOfMemory, + error.Canceled, error.OutOfMemory => |e| return e, }; break :code .{ .start = @intCast(start), @@ -655,7 +653,7 @@ fn updateUav( pt: Zcu.PerThread, val: Value, rendered_decl: *RenderedDecl, -) Allocator.Error!void { +) link.Error!void { const tracy = trace(@src()); defer tracy.end(); @@ -691,7 +689,8 @@ fn updateUav( .init_val = val, }) catch |err| switch (err) { error.AlreadyReported => return, - error.WriteFailed, error.OutOfMemory => return error.OutOfMemory, + error.WriteFailed => return error.OutOfMemory, + error.Canceled, error.OutOfMemory => |e| return e, }; break :fwd_decl .{ .start = @intCast(start), @@ -710,7 +709,8 @@ fn updateUav( .init_val = val, }) catch |err| switch (err) { error.AlreadyReported => return, - error.WriteFailed, error.OutOfMemory => return error.OutOfMemory, + error.WriteFailed => return error.OutOfMemory, + error.Canceled, error.OutOfMemory => |e| return e, }; break :code .{ .start = @intCast(start), @@ -1144,14 +1144,14 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog for (need_never_tail_funcs.keys()) |fn_nav| { codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_tail, &lazy_decls_aw.writer) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, - error.OutOfMemory => |e| return e, + error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => unreachable, }; } for (need_never_inline_funcs.keys()) |fn_nav| { codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_inline, &lazy_decls_aw.writer) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, - error.OutOfMemory => |e| return e, + error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => unreachable, }; } @@ -1399,7 +1399,7 @@ fn addCTypeDependencies( }; } -fn updateNewUavs(c: *C, pt: Zcu.PerThread, old_uavs_len: usize) Allocator.Error!void { +fn updateNewUavs(c: *C, pt: Zcu.PerThread, old_uavs_len: usize) link.Error!void { const gpa = pt.zcu.comp.gpa; var index = old_uavs_len; while (index < c.uavs.count()) : (index += 1) { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index b1ae945300e65c46776f2f43b69b3f0e7ec9f65a..9a7984de7f0d1d5362e59ce49cc7de028ca8f9b4 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1666,7 +1666,7 @@ fn create( .global_pending_index = 0, .navs = .empty, .uavs = .empty, - .lazy = .initFill(.{ + .lazy = comptime .initFill(.{ .map = .empty, .pending_index = 0, }), @@ -3158,7 +3158,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void { }, inline .lazy_code, .lazy_const_data => |mi, tag| { const lazy_sym = mi.lazySymbol(coff); - const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ + const name = try gpa.print("__lazy_{s}_{f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt), }); @@ -5488,6 +5488,44 @@ 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); } + + // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. + try coff.genPending(pt); +} + +pub fn updateContainerType( + coff: *Coff, + pt: Zcu.PerThread, + ty: InternPool.Index, + success: bool, +) link.Error!void { + if (!success) return; + var lazy_it = coff.lazy.iterator(); + while (lazy_it.next()) |lazy| if (lazy.value.map.getIndex(ty)) |lmi| { + if (lazy.value.pending_index <= lmi) continue; + // This type has changed on this incremental update, so update the lazy code/data. + const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = @intCast(lmi) }; + const kind = switch (lmr.kind) { + .code => "code", + .const_data => "data", + }; + var name: [std.Progress.Node.max_name_len]u8 = undefined; + const sub_prog_node = coff.synth_prog_node.start( + std.mem.print(&name, "lazy {s} for {f}", .{ + kind, + Type.fromInterned(ty).fmt(pt), + }) catch &name, + 0, + ); + defer sub_prog_node.end(); + coff.genLazy(pt, lmr) catch |err| switch (err) { + else => |e| return e, + error.MappedFileIo => return coff.base.comp.link_diags.fail( + "linker failed to lower lazy {s}: {t}", + .{ kind, coff.mf.io_err.? }, + ), + }; + }; } pub fn lowerUav( @@ -5603,10 +5641,13 @@ fn updateFuncInner( }; si.get(coff).extra.size = @intCast(nw.interface.end); try si.applyLocationRelocs(coff); + + // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. + try coff.genPending(pt); } pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { - coff.flushLazy(pt, .{ + coff.genLazy(pt, .{ .kind = .const_data, .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), }) catch |err| switch (err) { @@ -5919,22 +5960,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { }; break :task; } - while (coff.pending_uavs.pop()) |pending_uav| { - const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key }); - defer sub_prog_node.end(); - coff.flushUav( - .{ .zcu = comp.zcu.?, .tid = tid }, - pending_uav.key, - pending_uav.value.alignment, - ) catch |err| switch (err) { - else => |e| return e, - error.MappedFileIo => return comp.link_diags.fail( - "linker failed to lower constant: {t}", - .{coff.mf.io_err.?}, - ), - }; - break :task; - } if (coff.pending_input) |pending_iami| { const name_slice = pending_iami.member(coff).name.toSlice(coff); const sub_prog_node = coff.input_prog_node.start( @@ -5983,33 +6008,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { }; break :task; } - var lazy_it = coff.lazy.iterator(); - while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { - const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; - const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; - lazy.value.pending_index += 1; - const kind = switch (lmr.kind) { - .code => "code", - .const_data => "data", - }; - var name: [std.Progress.Node.max_name_len]u8 = undefined; - const sub_prog_node = coff.synth_prog_node.start( - std.mem.print(&name, "lazy {s} for {f}", .{ - kind, - Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt), - }) catch &name, - 0, - ); - defer sub_prog_node.end(); - coff.flushLazy(pt, lmr) catch |err| switch (err) { - else => |e| return e, - error.MappedFileIo => return comp.link_diags.fail( - "linker failed to lower lazy {s}: {t}", - .{ kind, coff.mf.io_err.? }, - ), - }; - break :task; - }; if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) { defer coff.symbol_table.pending_symbol_index += 1; const si = coff.symbol_table.symbols.keys()[coff.symbol_table.pending_symbol_index]; @@ -6038,12 +6036,10 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { } if (coff.section_merge_pending_index < coff.section_merges.count()) return true; - if (coff.pending_uavs.count() > 0) return true; if (coff.pending_input != null) return true; if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true; assert(!coff.exports_complete or coff.inputs_complete); if (coff.exports_complete and coff.pending_special_symbol != .none) return true; - for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true; return false; } @@ -6153,7 +6149,47 @@ fn idleProgNode( }, 0); } -fn flushUav( +fn genPending(coff: *Coff, pt: Zcu.PerThread) Error!void { + const comp = pt.zcu.comp; + while (coff.pending_uavs.pop()) |pending_uav| { + const sub_prog_node = coff.idleProgNode(pt.tid, coff.const_prog_node, .{ .uav = pending_uav.key }); + defer sub_prog_node.end(); + coff.genUav(pt, pending_uav.key, pending_uav.value.alignment) catch |err| switch (err) { + else => |e| return e, + error.MappedFileIo => return comp.link_diags.fail( + "linker failed to lower constant: {t}", + .{coff.mf.io_err.?}, + ), + }; + } + var lazy_it = coff.lazy.iterator(); + while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { + const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; + lazy.value.pending_index += 1; + const kind = switch (lmr.kind) { + .code => "code", + .const_data => "data", + }; + var name: [std.Progress.Node.max_name_len]u8 = undefined; + const sub_prog_node = coff.synth_prog_node.start( + std.mem.print(&name, "lazy {s} for {f}", .{ + kind, + Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt), + }) catch &name, + 0, + ); + defer sub_prog_node.end(); + coff.genLazy(pt, lmr) catch |err| switch (err) { + else => |e| return e, + error.MappedFileIo => return comp.link_diags.fail( + "linker failed to lower lazy {s}: {t}", + .{ kind, coff.mf.io_err.? }, + ), + }; + }; +} + +fn genUav( coff: *Coff, pt: Zcu.PerThread, umi: Node.UavMapIndex, @@ -6311,7 +6347,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { .{ name, imp_match } else name: { try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len); - const imp_name = try std.fmt.allocPrint(gpa, imp_prefix ++ "{s}", .{name_slice}); + const imp_name = try gpa.print(imp_prefix ++ "{s}", .{name_slice}); defer gpa.free(imp_name); break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true }; }; @@ -6773,7 +6809,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol { }; } -fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { +fn genLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { const zcu = pt.zcu; const gpa = zcu.gpa; diff --git a/src/link/ConstPool.zig b/src/link/ConstPool.zig index 9cf25cd1cb690fe58acbc592e5bfe86a7f3ebd32..e2b334a83dfb51c28e4898f9e7289f1763a22c18 100644 --- a/src/link/ConstPool.zig +++ b/src/link/ConstPool.zig @@ -46,6 +46,7 @@ pub const Index = enum(u32) { pub const User = union(enum) { dwarf: *@import("Dwarf.zig"), + elf2: *@import("Elf2.zig"), c: *@import("C.zig"), llvm: @import("../codegen/llvm.zig").Object.Ptr, @@ -73,7 +74,7 @@ pub const User = union(enum) { pt: Zcu.PerThread, index: Index, val: InternPool.Index, - ) Allocator.Error!void { + ) link.Error!void { switch (user) { inline else => |impl| return impl.updateConst(pt, index, val), } @@ -89,7 +90,7 @@ pub const User = union(enum) { pt: Zcu.PerThread, index: Index, val: InternPool.Index, - ) Allocator.Error!void { + ) link.Error!void { switch (user) { inline else => |impl| return impl.updateConstIncomplete(pt, index, val), } @@ -128,7 +129,7 @@ pub fn updateContainerType( user: User, container_ty: InternPool.Index, success: bool, -) Allocator.Error!void { +) link.Error!void { if (success) { const gpa = pt.zcu.comp.gpa; try pool.complete_containers.put(gpa, container_ty, {}); @@ -160,13 +161,16 @@ pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Inde } return index; } -pub fn flushPending(pool: *ConstPool, pt: Zcu.PerThread, user: User) Allocator.Error!void { +pub fn getIfExists(pool: *ConstPool, val: InternPool.Index) ?ConstPool.Index { + return @fromBackingInt(@intCast(pool.values.getIndex(val) orelse return null)); +} +pub fn flushPending(pool: *ConstPool, pt: Zcu.PerThread, user: User) link.Error!void { while (pool.pending.pop()) |pending_ty| { try pool.update(pt, user, pending_ty); } } -fn update(pool: *ConstPool, pt: Zcu.PerThread, user: User, index: ConstPool.Index) Allocator.Error!void { +fn update(pool: *ConstPool, pt: Zcu.PerThread, user: User, index: ConstPool.Index) link.Error!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const val = index.val(pool); @@ -286,5 +290,6 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const InternPool = @import("../InternPool.zig"); +const link = @import("../link.zig"); const Type = @import("../Type.zig"); const Zcu = @import("../Zcu.zig"); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 8b937cb20d07ec3c654d95e1e44d74554f66d5f0..61882b07b38e2dca4622a1a6b05b57700f2dfb2f 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2585,7 +2585,7 @@ pub fn initWipNav( pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: link.File.SymbolId, -) error{ OutOfMemory, AlreadyReported }!WipNav { +) link.Error!WipNav { return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) { error.OutOfMemory => error.OutOfMemory, else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}), @@ -3008,7 +3008,7 @@ fn finishWipNavWriterError( try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf }); } -pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, AlreadyReported }!void { +pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) { error.OutOfMemory => error.OutOfMemory, else => |e| pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}), diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d372c2e58a9990eb17812e39b9dc3a2e4588b62b..e20eaebb39e394e7e28517ce7520b7f10fb79a5f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1677,9 +1677,7 @@ pub fn updateContainerType( ty: InternPool.Index, success: bool, ) link.Error!void { - return self.zigObjectPtr().?.updateContainerType(pt, ty, success) catch |err| switch (err) { - error.OutOfMemory => |e| return e, - }; + try self.zigObjectPtr().?.updateContainerType(pt, ty, success); } pub fn updateExports( diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 706099a25a94adaf03ff4b6ea2e414c02443b4f1..a694aa21c6fff16a98a67c484375c786154fa15f 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -174,16 +174,13 @@ uavs: std.array_hash_map.Auto(InternPool.Index, struct { first_symbol_reloc: SymbolReloc.Index, // No `first_got_reloc` field because a UAV never contains GOT relocations. }), -lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { - map: std.array_hash_map.Auto(InternPool.Index, struct { - lsi: Symbol.LocalIndex, - /// The start index of the contiguous sequence of symbol relocations in this lazy code/data. - first_symbol_reloc: SymbolReloc.Index, - /// The start index of the contiguous sequence of GOT relocations in this lazy code/data. - first_got_reloc: GotReloc.Index, - }), - pending_index: u32, -}), +lazy: std.EnumArray(link.File.LazySymbol.Kind, std.array_hash_map.Auto(link.ConstPool.Index, struct { + lsi: Symbol.LocalIndex, + /// The start index of the contiguous sequence of symbol relocations in this lazy code/data. + first_symbol_reloc: SymbolReloc.Index, + /// The start index of the contiguous sequence of GOT relocations in this lazy code/data. + first_got_reloc: GotReloc.Index, +})), pending_uavs: std.ArrayList(Node.UavMapIndex), symbol_relocs: std.ArrayList(SymbolReloc), node_relocs: std.ArrayList(NodeReloc), @@ -240,7 +237,6 @@ overflowed_reloc_count: u32, misaligned_reloc_count: u32, const_prog_node: std.Progress.Node, -synth_prog_node: std.Progress.Node, input_prog_node: std.Progress.Node, const Error = link.Error || error{MappedFileIo}; @@ -408,20 +404,23 @@ const Node = union(enum) { } fn firstSymbolReloc(lmi: @This(), elf: *const Elf) SymbolReloc.Index { - return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_symbol_reloc; + return elf.lazy.getPtrConst(kind).values()[@backingInt(lmi)].first_symbol_reloc; } fn firstGotReloc(lmi: @This(), elf: *const Elf) GotReloc.Index { - return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_got_reloc; + return elf.lazy.getPtrConst(kind).values()[@backingInt(lmi)].first_got_reloc; } }; } pub fn lazySymbol(lmr: LazyMapRef, elf: *const Elf) link.File.LazySymbol { - return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; + return .{ + .kind = lmr.kind, + .ty = elf.lazy.getPtrConst(lmr.kind).keys()[lmr.index].val(&elf.dwarf.const_pool), + }; } pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.LocalIndex { - return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index].lsi; + return elf.lazy.getPtrConst(lmr.kind).values()[lmr.index].lsi; } }; @@ -3283,21 +3282,26 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { const s: Symbol.Id = .local(lsi); return s.toTypeErased(); } -pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) link.Error!link.File.SymbolId { +pub fn lazySymbol( + elf: *Elf, + pt: Zcu.PerThread, + lazy: link.File.LazySymbol, +) link.Error!link.File.SymbolId { const diags = &elf.base.comp.link_diags; - return elf.lazySymbolInner(lazy) catch |err| switch (err) { + return elf.lazySymbolInner(pt, lazy) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), }; } -fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.SymbolId { +fn lazySymbolInner(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol) Error!link.File.SymbolId { const gpa = elf.base.comp.gpa; try elf.ensureUnusedSymbolCapacity(1, .all_local); try elf.nodes.ensureUnusedCapacity(gpa, 1); - try elf.lazy.getPtr(lazy.kind).map.ensureUnusedCapacity(gpa, 1); + try elf.lazy.getPtr(lazy.kind).ensureUnusedCapacity(gpa, 1); - const gop = elf.lazy.getPtr(lazy.kind).map.getOrPutAssumeCapacity(lazy.ty); + const cpi = try elf.dwarf.const_pool.get(pt, .{ .elf2 = elf }, lazy.ty); + const gop = elf.lazy.getPtr(lazy.kind).getOrPutAssumeCapacity(cpi); if (!gop.found_existing) { const shndx: Section.Index, const sym_type: std.elf.STT = switch (lazy.kind) { .code => .{ .text, .FUNC }, @@ -3326,7 +3330,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol .code => .{ .lazy_code = @fromBackingInt(@intCast(gop.index)) }, .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(gop.index)) }, }); - elf.synth_prog_node.increaseEstimatedTotalItems(1); + elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1); } const s: Symbol.Id = .local(gop.value_ptr.lsi); return s.toTypeErased(); @@ -3754,10 +3758,7 @@ fn create( .one_shot_fixups = .empty, .navs = .empty, .uavs = .empty, - .lazy = comptime .initFill(.{ - .map = .empty, - .pending_index = 0, - }), + .lazy = comptime .initFill(.empty), .pending_uavs = .empty, .symbol_relocs = .empty, .node_relocs = .empty, @@ -3772,7 +3773,7 @@ fn create( .dwarf => |v| v, .code_view => unreachable, }), - .dwarf_shared = .initFill(.{ + .dwarf_shared = comptime .initFill(.{ .first_target_reloc = .none, }), .dwarf_units = .empty, @@ -3784,7 +3785,6 @@ fn create( .misaligned_reloc_count = 0, .const_prog_node = .none, - .synth_prog_node = .none, .input_prog_node = .none, }; errdefer elf.deinit(); @@ -3820,7 +3820,7 @@ pub fn deinit(elf: *Elf) void { elf.one_shot_fixups.deinit(gpa); elf.navs.deinit(gpa); elf.uavs.deinit(gpa); - for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); + for (&elf.lazy.values) |*lazy| lazy.deinit(gpa); elf.pending_uavs.deinit(gpa); elf.symbol_relocs.deinit(gpa); elf.node_relocs.deinit(gpa); @@ -5087,11 +5087,6 @@ fn initHeaders( pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { prog_node.increaseEstimatedTotalItems(4); elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len); - elf.synth_prog_node = prog_node.start("Synthetics", count: { - var count: usize = 0; - for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; - break :count count; - }); elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len); elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) + (elf.input_sections.items.len - elf.input_section_pending_index)); @@ -5102,8 +5097,6 @@ pub fn endProgress(elf: *Elf) void { elf.input_prog_node = .none; elf.mf.update_prog_node.end(); elf.mf.update_prog_node = .none; - elf.synth_prog_node.end(); - elf.synth_prog_node = .none; elf.const_prog_node.end(); elf.const_prog_node = .none; } @@ -5267,8 +5260,8 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc, }, inline .lazy_code, .lazy_const_data => |lmi| .{ - .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc, - .first_got_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc, + .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).values()[lmi.ref().index].first_symbol_reloc, + .first_got_reloc = &elf.lazy.getPtr(lmi.ref().kind).values()[lmi.ref().index].first_got_reloc, }, .unit_debug_info_header => |ui| .{ .first_node_reloc = &elf.dwarf_units.items[@backingInt(ui)].debug_info_header_first_node_reloc, @@ -8452,6 +8445,73 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) try elf.genPending(pt); } +pub fn updateContainerType( + elf: *Elf, + pt: Zcu.PerThread, + ty: InternPool.Index, + success: bool, +) link.Error!void { + try elf.dwarf.const_pool.updateContainerType(pt, .{ .elf2 = elf }, ty, success); +} + +pub fn addConst( + elf: *Elf, + pt: Zcu.PerThread, + index: link.ConstPool.Index, + val: InternPool.Index, +) std.mem.Allocator.Error!void { + if (false) try elf.dwarf.addConst(pt, index, val); +} + +pub fn updateConst( + elf: *Elf, + pt: Zcu.PerThread, + cpi: link.ConstPool.Index, + val: InternPool.Index, +) link.Error!void { + if (val == .anyerror_type) return; + try elf.updateConstInner(pt, cpi, val); +} +fn updateConstInner( + elf: *Elf, + pt: Zcu.PerThread, + cpi: link.ConstPool.Index, + val: InternPool.Index, +) link.Error!void { + var lazy_it = elf.lazy.iterator(); + while (lazy_it.next()) |lazy| if (lazy.value.getIndex(cpi)) |li| { + const lazy_ty: Type = .fromInterned(cpi.val(&elf.dwarf.const_pool)); + var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; + const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(pt.zcu)) { + .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, + .error_set => switch (lazy.key) { + .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, + .const_data => "@errorName(anyerror)", + }, + else => unreachable, + }; + const prog_node = elf.base.comp.link_prog_node.start(prog_name, 0); + defer prog_node.end(); + elf.genLazy(pt, .{ .kind = lazy.key, .index = @intCast(li) }) 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.?}, + ), + }; + }; + if (false) try elf.dwarf.updateConst(pt, cpi, val); +} + +pub fn updateConstIncomplete( + elf: *Elf, + pt: Zcu.PerThread, + cpi: link.ConstPool.Index, + val: InternPool.Index, +) link.Error!void { + if (false) try elf.dwarf.updateConstIncomplete(pt, cpi, val); +} + pub fn updateFunc( elf: *Elf, pt: Zcu.PerThread, @@ -8726,16 +8786,11 @@ fn updateFuncInner( } pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) link.Error!void { - elf.genLazy(pt, .{ - .kind = .const_data, - .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), - }) 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.?}, - ), - }; + try elf.updateConstInner( + pt, + elf.dwarf.const_pool.getIfExists(.anyerror_type) orelse return, + .anyerror_type, + ); } pub fn flush( @@ -8782,8 +8837,7 @@ fn flushInner( while (try elf.idle(tid)) {} assert(elf.pending_uavs.items.len == 0); - var lazy_it = elf.lazy.iterator(); - while (lazy_it.next()) |lazy| assert(lazy.value.pending_index == lazy.value.map.count()); + assert(elf.dwarf.const_pool.pending.items.len == 0); // We've done the final `idle` loop, so everything is at its final place in the file. We have a // few more things to check and write now that addresses and offsets are finalized. @@ -8844,9 +8898,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { const diags = &comp.link_diags; assert(elf.pending_uavs.items.len == 0); - for (&elf.lazy.values) |*lazy| { - assert(lazy.pending_index == lazy.map.count()); - } + assert(elf.dwarf.const_pool.pending.items.len == 0); task: { if (elf.input_pending_index < elf.inputs.items.len) { @@ -9061,8 +9113,6 @@ fn idleProgNode( } fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { - const zcu = elf.base.comp.zcu.?; - while (elf.pending_uavs.pop()) |umi| { var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; const prog_name = std.mem.print(&prog_name_buf, "{f}", .{ @@ -9072,25 +9122,7 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { defer prog_node.end(); try elf.genUav(pt, umi); } - - var lazy_it = elf.lazy.iterator(); - while (lazy_it.next()) |lazy| while (lazy.value.pending_index < lazy.value.map.count()) { - const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; - lazy.value.pending_index += 1; - const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty); - var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; - const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) { - .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, - .error_set => switch (lmr.kind) { - .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, - .const_data => "@errorName", - }, - else => unreachable, - }; - const prog_node = elf.synth_prog_node.start(prog_name, 0); - defer prog_node.end(); - try elf.genLazy(pt, lmr); - }; + try elf.dwarf.const_pool.flushPending(pt, .{ .elf2 = elf }); } fn genUav( diff --git a/test/incremental/no_change_preserves_tag_names b/test/incremental/tag_name similarity index 66% rename from test/incremental/no_change_preserves_tag_names rename to test/incremental/tag_name index 138bd919e3d176d11556c37341b51cfba3fa0440..17954435c15786ddf98bbd576c1a2ae346ab14aa 100644 --- a/test/incremental/no_change_preserves_tag_names +++ b/test/incremental/tag_name @@ -16,3 +16,12 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } #expect_stdout="first" +#update=swap fields +#file=main.zig +const std = @import("std"); +var some_enum: enum { second, first } = .first; +const io = std.Io.Threaded.global_single_threaded.io(); +pub fn main() !void { + try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); +} +#expect_stdout="first" -- 2.54.0