authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-31 05:42:43-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 11:00:54-04:00
log91d8b7b8dc04aecea1a4fa7c6c6bc0696ebdada4
tree242ab4f7fec35e9bedded349068ba8edbfac2699
parentc5c037808e30d2c632bd3bd08ed17eef7fdd373e

Zcu: notify the linker once source files have been scanned


3 files changed, 41 insertions(+), 13 deletions(-)

src/Zcu/PerThread.zig+2
...@@ -258,6 +258,8 @@ pub fn update(...@@ -258,6 +258,8 @@ pub fn update(
258 return;258 return;
259 }259 }
260260
261 try comp.link_queue.enqueueZcu(comp, pt.tid, .files_ready);
262
261 if (comp.config.incremental) {263 if (comp.config.incremental) {
262 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);264 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
263 defer update_zir_refs_node.end();265 defer update_zir_refs_node.end();
src/link.zig+35-13
...@@ -794,6 +794,28 @@ pub const File = struct {...@@ -794,6 +794,28 @@ pub const File = struct {
794 }794 }
795 }795 }
796796
797 /// When there is a ZCU, this is called exactly once per update, to indicate that all per-file
798 /// state (e.g. `Zcu.alive_files`) has been populated by the frontend, so can now be safely
799 /// accessed by the linker.
800 ///
801 /// This call occurs before any call to any of these functions:
802 /// * `updateNav`
803 /// * `updateFunc`
804 /// * `updateContainerType`
805 /// * `updateLineNumber`
806 ///
807 /// Asserts that the ZCU is not using the LLVM backend.
808 fn zcuFilesReady(base: *File) Error!void {
809 assert(base.comp.zcu.?.llvm_object == null);
810 switch (base.tag) {
811 else => {},
812 inline .elf2 => |tag| {
813 dev.check(tag.devFeature());
814 return @as(*tag.Type(), @fieldParentPtr("base", base)).zcuFilesReady();
815 },
816 }
817 }
818
797 /// Asserts that the ZCU is not using the LLVM backend.819 /// Asserts that the ZCU is not using the LLVM backend.
798 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {820 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Error!void {
799 assert(base.comp.zcu.?.llvm_object == null);821 assert(base.comp.zcu.?.llvm_object == null);
...@@ -823,19 +845,6 @@ pub const File = struct {...@@ -823,19 +845,6 @@ pub const File = struct {
823 }845 }
824 }846 }
825847
826 /// Never called when LLVM is codegenning the ZCU.
827 fn clearContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) Error!void {
828 assert(base.comp.zcu.?.llvm_object == null);
829 switch (base.tag) {
830 .lld => unreachable,
831 else => {},
832 inline .elf => |tag| {
833 dev.check(tag.devFeature());
834 return @as(*tag.Type(), @fieldParentPtr("base", base)).clearContainerType(pt, ty);
835 },
836 }
837 }
838
839 /// The active tag of `mir` is determined by the backend used for the module this function is in.848 /// The active tag of `mir` is determined by the backend used for the module this function is in.
840 /// Never called when LLVM is codegenning the ZCU.849 /// Never called when LLVM is codegenning the ZCU.
841 fn updateFunc(850 fn updateFunc(
...@@ -1417,6 +1426,9 @@ pub const PrelinkTask = union(enum) {...@@ -1417,6 +1426,9 @@ pub const PrelinkTask = union(enum) {
1417 load_dso: Path,1426 load_dso: Path,
1418};1427};
1419pub const ZcuTask = union(enum) {1428pub const ZcuTask = union(enum) {
1429 /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file
1430 /// state (e.g. `Zcu.alive_files`) is populated so can now be safely accessed by the linker.
1431 files_ready,
1420 /// Write the constant value for a Decl to the output file.1432 /// Write the constant value for a Decl to the output file.
1421 link_nav: InternPool.Nav.Index,1433 link_nav: InternPool.Nav.Index,
1422 /// Write the machine code for a function to the output file.1434 /// Write the machine code for a function to the output file.
...@@ -1620,6 +1632,16 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void...@@ -1620,6 +1632,16 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
1620 var timer = comp.startTimer();1632 var timer = comp.startTimer();
16211633
1622 const maybe_nav: ?InternPool.Nav.Index = switch (task) {1634 const maybe_nav: ?InternPool.Nav.Index = switch (task) {
1635 .files_ready => {
1636 if (zcu.llvm_object != null) return;
1637 const lf = comp.bin_file orelse return;
1638 lf.zcuFilesReady() catch |err| switch (err) {
1639 error.Canceled => io.recancel(),
1640 error.AlreadyReported => return,
1641 error.OutOfMemory => return diags.setAllocFailure(),
1642 };
1643 return;
1644 },
1623 .link_nav => |nav_index| nav: {1645 .link_nav => |nav_index| nav: {
1624 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);1646 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
1625 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);1647 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);
src/link/Elf2.zig+4
...@@ -7148,6 +7148,10 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -7148,6 +7148,10 @@ fn prelinkInner(elf: *Elf) Error!void {
7148 }7148 }
7149}7149}
71507150
7151pub fn zcuFilesReady(elf: *Elf) link.Error!void {
7152 _ = elf; // TODO jacobly
7153}
7154
7151fn prepareDynamic(elf: *Elf) Error!void {7155fn prepareDynamic(elf: *Elf) Error!void {
7152 const comp = elf.base.comp;7156 const comp = elf.base.comp;
71537157