authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-20 19:36:50-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
logd1cde847a367c526c63d65714583189fa2912731
tree96f1c2f65c9fe7f84381356e733f14b1341e328b
parent694b129d8960a9c3548dccb2a8f0c82f44fbafa9

implement the prelink phase in the frontend

this strategy uses a "postponed" queue to handle codegen tasks that spawn too early. there's probably a better way.

4 files changed, 110 insertions(+), 23 deletions(-)

src/Compilation.zig+34-3
...@@ -113,6 +113,12 @@ link_diags: link.Diags,...@@ -113,6 +113,12 @@ link_diags: link.Diags,
113link_task_queue: ThreadSafeQueue(link.Task) = .empty,113link_task_queue: ThreadSafeQueue(link.Task) = .empty,
114/// Ensure only 1 simultaneous call to `flushTaskQueue`.114/// Ensure only 1 simultaneous call to `flushTaskQueue`.
115link_task_queue_safety: std.debug.SafetyLock = .{},115link_task_queue_safety: std.debug.SafetyLock = .{},
116/// If any tasks are queued up that depend on prelink being finished, they are moved
117/// here until prelink finishes.
118link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,
119/// Initialized with how many link input tasks are expected. After this reaches zero
120/// the linker will begin the prelink phase.
121remaining_prelink_tasks: u32,
116122
117work_queues: [123work_queues: [
118 len: {124 len: {
...@@ -1515,6 +1521,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1515,6 +1521,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1515 .file_system_inputs = options.file_system_inputs,1521 .file_system_inputs = options.file_system_inputs,
1516 .parent_whole_cache = options.parent_whole_cache,1522 .parent_whole_cache = options.parent_whole_cache,
1517 .link_diags = .init(gpa),1523 .link_diags = .init(gpa),
1524 .remaining_prelink_tasks = 0,
1518 };1525 };
15191526
1520 // Prevent some footguns by making the "any" fields of config reflect1527 // Prevent some footguns by making the "any" fields of config reflect
...@@ -1780,10 +1787,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1780,10 +1787,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1780 inline for (fields) |field| {1787 inline for (fields) |field| {
1781 if (@field(paths, field.name)) |path| {1788 if (@field(paths, field.name)) |path| {
1782 comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path });1789 comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path });
1790 comp.remaining_prelink_tasks += 1;
1783 }1791 }
1784 }1792 }
1785 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`.1793 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`.
1786 comp.link_task_queue.shared.appendAssumeCapacity(.load_host_libc);1794 comp.link_task_queue.shared.appendAssumeCapacity(.load_host_libc);
1795 comp.remaining_prelink_tasks += 1;
1787 } else if (target.isMusl() and !target.isWasm()) {1796 } else if (target.isMusl() and !target.isWasm()) {
1788 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1797 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
17891798
...@@ -1792,14 +1801,17 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1792,14 +1801,17 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1792 .{ .musl_crt_file = .crti_o },1801 .{ .musl_crt_file = .crti_o },
1793 .{ .musl_crt_file = .crtn_o },1802 .{ .musl_crt_file = .crtn_o },
1794 });1803 });
1804 comp.remaining_prelink_tasks += 2;
1795 }1805 }
1796 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {1806 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {
1797 try comp.queueJobs(&.{.{ .musl_crt_file = f }});1807 try comp.queueJobs(&.{.{ .musl_crt_file = f }});
1808 comp.remaining_prelink_tasks += 1;
1798 }1809 }
1799 try comp.queueJobs(&.{.{ .musl_crt_file = switch (comp.config.link_mode) {1810 try comp.queueJobs(&.{.{ .musl_crt_file = switch (comp.config.link_mode) {
1800 .static => .libc_a,1811 .static => .libc_a,
1801 .dynamic => .libc_so,1812 .dynamic => .libc_so,
1802 } }});1813 } }});
1814 comp.remaining_prelink_tasks += 1;
1803 } else if (target.isGnuLibC()) {1815 } else if (target.isGnuLibC()) {
1804 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1816 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18051817
...@@ -1808,14 +1820,18 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1808,14 +1820,18 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1808 .{ .glibc_crt_file = .crti_o },1820 .{ .glibc_crt_file = .crti_o },
1809 .{ .glibc_crt_file = .crtn_o },1821 .{ .glibc_crt_file = .crtn_o },
1810 });1822 });
1823 comp.remaining_prelink_tasks += 2;
1811 }1824 }
1812 if (glibc.needsCrt0(comp.config.output_mode)) |f| {1825 if (glibc.needsCrt0(comp.config.output_mode)) |f| {
1813 try comp.queueJobs(&.{.{ .glibc_crt_file = f }});1826 try comp.queueJobs(&.{.{ .glibc_crt_file = f }});
1827 comp.remaining_prelink_tasks += 1;
1814 }1828 }
1815 try comp.queueJobs(&[_]Job{1829 try comp.queueJobs(&[_]Job{
1816 .{ .glibc_shared_objects = {} },1830 .{ .glibc_shared_objects = {} },
1817 .{ .glibc_crt_file = .libc_nonshared_a },1831 .{ .glibc_crt_file = .libc_nonshared_a },
1818 });1832 });
1833 comp.remaining_prelink_tasks += 1;
1834 comp.remaining_prelink_tasks += glibc.sharedObjectsCount(&target);
1819 } else if (target.isWasm() and target.os.tag == .wasi) {1835 } else if (target.isWasm() and target.os.tag == .wasi) {
1820 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1836 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18211837
...@@ -1823,11 +1839,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1823,11 +1839,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1823 try comp.queueJob(.{1839 try comp.queueJob(.{
1824 .wasi_libc_crt_file = crt_file,1840 .wasi_libc_crt_file = crt_file,
1825 });1841 });
1842 comp.remaining_prelink_tasks += 1;
1826 }1843 }
1827 try comp.queueJobs(&[_]Job{1844 try comp.queueJobs(&[_]Job{
1828 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) },1845 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) },
1829 .{ .wasi_libc_crt_file = .libc_a },1846 .{ .wasi_libc_crt_file = .libc_a },
1830 });1847 });
1848 comp.remaining_prelink_tasks += 2;
1831 } else if (target.isMinGW()) {1849 } else if (target.isMinGW()) {
1832 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1850 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18331851
...@@ -1836,6 +1854,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1836,6 +1854,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1836 .{ .mingw_crt_file = .mingw32_lib },1854 .{ .mingw_crt_file = .mingw32_lib },
1837 crt_job,1855 crt_job,
1838 });1856 });
1857 comp.remaining_prelink_tasks += 2;
18391858
1840 // When linking mingw-w64 there are some import libs we always need.1859 // When linking mingw-w64 there are some import libs we always need.
1841 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);1860 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
...@@ -1847,6 +1866,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1847,6 +1866,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1847 }1866 }
1848 } else if (target.os.tag == .freestanding and capable_of_building_zig_libc) {1867 } else if (target.os.tag == .freestanding and capable_of_building_zig_libc) {
1849 try comp.queueJob(.{ .zig_libc = {} });1868 try comp.queueJob(.{ .zig_libc = {} });
1869 comp.remaining_prelink_tasks += 1;
1850 } else {1870 } else {
1851 return error.LibCUnavailable;1871 return error.LibCUnavailable;
1852 }1872 }
...@@ -1858,16 +1878,20 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1858,16 +1878,20 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1858 for (0..count) |i| {1878 for (0..count) |i| {
1859 try comp.queueJob(.{ .windows_import_lib = i });1879 try comp.queueJob(.{ .windows_import_lib = i });
1860 }1880 }
1881 comp.remaining_prelink_tasks += @intCast(count);
1861 }1882 }
1862 if (comp.wantBuildLibUnwindFromSource()) {1883 if (comp.wantBuildLibUnwindFromSource()) {
1863 try comp.queueJob(.{ .libunwind = {} });1884 try comp.queueJob(.{ .libunwind = {} });
1885 comp.remaining_prelink_tasks += 1;
1864 }1886 }
1865 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {1887 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {
1866 try comp.queueJob(.libcxx);1888 try comp.queueJob(.libcxx);
1867 try comp.queueJob(.libcxxabi);1889 try comp.queueJob(.libcxxabi);
1890 comp.remaining_prelink_tasks += 2;
1868 }1891 }
1869 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) {1892 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) {
1870 try comp.queueJob(.libtsan);1893 try comp.queueJob(.libtsan);
1894 comp.remaining_prelink_tasks += 1;
1871 }1895 }
18721896
1873 if (target.isMinGW() and comp.config.any_non_single_threaded) {1897 if (target.isMinGW() and comp.config.any_non_single_threaded) {
...@@ -1886,21 +1910,25 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1886,21 +1910,25 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1886 if (is_exe_or_dyn_lib) {1910 if (is_exe_or_dyn_lib) {
1887 log.debug("queuing a job to build compiler_rt_lib", .{});1911 log.debug("queuing a job to build compiler_rt_lib", .{});
1888 comp.job_queued_compiler_rt_lib = true;1912 comp.job_queued_compiler_rt_lib = true;
1913 comp.remaining_prelink_tasks += 1;
1889 } else if (output_mode != .Obj) {1914 } else if (output_mode != .Obj) {
1890 log.debug("queuing a job to build compiler_rt_obj", .{});1915 log.debug("queuing a job to build compiler_rt_obj", .{});
1891 // In this case we are making a static library, so we ask1916 // In this case we are making a static library, so we ask
1892 // for a compiler-rt object to put in it.1917 // for a compiler-rt object to put in it.
1893 comp.job_queued_compiler_rt_obj = true;1918 comp.job_queued_compiler_rt_obj = true;
1919 comp.remaining_prelink_tasks += 1;
1894 }1920 }
1895 }1921 }
18961922
1897 if (is_exe_or_dyn_lib and comp.config.any_fuzz and capable_of_building_compiler_rt) {1923 if (is_exe_or_dyn_lib and comp.config.any_fuzz and capable_of_building_compiler_rt) {
1898 log.debug("queuing a job to build libfuzzer", .{});1924 log.debug("queuing a job to build libfuzzer", .{});
1899 comp.job_queued_fuzzer_lib = true;1925 comp.job_queued_fuzzer_lib = true;
1926 comp.remaining_prelink_tasks += 1;
1900 }1927 }
1901 }1928 }
19021929
1903 try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);1930 try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);
1931 comp.remaining_prelink_tasks += 1;
1904 }1932 }
19051933
1906 return comp;1934 return comp;
...@@ -1977,6 +2005,7 @@ pub fn destroy(comp: *Compilation) void {...@@ -1977,6 +2005,7 @@ pub fn destroy(comp: *Compilation) void {
19772005
1978 comp.link_diags.deinit();2006 comp.link_diags.deinit();
1979 comp.link_task_queue.deinit(gpa);2007 comp.link_task_queue.deinit(gpa);
2008 comp.link_task_queue_postponed.deinit(gpa);
19802009
1981 comp.clearMiscFailures();2010 comp.clearMiscFailures();
19822011
...@@ -3528,9 +3557,9 @@ pub fn performAllTheWork(...@@ -3528,9 +3557,9 @@ pub fn performAllTheWork(
35283557
3529 defer if (comp.zcu) |zcu| {3558 defer if (comp.zcu) |zcu| {
3530 zcu.sema_prog_node.end();3559 zcu.sema_prog_node.end();
3531 zcu.sema_prog_node = std.Progress.Node.none;3560 zcu.sema_prog_node = .none;
3532 zcu.codegen_prog_node.end();3561 zcu.codegen_prog_node.end();
3533 zcu.codegen_prog_node = std.Progress.Node.none;3562 zcu.codegen_prog_node = .none;
35343563
3535 zcu.generation += 1;3564 zcu.generation += 1;
3536 };3565 };
...@@ -3663,7 +3692,7 @@ fn performAllTheWorkInner(...@@ -3663,7 +3692,7 @@ fn performAllTheWorkInner(
3663 try zcu.flushRetryableFailures();3692 try zcu.flushRetryableFailures();
36643693
3665 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);3694 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
3666 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);3695 zcu.codegen_prog_node = if (comp.bin_file != null) main_progress_node.start("Code Generation", 0) else .none;
3667 }3696 }
36683697
3669 if (!comp.separateCodegenThreadOk()) {3698 if (!comp.separateCodegenThreadOk()) {
...@@ -3693,6 +3722,8 @@ fn performAllTheWorkInner(...@@ -3693,6 +3722,8 @@ fn performAllTheWorkInner(
3693 });3722 });
3694 continue;3723 continue;
3695 }3724 }
3725 zcu.sema_prog_node.end();
3726 zcu.sema_prog_node = .none;
3696 }3727 }
3697 break;3728 break;
3698 }3729 }
src/glibc.zig+12
...@@ -1217,6 +1217,18 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -1217,6 +1217,18 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
1217 });1217 });
1218}1218}
12191219
1220pub fn sharedObjectsCount(target: *const std.Target) u8 {
1221 const target_version = target.os.versionRange().gnuLibCVersion() orelse return 0;
1222 var count: u8 = 0;
1223 for (libs) |lib| {
1224 if (lib.removed_in) |rem_in| {
1225 if (target_version.order(rem_in) != .lt) continue;
1226 }
1227 count += 1;
1228 }
1229 return count;
1230}
1231
1220fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {1232fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
1221 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;1233 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;
12221234
src/link.zig+60-18
...@@ -364,6 +364,7 @@ pub const File = struct {...@@ -364,6 +364,7 @@ pub const File = struct {
364 build_id: std.zig.BuildId,364 build_id: std.zig.BuildId,
365 allow_shlib_undefined: bool,365 allow_shlib_undefined: bool,
366 stack_size: u64,366 stack_size: u64,
367 post_prelink: bool = false,
367368
368 /// Prevents other processes from clobbering files in the output directory369 /// Prevents other processes from clobbering files in the output directory
369 /// of this linking operation.370 /// of this linking operation.
...@@ -780,6 +781,8 @@ pub const File = struct {...@@ -780,6 +781,8 @@ pub const File = struct {
780 return;781 return;
781 }782 }
782783
784 assert(base.post_prelink);
785
783 const use_lld = build_options.have_llvm and comp.config.use_lld;786 const use_lld = build_options.have_llvm and comp.config.use_lld;
784 const output_mode = comp.config.output_mode;787 const output_mode = comp.config.output_mode;
785 const link_mode = comp.config.link_mode;788 const link_mode = comp.config.link_mode;
...@@ -1007,7 +1010,8 @@ pub const File = struct {...@@ -1007,7 +1010,8 @@ pub const File = struct {
10071010
1008 /// Called when all linker inputs have been sent via `loadInput`. After1011 /// Called when all linker inputs have been sent via `loadInput`. After
1009 /// this, `loadInput` will not be called anymore.1012 /// this, `loadInput` will not be called anymore.
1010 pub fn prelink(base: *File) FlushError!void {1013 pub fn prelink(base: *File, prog_node: std.Progress.Node) FlushError!void {
1014 assert(!base.post_prelink);
1011 const use_lld = build_options.have_llvm and base.comp.config.use_lld;1015 const use_lld = build_options.have_llvm and base.comp.config.use_lld;
1012 if (use_lld) return;1016 if (use_lld) return;
10131017
...@@ -1019,7 +1023,7 @@ pub const File = struct {...@@ -1019,7 +1023,7 @@ pub const File = struct {
1019 switch (base.tag) {1023 switch (base.tag) {
1020 inline .wasm => |tag| {1024 inline .wasm => |tag| {
1021 dev.check(tag.devFeature());1025 dev.check(tag.devFeature());
1022 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink();1026 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(prog_node);
1023 },1027 },
1024 else => {},1028 else => {},
1025 }1029 }
...@@ -1326,12 +1330,32 @@ pub const File = struct {...@@ -1326,12 +1330,32 @@ pub const File = struct {
1326/// from the rest of compilation. All tasks performed here are1330/// from the rest of compilation. All tasks performed here are
1327/// single-threaded with respect to one another.1331/// single-threaded with respect to one another.
1328pub fn flushTaskQueue(tid: usize, comp: *Compilation) void {1332pub fn flushTaskQueue(tid: usize, comp: *Compilation) void {
1333 const diags = &comp.link_diags;
1329 // As soon as check() is called, another `flushTaskQueue` call could occur,1334 // As soon as check() is called, another `flushTaskQueue` call could occur,
1330 // so the safety lock must go after the check.1335 // so the safety lock must go after the check.
1331 while (comp.link_task_queue.check()) |tasks| {1336 while (comp.link_task_queue.check()) |tasks| {
1332 comp.link_task_queue_safety.lock();1337 comp.link_task_queue_safety.lock();
1333 defer comp.link_task_queue_safety.unlock();1338 defer comp.link_task_queue_safety.unlock();
1339
1340 if (comp.remaining_prelink_tasks > 0) {
1341 comp.link_task_queue_postponed.ensureUnusedCapacity(comp.gpa, tasks.len) catch |err| switch (err) {
1342 error.OutOfMemory => return diags.setAllocFailure(),
1343 };
1344 }
1345
1334 for (tasks) |task| doTask(comp, tid, task);1346 for (tasks) |task| doTask(comp, tid, task);
1347
1348 if (comp.remaining_prelink_tasks == 0) {
1349 if (comp.bin_file) |base| if (!base.post_prelink) {
1350 base.prelink(comp.work_queue_progress_node) catch |err| switch (err) {
1351 error.OutOfMemory => diags.setAllocFailure(),
1352 error.LinkFailure => continue,
1353 };
1354 base.post_prelink = true;
1355 for (comp.link_task_queue_postponed.items) |task| doTask(comp, tid, task);
1356 comp.link_task_queue_postponed.clearRetainingCapacity();
1357 };
1358 }
1335 }1359 }
1336}1360}
13371361
...@@ -1375,6 +1399,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1375,6 +1399,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1375 const diags = &comp.link_diags;1399 const diags = &comp.link_diags;
1376 switch (task) {1400 switch (task) {
1377 .load_explicitly_provided => if (comp.bin_file) |base| {1401 .load_explicitly_provided => if (comp.bin_file) |base| {
1402 comp.remaining_prelink_tasks -= 1;
1378 const prog_node = comp.work_queue_progress_node.start("Parse Linker Inputs", comp.link_inputs.len);1403 const prog_node = comp.work_queue_progress_node.start("Parse Linker Inputs", comp.link_inputs.len);
1379 defer prog_node.end();1404 defer prog_node.end();
1380 for (comp.link_inputs) |input| {1405 for (comp.link_inputs) |input| {
...@@ -1392,6 +1417,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1392,6 +1417,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1392 }1417 }
1393 },1418 },
1394 .load_host_libc => if (comp.bin_file) |base| {1419 .load_host_libc => if (comp.bin_file) |base| {
1420 comp.remaining_prelink_tasks -= 1;
1395 const prog_node = comp.work_queue_progress_node.start("Linker Parse Host libc", 0);1421 const prog_node = comp.work_queue_progress_node.start("Linker Parse Host libc", 0);
1396 defer prog_node.end();1422 defer prog_node.end();
13971423
...@@ -1451,6 +1477,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1451,6 +1477,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1451 }1477 }
1452 },1478 },
1453 .load_object => |path| if (comp.bin_file) |base| {1479 .load_object => |path| if (comp.bin_file) |base| {
1480 comp.remaining_prelink_tasks -= 1;
1454 const prog_node = comp.work_queue_progress_node.start("Linker Parse Object", 0);1481 const prog_node = comp.work_queue_progress_node.start("Linker Parse Object", 0);
1455 defer prog_node.end();1482 defer prog_node.end();
1456 base.openLoadObject(path) catch |err| switch (err) {1483 base.openLoadObject(path) catch |err| switch (err) {
...@@ -1459,6 +1486,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1459,6 +1486,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1459 };1486 };
1460 },1487 },
1461 .load_archive => |path| if (comp.bin_file) |base| {1488 .load_archive => |path| if (comp.bin_file) |base| {
1489 comp.remaining_prelink_tasks -= 1;
1462 const prog_node = comp.work_queue_progress_node.start("Linker Parse Archive", 0);1490 const prog_node = comp.work_queue_progress_node.start("Linker Parse Archive", 0);
1463 defer prog_node.end();1491 defer prog_node.end();
1464 base.openLoadArchive(path, null) catch |err| switch (err) {1492 base.openLoadArchive(path, null) catch |err| switch (err) {
...@@ -1467,6 +1495,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1467,6 +1495,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1467 };1495 };
1468 },1496 },
1469 .load_dso => |path| if (comp.bin_file) |base| {1497 .load_dso => |path| if (comp.bin_file) |base| {
1498 comp.remaining_prelink_tasks -= 1;
1470 const prog_node = comp.work_queue_progress_node.start("Linker Parse Shared Library", 0);1499 const prog_node = comp.work_queue_progress_node.start("Linker Parse Shared Library", 0);
1471 defer prog_node.end();1500 defer prog_node.end();
1472 base.openLoadDso(path, .{1501 base.openLoadDso(path, .{
...@@ -1478,6 +1507,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1478,6 +1507,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1478 };1507 };
1479 },1508 },
1480 .load_input => |input| if (comp.bin_file) |base| {1509 .load_input => |input| if (comp.bin_file) |base| {
1510 comp.remaining_prelink_tasks -= 1;
1481 const prog_node = comp.work_queue_progress_node.start("Linker Parse Input", 0);1511 const prog_node = comp.work_queue_progress_node.start("Linker Parse Input", 0);
1482 defer prog_node.end();1512 defer prog_node.end();
1483 base.loadInput(input) catch |err| switch (err) {1513 base.loadInput(input) catch |err| switch (err) {
...@@ -1492,26 +1522,38 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1492,26 +1522,38 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1492 };1522 };
1493 },1523 },
1494 .codegen_nav => |nav_index| {1524 .codegen_nav => |nav_index| {
1495 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1525 if (comp.remaining_prelink_tasks == 0) {
1496 defer pt.deactivate();1526 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1497 pt.linkerUpdateNav(nav_index) catch |err| switch (err) {1527 defer pt.deactivate();
1498 error.OutOfMemory => diags.setAllocFailure(),1528 pt.linkerUpdateNav(nav_index) catch |err| switch (err) {
1499 };1529 error.OutOfMemory => diags.setAllocFailure(),
1530 };
1531 } else {
1532 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1533 }
1500 },1534 },
1501 .codegen_func => |func| {1535 .codegen_func => |func| {
1502 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1536 if (comp.remaining_prelink_tasks == 0) {
1503 defer pt.deactivate();1537 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1504 // This call takes ownership of `func.air`.1538 defer pt.deactivate();
1505 pt.linkerUpdateFunc(func.func, func.air) catch |err| switch (err) {1539 // This call takes ownership of `func.air`.
1506 error.OutOfMemory => diags.setAllocFailure(),1540 pt.linkerUpdateFunc(func.func, func.air) catch |err| switch (err) {
1507 };1541 error.OutOfMemory => diags.setAllocFailure(),
1542 };
1543 } else {
1544 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1545 }
1508 },1546 },
1509 .codegen_type => |ty| {1547 .codegen_type => |ty| {
1510 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1548 if (comp.remaining_prelink_tasks == 0) {
1511 defer pt.deactivate();1549 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1512 pt.linkerUpdateContainerType(ty) catch |err| switch (err) {1550 defer pt.deactivate();
1513 error.OutOfMemory => diags.setAllocFailure(),1551 pt.linkerUpdateContainerType(ty) catch |err| switch (err) {
1514 };1552 error.OutOfMemory => diags.setAllocFailure(),
1553 };
1554 } else {
1555 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1556 }
1515 },1557 },
1516 .update_line_number => |ti| {1558 .update_line_number => |ti| {
1517 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1559 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
src/link/Wasm/Flush.zig+4-2
...@@ -571,8 +571,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -571,8 +571,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
571 .__tls_size => @panic("TODO"),571 .__tls_size => @panic("TODO"),
572 .object_global => |i| {572 .object_global => |i| {
573 const global = i.ptr(wasm);573 const global = i.ptr(wasm);
574 try binary_writer.writeByte(@intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())));574 try binary_bytes.appendSlice(gpa, &.{
575 try binary_writer.writeByte(@intFromBool(global.flags.global_type.mutable));575 @intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())),
576 @intFromBool(global.flags.global_type.mutable),
577 });
576 try emitExpr(wasm, binary_bytes, global.expr);578 try emitExpr(wasm, binary_bytes, global.expr);
577 },579 },
578 .nav_exe => @panic("TODO"),580 .nav_exe => @panic("TODO"),