From 065e10c95ccca509afecfecc849da9114e0000b2 Mon Sep 17 00:00:00 2001 From: mlugg Date: Wed, 1 Jan 2025 20:16:48 +0000 Subject: [PATCH] link: new incremental line number update API --- change_line_number | 16 ++++++++++++++++ src/Compilation.zig | 4 ++++ src/Zcu/PerThread.zig | 31 +++++++++++++++++++++++++------ src/link.zig | 27 +++++++++++++++++++++------ src/link/C.zig | 4 ++-- src/link/Coff.zig | 6 +++--- src/link/Dwarf.zig | 20 +++++--------------- src/link/Elf.zig | 4 ++-- src/link/Elf/ZigObject.zig | 17 ++--------------- src/link/MachO.zig | 4 ++-- src/link/MachO/ZigObject.zig | 9 ++------- src/link/Plan9.zig | 5 ++--- src/link/Wasm.zig | 4 ++-- src/link/Wasm/ZigObject.zig | 10 ++-------- 14 files changed, 90 insertions(+), 71 deletions(-) create mode 100644 change_line_number diff --git a/change_line_number b/change_line_number new file mode 100644 index 0000000000..c272bcb5df --- /dev/null +++ b/change_line_number @@ -0,0 +1,16 @@ +#target=x86_64-linux-selfhosted +#update=initial version +#file=main.zig +const std = @import("std"); +pub fn main() !void { + try std.io.getStdOut().writeAll("foo\n"); +} +#expect_stdout="foo\n" +#update=change line number +#file=main.zig +const std = @import("std"); + +pub fn main() !void { + try std.io.getStdOut().writeAll("foo\n"); +} +#expect_stdout="foo\n" diff --git a/src/Compilation.zig b/src/Compilation.zig index 4a32b3c457..fc2e25febf 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -348,6 +348,7 @@ const Job = union(enum) { /// Corresponds to the task in `link.Task`. /// Only needed for backends that haven't yet been updated to not race against Sema. codegen_type: InternPool.Index, + update_line_number: InternPool.TrackedInst.Index, /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed. /// This may be its first time being analyzed, or it may be outdated. /// If the unit is a function, a `codegen_func` job will then be queued. @@ -3718,6 +3719,9 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre .codegen_type => |ty| { comp.dispatchCodegenTask(tid, .{ .codegen_type = ty }); }, + .update_line_number => |ti| { + comp.dispatchCodegenTask(tid, .{ .update_line_number = ti }); + }, .analyze_func => |func| { const named_frame = tracy.namedFrame("analyze_func"); defer named_frame.end(); diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 854e27ae9b..9619986e6c 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -379,6 +379,7 @@ fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnman pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { assert(pt.tid == .main); const zcu = pt.zcu; + const comp = zcu.comp; const ip = &zcu.intern_pool; const gpa = zcu.gpa; @@ -435,8 +436,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { const old_zir = file.prev_zir.?.*; const new_zir = file.zir; - const old_tag = old_zir.instructions.items(.tag); - const old_data = old_zir.instructions.items(.data); + const old_tag = old_zir.instructions.items(.tag)[@intFromEnum(old_inst)]; + const old_data = old_zir.instructions.items(.data)[@intFromEnum(old_inst)]; + + switch (old_tag) { + .declaration => { + const old_line = old_zir.getDeclaration(old_inst).src_line; + const new_line = new_zir.getDeclaration(new_inst).src_line; + if (old_line != new_line) { + try comp.queueJob(.{ .update_line_number = tracked_inst_index }); + } + }, + else => {}, + } if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { if (new_zir.getAssociatedSrcHash(new_inst)) |new_hash| { @@ -455,8 +467,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { } // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. - const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { - .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { + const has_namespace = switch (old_tag) { + .extended => switch (old_data.extended.opcode) { .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, else => false, }, @@ -2517,8 +2529,6 @@ const ScanDeclIter = struct { ); try comp.queueJob(.{ .analyze_comptime_unit = unit }); } - - // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live. } }; @@ -3152,6 +3162,15 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void } } +pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Index) !void { + if (pt.zcu.comp.bin_file) |lf| { + lf.updateLineNumber(pt, ti) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| log.err("update line number failed: {s}", .{@errorName(e)}), + }; + } +} + pub fn reportRetryableAstGenError( pt: Zcu.PerThread, src: Zcu.AstGenSrc, diff --git a/src/link.zig b/src/link.zig index 58c5cf35af..fd1ef7ce33 100644 --- a/src/link.zig +++ b/src/link.zig @@ -727,16 +727,22 @@ pub const File = struct { } } - pub fn updateNavLineNumber( - base: *File, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, - ) UpdateNavError!void { + /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because + /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`. + pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateNavError!void { + { + const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?; + const file = pt.zcu.fileByIndex(ti.file); + assert(file.zir_loaded); + const inst = file.zir.instructions.get(@intFromEnum(ti.inst)); + assert(inst.tag == .declaration); + } + switch (base.tag) { .spirv, .nvptx => {}, inline else => |tag| { dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNavineNumber(pt, nav_index); + return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); }, } } @@ -1407,6 +1413,8 @@ pub const Task = union(enum) { codegen_func: CodegenFunc, codegen_type: InternPool.Index, + update_line_number: InternPool.TrackedInst.Index, + pub const CodegenFunc = struct { /// This will either be a non-generic `func_decl` or a `func_instance`. func: InternPool.Index, @@ -1558,6 +1566,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { error.OutOfMemory => diags.setAllocFailure(), }; }, + .update_line_number => |ti| { + const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); + defer pt.deactivate(); + pt.linkerUpdateLineNumber(ti) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + }; + }, } } diff --git a/src/link/C.zig b/src/link/C.zig index d84f29eb4b..88b0839b85 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -379,12 +379,12 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ! gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items); } -pub fn updateNavLineNumber(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { +pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { // The C backend does not have the ability to fix line numbers without re-generating // the entire Decl. _ = self; _ = pt; - _ = nav_index; + _ = ti_id; } pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f13863cfb9..6ce9924045 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -2484,11 +2484,11 @@ pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8 return global_index; } -pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { +pub fn updateLineNumber(coff: *Coff, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { _ = coff; _ = pt; - _ = decl_index; - log.debug("TODO implement updateDeclLineNumber", .{}); + _ = ti_id; + log.debug("TODO implement updateLineNumber", .{}); } /// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 5af6f80410..614aa3bdbb 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4156,21 +4156,11 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP } } -pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void { - const ip = &zcu.intern_pool; - - const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index; - const inst_info = zir_index.resolveFull(ip).?; - assert(inst_info.inst != .main_struct_inst); - const file = zcu.fileByIndex(inst_info.file); - - const line = file.zir.getDeclaration(inst_info.inst).src_line; - var line_buf: [4]u8 = undefined; - std.mem.writeInt(u32, &line_buf, line, dwarf.endian); - - const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?); - const entry = unit.getEntry(dwarf.navs.get(nav_index).?); - try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf)); +pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, ti_id: InternPool.TrackedInst.Index) UpdateError!void { + _ = dwarf; + _ = zcu; + _ = ti_id; + @panic("TODO: Dwarf.updateLineNumber"); } pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ca7a46c4bb..4e6bab756c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2372,9 +2372,9 @@ pub fn updateExports( return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices); } -pub fn updateNavLineNumber(self: *Elf, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void { +pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (self.llvm_object) |_| return; - return self.zigObjectPtr().?.updateNavLineNumber(pt, nav); + return self.zigObjectPtr().?.updateLineNumber(pt, ti_id); } pub fn deleteExport( diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 5a2a7a8009..5081e3bf2f 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1863,22 +1863,9 @@ pub fn updateExports( } } -/// Must be called only after a successful call to `updateNav`. -pub fn updateNavLineNumber( - self: *ZigObject, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, -) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const ip = &pt.zcu.intern_pool; - const nav = ip.getNav(nav_index); - - log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index }); - +pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (self.dwarf) |*dwarf| { - try dwarf.updateNavLineNumber(pt.zcu, nav_index); + try dwarf.updateLineNumber(pt.zcu, ti_id); } } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8bec62420b..3a3710aed8 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -3014,9 +3014,9 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !vo return self.getZigObject().?.updateNav(self, pt, nav); } -pub fn updateNavLineNumber(self: *MachO, pt: Zcu.PerThread, nav: InternPool.NavIndex) !void { +pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (self.llvm_object) |_| return; - return self.getZigObject().?.updateNavLineNumber(pt, nav); + return self.getZigObject().?.updateLineNumber(pt, ti_id); } pub fn updateExports( diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 511cb6839d..126b8ff509 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -1432,14 +1432,9 @@ fn updateLazySymbol( try macho_file.base.file.?.pwriteAll(code, file_offset); } -/// Must be called only after a successful call to `updateNav`. -pub fn updateNavLineNumber( - self: *ZigObject, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, -) !void { +pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (self.dwarf) |*dwarf| { - try dwarf.updateNavLineNumber(pt.zcu, nav_index); + try dwarf.updateLineNumber(pt.zcu, ti_id); } } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 8e27e20ec7..31aac2486e 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -1354,11 +1354,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { } } -/// Must be called only after a successful call to `updateDecl`. -pub fn updateDeclLineNumber(self: *Plan9, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void { +pub fn updateLineNumber(self: *Plan9, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { _ = self; _ = pt; - _ = decl_index; + _ = ti_id; } pub fn getNavVAddr( diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 7d00aa5a64..ec13a75f2c 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1574,9 +1574,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi try wasm.zig_object.?.updateNav(wasm, pt, nav); } -pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void { +pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (wasm.llvm_object) |_| return; - try wasm.zig_object.?.updateNavLineNumber(pt, nav); + try wasm.zig_object.?.updateLineNumber(pt, ti_id); } /// From a given symbol location, returns its `wasm.GlobalType`. diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 09d7647730..f2bce777ed 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -1074,15 +1074,9 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *? return atom_index; } -pub fn updateDeclLineNumber( - zig_object: *ZigObject, - pt: Zcu.PerThread, - decl_index: InternPool.DeclIndex, -) !void { +pub fn updateLineNumber(zig_object: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { if (zig_object.dwarf) |*dw| { - const decl = pt.zcu.declPtr(decl_index); - log.debug("updateDeclLineNumber {}{*}", .{ decl.fqn.fmt(&pt.zcu.intern_pool), decl }); - try dw.updateDeclLineNumber(pt.zcu, decl_index); + try dw.updateLineNumber(pt.zcu, ti_id); } }