From 6561a98a61bb54c9d6c868f788da3eaa6f48d2c3 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sun, 20 Apr 2025 02:01:46 +0100 Subject: incremental: correctly handle dead exporters Resolves: #23604 --- src/Zcu/PerThread.zig | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 095cd6c1cb..9084e8b0ca 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -2837,6 +2837,11 @@ pub fn processExports(pt: Zcu.PerThread) !void { const zcu = pt.zcu; const gpa = zcu.gpa; + if (zcu.single_exports.count() == 0 and zcu.multi_exports.count() == 0) { + // We can avoid a call to `resolveReferences` in this case. + return; + } + // First, construct a mapping of every exported value and Nav to the indices of all its different exports. var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; @@ -2857,8 +2862,18 @@ pub fn processExports(pt: Zcu.PerThread) !void { // So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization. try nav_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count()); - for (zcu.single_exports.values()) |export_idx| { + const unit_references = try zcu.resolveReferences(); + + for (zcu.single_exports.keys(), zcu.single_exports.values()) |exporter, export_idx| { const exp = export_idx.ptr(zcu); + if (!unit_references.contains(exporter)) { + // This export might already have been sent to the linker on a previous update, in which case we need to delete it. + // The linker export API should be modified to eliminate this call. #23616 + if (zcu.comp.bin_file) |lf| { + lf.deleteExport(exp.exported, exp.opts.name); + } + continue; + } const value_ptr, const found_existing = switch (exp.exported) { .nav => |nav| gop: { const gop = try nav_exports.getOrPut(gpa, nav); @@ -2873,8 +2888,19 @@ pub fn processExports(pt: Zcu.PerThread) !void { try value_ptr.append(gpa, export_idx); } - for (zcu.multi_exports.values()) |info| { - for (zcu.all_exports.items[info.index..][0..info.len], info.index..) |exp, export_idx| { + for (zcu.multi_exports.keys(), zcu.multi_exports.values()) |exporter, info| { + const exports = zcu.all_exports.items[info.index..][0..info.len]; + if (!unit_references.contains(exporter)) { + // This export might already have been sent to the linker on a previous update, in which case we need to delete it. + // The linker export API should be modified to eliminate this loop. #23616 + if (zcu.comp.bin_file) |lf| { + for (exports) |exp| { + lf.deleteExport(exp.exported, exp.opts.name); + } + } + continue; + } + for (exports, info.index..) |exp, export_idx| { const value_ptr, const found_existing = switch (exp.exported) { .nav => |nav| gop: { const gop = try nav_exports.getOrPut(gpa, nav); -- cgit v1.2.3