| author | |
| committer | |
| log | d1cde847a367c526c63d65714583189fa2912731 |
| tree | 96f1c2f65c9fe7f84381356e733f14b1341e328b |
| parent | 694b129d8960a9c3548dccb2a8f0c82f44fbafa9 |
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, |
| 113 | link_task_queue: ThreadSafeQueue(link.Task) = .empty, | 113 | link_task_queue: ThreadSafeQueue(link.Task) = .empty, |
| 114 | /// Ensure only 1 simultaneous call to `flushTaskQueue`. | 114 | /// Ensure only 1 simultaneous call to `flushTaskQueue`. |
| 115 | link_task_queue_safety: std.debug.SafetyLock = .{}, | 115 | link_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. | ||
| 118 | link_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. | ||
| 121 | remaining_prelink_tasks: u32, | ||
| 116 | 122 | ||
| 117 | work_queues: [ | 123 | work_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 | }; |
| 1519 | 1526 | ||
| 1520 | // Prevent some footguns by making the "any" fields of config reflect | 1527 | // 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; |
| 1789 | 1798 | ||
| ... | @@ -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; |
| 1805 | 1817 | ||
| ... | @@ -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; |
| 1821 | 1837 | ||
| ... | @@ -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; |
| 1833 | 1851 | ||
| ... | @@ -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; | ||
| 1839 | 1858 | ||
| 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 | } |
| 1872 | 1896 | ||
| 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 ask | 1916 | // 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 | } |
| 1896 | 1922 | ||
| 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 | } |
| 1902 | 1929 | ||
| 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 | } |
| 1905 | 1933 | ||
| 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 { |
| 1977 | 2005 | ||
| 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); | ||
| 1980 | 2009 | ||
| 1981 | comp.clearMiscFailures(); | 2010 | comp.clearMiscFailures(); |
| 1982 | 2011 | ||
| ... | @@ -3528,9 +3557,9 @@ pub fn performAllTheWork( | ... | @@ -3528,9 +3557,9 @@ pub fn performAllTheWork( |
| 3528 | 3557 | ||
| 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; |
| 3534 | 3563 | ||
| 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(); |
| 3664 | 3693 | ||
| 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 | } |
| 3668 | 3697 | ||
| 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 | } |
| 1219 | 1219 | ||
| 1220 | pub 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 | |||
| 1220 | fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { | 1232 | fn 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().?; |
| 1222 | 1234 |
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, | ||
| 367 | 368 | ||
| 368 | /// Prevents other processes from clobbering files in the output directory | 369 | /// 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 | } |
| 782 | 783 | ||
| 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 { |
| 1007 | 1010 | ||
| 1008 | /// Called when all linker inputs have been sent via `loadInput`. After | 1011 | /// 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; |
| 1013 | 1017 | ||
| ... | @@ -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 are | 1330 | /// 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. |
| 1328 | pub fn flushTaskQueue(tid: usize, comp: *Compilation) void { | 1332 | pub 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 | } |
| 1337 | 1361 | ||
| ... | @@ -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(); |
| 1397 | 1423 | ||
| ... | @@ -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"), |