| author | |
| committer | |
| log | 203bbaee07dfd8e67ea102dbb29afb75be246e53 |
| tree | a9f4352e17246561d99119cbbb5d4e5198456f07 |
| parent | f08a8f0fc217914690a58035291da8bcc7a86e47 |
5 files changed, 475 insertions(+), 344 deletions(-)
src/Compilation.zig+178-139| ... | @@ -20,7 +20,6 @@ const link = @import("link.zig"); | ... | @@ -20,7 +20,6 @@ const link = @import("link.zig"); |
| 20 | const tracy = @import("tracy.zig"); | 20 | const tracy = @import("tracy.zig"); |
| 21 | const trace = tracy.trace; | 21 | const trace = tracy.trace; |
| 22 | const build_options = @import("build_options"); | 22 | const build_options = @import("build_options"); |
| 23 | const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; | ||
| 24 | const LibCInstallation = std.zig.LibCInstallation; | 23 | const LibCInstallation = std.zig.LibCInstallation; |
| 25 | const glibc = @import("libs/glibc.zig"); | 24 | const glibc = @import("libs/glibc.zig"); |
| 26 | const musl = @import("libs/musl.zig"); | 25 | const musl = @import("libs/musl.zig"); |
| ... | @@ -148,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma | ... | @@ -148,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma |
| 148 | pub fn values(_: @This()) [0]void { | 147 | pub fn values(_: @This()) [0]void { |
| 149 | return .{}; | 148 | return .{}; |
| 150 | } | 149 | } |
| 150 | pub fn clearRetainingCapacity(_: @This()) void {} | ||
| 151 | pub fn deinit(_: @This(), _: Allocator) void {} | 151 | pub fn deinit(_: @This(), _: Allocator) void {} |
| 152 | } = .{}, | 152 | } = .{}, |
| 153 | 153 | ||
| ... | @@ -238,8 +238,6 @@ reference_trace: ?u32 = null, | ... | @@ -238,8 +238,6 @@ reference_trace: ?u32 = null, |
| 238 | /// This mutex guards all `Compilation` mutable state. | 238 | /// This mutex guards all `Compilation` mutable state. |
| 239 | mutex: std.Io.Mutex = .init, | 239 | mutex: std.Io.Mutex = .init, |
| 240 | 240 | ||
| 241 | test_filters: []const []const u8, | ||
| 242 | |||
| 243 | link_prog_node: std.Progress.Node = .none, | 241 | link_prog_node: std.Progress.Node = .none, |
| 244 | 242 | ||
| 245 | llvm_opt_bisect_limit: c_int, | 243 | llvm_opt_bisect_limit: c_int, |
| ... | @@ -1635,28 +1633,11 @@ pub const CreateOptions = struct { | ... | @@ -1635,28 +1633,11 @@ pub const CreateOptions = struct { |
| 1635 | }; | 1633 | }; |
| 1636 | }; | 1634 | }; |
| 1637 | 1635 | ||
| 1638 | fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void { | ||
| 1639 | assert(zcu.module_roots.count() != 0); // module_roots is populated | ||
| 1640 | |||
| 1641 | for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| { | ||
| 1642 | if (mod == zcu.std_mod) continue; // redundant | ||
| 1643 | if (opt_mod_root_file.unwrap()) |mod_root_file| { | ||
| 1644 | if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant | ||
| 1645 | } | ||
| 1646 | cache_helpers.addModule(hash, mod); | ||
| 1647 | hash.add(mod.root.root); | ||
| 1648 | hash.addBytes(mod.root.sub_path); | ||
| 1649 | hash.addBytes(mod.root_src_path); | ||
| 1650 | hash.addListOfBytes(mod.deps.keys()); | ||
| 1651 | } | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | const RtStrat = enum { none, lib, obj, zcu }; | 1636 | const RtStrat = enum { none, lib, obj, zcu }; |
| 1655 | 1637 | ||
| 1656 | pub const CreateDiagnostic = union(enum) { | 1638 | pub const CreateDiagnostic = union(enum) { |
| 1657 | export_table_import_table_conflict, | 1639 | export_table_import_table_conflict, |
| 1658 | emit_h_without_zcu, | 1640 | emit_h_without_zcu, |
| 1659 | illegal_zig_import, | ||
| 1660 | cross_libc_unavailable, | 1641 | cross_libc_unavailable, |
| 1661 | find_native_libc: std.zig.LibCInstallation.FindError, | 1642 | find_native_libc: std.zig.LibCInstallation.FindError, |
| 1662 | libc_installation_missing_cc_dir, | 1643 | libc_installation_missing_cc_dir, |
| ... | @@ -1672,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) { | ... | @@ -1672,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) { |
| 1672 | switch (diag) { | 1653 | switch (diag) { |
| 1673 | .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"), | 1654 | .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"), |
| 1674 | .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"), | 1655 | .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"), |
| 1675 | .illegal_zig_import => try w.writeAll("this compiler implementation does not support importing the root source file of a provided module"), | ||
| 1676 | .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"), | 1656 | .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"), |
| 1677 | .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}), | 1657 | .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}), |
| 1678 | .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"), | 1658 | .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"), |
| ... | @@ -1720,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -1720,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 1720 | const use_llvm = options.config.use_llvm; | 1700 | const use_llvm = options.config.use_llvm; |
| 1721 | const target = &options.root_mod.resolved_target.result; | 1701 | const target = &options.root_mod.resolved_target.result; |
| 1722 | 1702 | ||
| 1723 | const comp: *Compilation = comp: { | 1703 | const comp = comp: { |
| 1724 | // We put the `Compilation` itself in the arena. Freeing the arena will free the module. | 1704 | // We put the `Compilation` itself in the arena. Freeing the arena will free the module. |
| 1725 | // It's initialized later after we prepare the initialization options. | 1705 | // It's initialized later after we prepare the initialization options. |
| 1726 | const root_name = try arena.dupeSentinel(u8, options.root_name, 0); | 1706 | const root_name = try arena.dupeSentinel(u8, options.root_name, 0); |
| ... | @@ -1988,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -1988,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 1988 | // TODO audit this and make sure everything is in it | 1968 | // TODO audit this and make sure everything is in it |
| 1989 | 1969 | ||
| 1990 | const comp = try arena.create(Compilation); | 1970 | const comp = try arena.create(Compilation); |
| 1991 | const opt_zcu: ?*Zcu = if (have_zcu) blk: { | 1971 | const opt_zcu = if (have_zcu) blk: { |
| 1992 | // Pre-open the directory handles for cached ZIR code so that it does not need | 1972 | // Pre-open the directory handles for cached ZIR code so that it does not need |
| 1993 | // to redundantly happen for each AstGen operation. | 1973 | // to redundantly happen for each AstGen operation. |
| 1994 | const zir_sub_dir = "z"; | 1974 | const zir_sub_dir = "z"; |
| ... | @@ -2041,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -2041,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2041 | zcu.* = .{ | 2021 | zcu.* = .{ |
| 2042 | .gpa = gpa, | 2022 | .gpa = gpa, |
| 2043 | .comp = comp, | 2023 | .comp = comp, |
| 2044 | .main_mod = main_mod, | 2024 | .llvm_object = null, |
| 2025 | |||
| 2045 | .root_mod = options.root_mod, | 2026 | .root_mod = options.root_mod, |
| 2027 | .main_mod = main_mod, | ||
| 2046 | .std_mod = std_mod, | 2028 | .std_mod = std_mod, |
| 2029 | .sema_prog_node = .none, | ||
| 2030 | .codegen_prog_node = .none, | ||
| 2031 | .pending_codegen_jobs = .init(0), | ||
| 2032 | |||
| 2033 | .cur_sema_prog_node = .none, | ||
| 2034 | |||
| 2047 | .global_zir_cache = global_zir_cache, | 2035 | .global_zir_cache = global_zir_cache, |
| 2048 | .local_zir_cache = local_zir_cache, | 2036 | .local_zir_cache = local_zir_cache, |
| 2037 | |||
| 2038 | .all_exports = .empty, | ||
| 2039 | .free_exports = .empty, | ||
| 2040 | .single_exports = .empty, | ||
| 2041 | .multi_exports = .empty, | ||
| 2042 | |||
| 2043 | .module_roots = .empty, | ||
| 2044 | .builtin_modules = .empty, | ||
| 2045 | |||
| 2046 | .import_table = .empty, | ||
| 2047 | .alive_files = .empty, | ||
| 2048 | .embed_table = .empty, | ||
| 2049 | |||
| 2050 | .intern_pool = .empty, | ||
| 2051 | |||
| 2052 | .compile_logs = .empty, | ||
| 2053 | .compile_log_lines = .empty, | ||
| 2054 | .free_compile_log_lines = .empty, | ||
| 2055 | |||
| 2056 | .illegal_module_root = null, | ||
| 2057 | .multi_module_err = null, | ||
| 2058 | .failed_imports = .empty, | ||
| 2059 | .failed_files = .empty, | ||
| 2060 | .skip_analysis_this_update = false, | ||
| 2061 | .analysis_in_progress = .empty, | ||
| 2062 | .failed_analysis = .empty, | ||
| 2063 | .transitive_failed_analysis = .empty, | ||
| 2064 | .dependency_loops = .empty, | ||
| 2065 | .dependency_loop_nodes = .empty, | ||
| 2066 | .failed_codegen = .empty, | ||
| 2067 | .failed_types = .empty, | ||
| 2068 | .failed_exports = .empty, | ||
| 2069 | |||
| 2049 | .error_limit = error_limit, | 2070 | .error_limit = error_limit, |
| 2050 | .llvm_object = null, | 2071 | |
| 2072 | .outdated_lock = if (std.debug.runtime_safety) .init, | ||
| 2073 | .potentially_outdated = .empty, | ||
| 2074 | .outdated = .empty, | ||
| 2075 | .outdated_ready = .{ | ||
| 2076 | .funcs = .empty, | ||
| 2077 | .other = .empty, | ||
| 2078 | }, | ||
| 2079 | .retryable_failures = .empty, | ||
| 2080 | |||
| 2051 | .analysis_roots_buffer = undefined, | 2081 | .analysis_roots_buffer = undefined, |
| 2052 | .analysis_roots_len = 0, | 2082 | .analysis_roots_len = 0, |
| 2083 | .resolved_references = null, | ||
| 2084 | |||
| 2085 | .test_filters = options.test_filters, | ||
| 2086 | .test_functions = .empty, | ||
| 2087 | |||
| 2088 | .global_assembly = .empty, | ||
| 2089 | |||
| 2090 | .reference_table = .empty, | ||
| 2091 | .all_references = .empty, | ||
| 2092 | .free_references = .empty, | ||
| 2093 | |||
| 2094 | .inline_reference_frames = .empty, | ||
| 2095 | .free_inline_reference_frames = .empty, | ||
| 2096 | |||
| 2097 | .type_reference_table = .empty, | ||
| 2098 | .all_type_references = .empty, | ||
| 2099 | .free_type_references = .empty, | ||
| 2100 | |||
| 2101 | .std_lang_decl_values = .initFill(.none), | ||
| 2102 | |||
| 2103 | .incremental_debug_state = if (build_options.enable_debug_extensions) .init, | ||
| 2104 | |||
| 2105 | .cur_analysis_timer = null, | ||
| 2106 | |||
| 2053 | .codegen_task_pool = try .init(arena), | 2107 | .codegen_task_pool = try .init(arena), |
| 2108 | |||
| 2109 | .generation = 0, | ||
| 2110 | |||
| 2054 | .anon_name_counter = 0, | 2111 | .anon_name_counter = 0, |
| 2055 | }; | 2112 | }; |
| 2056 | try zcu.init(gpa, io, options.thread_limit); | ||
| 2057 | break :blk zcu; | 2113 | break :blk zcu; |
| 2058 | } else blk: { | 2114 | } else blk: { |
| 2059 | if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu); | 2115 | if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu); |
| ... | @@ -2091,7 +2147,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -2091,7 +2147,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2091 | .reference_trace = options.reference_trace, | 2147 | .reference_trace = options.reference_trace, |
| 2092 | .time_report = if (options.time_report) .init else null, | 2148 | .time_report = if (options.time_report) .init else null, |
| 2093 | .stack_report = options.stack_report, | 2149 | .stack_report = options.stack_report, |
| 2094 | .test_filters = options.test_filters, | ||
| 2095 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, | 2150 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 2096 | .debug_compile_errors = options.debug_compile_errors, | 2151 | .debug_compile_errors = options.debug_compile_errors, |
| 2097 | .debug_incremental = options.debug_incremental, | 2152 | .debug_incremental = options.debug_incremental, |
| ... | @@ -2143,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -2143,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2143 | comp.config.any_sanitize_c = any_sanitize_c; | 2198 | comp.config.any_sanitize_c = any_sanitize_c; |
| 2144 | comp.config.any_fuzz = any_fuzz; | 2199 | comp.config.any_fuzz = any_fuzz; |
| 2145 | 2200 | ||
| 2146 | if (opt_zcu) |zcu| { | 2201 | // Initialize the `zcu` after the fields on `comp` have been initialized. |
| 2147 | // Finish initializing the `zcu` after the fields on `comp` have been initialized. | 2202 | if (opt_zcu) |zcu| zcu.init(); |
| 2148 | zcu.initAfterCompilation(); | ||
| 2149 | |||
| 2150 | // Populate `zcu.module_roots`. | ||
| 2151 | const active = zcu.acquire(); | ||
| 2152 | defer active.release(); | ||
| 2153 | active.pt.populateModuleRootTable() catch |err| switch (err) { | ||
| 2154 | error.OutOfMemory => |e| return e, | ||
| 2155 | error.IllegalZigImport => return diag.fail(.illegal_zig_import), | ||
| 2156 | }; | ||
| 2157 | } | ||
| 2158 | 2203 | ||
| 2159 | const lf_open_opts: link.File.OpenOptions = .{ | 2204 | const lf_open_opts: link.File.OpenOptions = .{ |
| 2160 | .linker_script = options.linker_script, | 2205 | .linker_script = options.linker_script, |
| ... | @@ -2250,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -2250,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2250 | hash.add(options.config.is_test); | 2295 | hash.add(options.config.is_test); |
| 2251 | hash.addListOfBytes(options.test_filters); | 2296 | hash.addListOfBytes(options.test_filters); |
| 2252 | hash.add(options.skip_linker_dependencies); | 2297 | hash.add(options.skip_linker_dependencies); |
| 2253 | hash.add(options.emit_h != .no); | 2298 | //hash.add(options.emit_h != .no); |
| 2254 | hash.add(error_limit); | 2299 | hash.add(error_limit); |
| 2255 | 2300 | ||
| 2256 | // Here we put the root source file path name, but *not* with addFile. | 2301 | try comp.addModuleTableToCacheHash(&hash); |
| 2257 | // We want the hash to be the same regardless of the contents of the | ||
| 2258 | // source file, because incremental compilation will handle it, but we | ||
| 2259 | // do want to namespace different source file names because they are | ||
| 2260 | // likely different compilations and therefore this would be likely to | ||
| 2261 | // cause cache hits. | ||
| 2262 | if (comp.zcu) |zcu| { | ||
| 2263 | try addModuleTableToCacheHash(zcu, &hash); | ||
| 2264 | } else { | ||
| 2265 | cache_helpers.addModule(&hash, options.root_mod); | ||
| 2266 | } | ||
| 2267 | 2302 | ||
| 2268 | // In the case of incremental cache mode, this `artifact_directory` | 2303 | // In the case of incremental cache mode, this `artifact_directory` |
| 2269 | // is computed based on a hash of non-linker inputs, and it is where all | 2304 | // is computed based on a hash of non-linker inputs, and it is where all |
| ... | @@ -2315,22 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, | ... | @@ -2315,22 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2315 | comp.cache_use = .{ .whole = whole }; | 2350 | comp.cache_use = .{ .whole = whole }; |
| 2316 | }, | 2351 | }, |
| 2317 | } | 2352 | } |
| 2318 | |||
| 2319 | if (use_llvm and | ||
| 2320 | (comp.emit_bin != null or | ||
| 2321 | comp.emit_asm != null or | ||
| 2322 | comp.emit_llvm_ir != null or | ||
| 2323 | comp.emit_llvm_bc != null or | ||
| 2324 | log_llvm_ir: { | ||
| 2325 | break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir"); | ||
| 2326 | })) | ||
| 2327 | { | ||
| 2328 | if (opt_zcu) |zcu| { | ||
| 2329 | dev.check(.llvm_backend); | ||
| 2330 | zcu.llvm_object = try LlvmObject.create(arena, zcu); | ||
| 2331 | } | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | break :comp comp; | 2353 | break :comp comp; |
| 2335 | }; | 2354 | }; |
| 2336 | errdefer comp.destroy(); | 2355 | errdefer comp.destroy(); |
| ... | @@ -2599,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void { | ... | @@ -2599,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void { |
| 2599 | } | 2618 | } |
| 2600 | comp.win32_resources.deinit(gpa); | 2619 | comp.win32_resources.deinit(gpa); |
| 2601 | 2620 | ||
| 2602 | for (comp.failed_win32_resources.values()) |*value| { | 2621 | for (comp.failed_win32_resources.values()) |*bundle| { |
| 2603 | value.deinit(gpa); | 2622 | bundle.deinit(gpa); |
| 2604 | } | 2623 | } |
| 2605 | comp.failed_win32_resources.deinit(gpa); | 2624 | comp.failed_win32_resources.deinit(gpa); |
| 2606 | 2625 | ||
| ... | @@ -2624,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void { | ... | @@ -2624,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void { |
| 2624 | comp.misc_failures = .{}; | 2643 | comp.misc_failures = .{}; |
| 2625 | } | 2644 | } |
| 2626 | 2645 | ||
| 2627 | pub fn getTarget(self: *const Compilation) *const Target { | 2646 | pub fn getTarget(comp: *const Compilation) *const Target { |
| 2628 | return &self.root_mod.resolved_target.result; | 2647 | return &comp.root_mod.resolved_target.result; |
| 2629 | } | 2648 | } |
| 2630 | 2649 | ||
| 2631 | /// Only legal to call when cache mode is incremental and a link file is present. | 2650 | /// Only legal to call when cache mode is incremental and a link file is present. |
| ... | @@ -2644,6 +2663,18 @@ pub fn hotCodeSwap( | ... | @@ -2644,6 +2663,18 @@ pub fn hotCodeSwap( |
| 2644 | fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { | 2663 | fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2645 | const io = comp.io; | 2664 | const io = comp.io; |
| 2646 | 2665 | ||
| 2666 | if (comp.bin_file) |lf| { | ||
| 2667 | lf.endProgress(); | ||
| 2668 | comp.link_prog_node.end(); | ||
| 2669 | comp.link_prog_node = .none; | ||
| 2670 | switch (comp.cache_use) { | ||
| 2671 | .none, .whole => { | ||
| 2672 | lf.destroy(); | ||
| 2673 | comp.bin_file = null; | ||
| 2674 | }, | ||
| 2675 | .incremental => {}, | ||
| 2676 | } | ||
| 2677 | } | ||
| 2647 | switch (comp.cache_use) { | 2678 | switch (comp.cache_use) { |
| 2648 | .none => |none| { | 2679 | .none => |none| { |
| 2649 | if (none.tmp_artifact_directory) |*tmp_dir| { | 2680 | if (none.tmp_artifact_directory) |*tmp_dir| { |
| ... | @@ -2660,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { | ... | @@ -2660,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2660 | // replicated in the output binary (the output instead contains a reference to that | 2691 | // replicated in the output binary (the output instead contains a reference to that |
| 2661 | // file which debug tooling can look through). So, in that particular case, we need | 2692 | // file which debug tooling can look through). So, in that particular case, we need |
| 2662 | // to keep this directory around so that the output binary can be debugged. | 2693 | // to keep this directory around so that the output binary can be debugged. |
| 2663 | if (comp.bin_file != null and comp.getTarget().ofmt == .macho and comp.config.debug_format != .strip) { | 2694 | if (comp.bin_file == null or comp.getTarget().ofmt != .macho or comp.config.debug_format == .strip) { |
| 2664 | // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU | 2695 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); |
| 2665 | // object file must remain on-disk for its debug info. | 2696 | comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { |
| 2666 | return; | 2697 | log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ |
| 2698 | comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, | ||
| 2699 | }); | ||
| 2700 | }; | ||
| 2667 | } | 2701 | } |
| 2668 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); | ||
| 2669 | comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { | ||
| 2670 | log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ | ||
| 2671 | comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, | ||
| 2672 | }); | ||
| 2673 | }; | ||
| 2674 | } | 2702 | } |
| 2675 | }, | 2703 | }, |
| 2676 | .incremental => return, | 2704 | .incremental => return, |
| ... | @@ -2679,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { | ... | @@ -2679,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2679 | man.deinit(); | 2707 | man.deinit(); |
| 2680 | whole.cache_manifest = null; | 2708 | whole.cache_manifest = null; |
| 2681 | } | 2709 | } |
| 2682 | if (comp.bin_file) |lf| { | ||
| 2683 | lf.destroy(); | ||
| 2684 | comp.bin_file = null; | ||
| 2685 | } | ||
| 2686 | if (whole.tmp_artifact_directory) |*tmp_dir| { | 2710 | if (whole.tmp_artifact_directory) |*tmp_dir| { |
| 2687 | tmp_dir.handle.close(io); | 2711 | tmp_dir.handle.close(io); |
| 2688 | whole.tmp_artifact_directory = null; | 2712 | whole.tmp_artifact_directory = null; |
| ... | @@ -2695,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { | ... | @@ -2695,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2695 | } | 2719 | } |
| 2696 | }, | 2720 | }, |
| 2697 | } | 2721 | } |
| 2722 | assert(!comp.config.incremental); // always uses incremental cache mode | ||
| 2723 | if (comp.zcu) |zcu| { | ||
| 2724 | if (zcu.llvm_object) |llvm_object| { | ||
| 2725 | llvm_object.deinit(); | ||
| 2726 | zcu.llvm_object = null; | ||
| 2727 | } | ||
| 2728 | } | ||
| 2698 | } | 2729 | } |
| 2699 | 2730 | ||
| 2700 | pub const UpdateError = error{ | 2731 | pub const UpdateError = error{ |
| ... | @@ -2716,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -2716,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2716 | defer arena_allocator.deinit(); | 2747 | defer arena_allocator.deinit(); |
| 2717 | const arena = arena_allocator.allocator(); | 2748 | const arena = arena_allocator.allocator(); |
| 2718 | 2749 | ||
| 2719 | comp.clearMiscFailures(); | 2750 | reset: { |
| 2720 | comp.last_update_was_cache_hit = false; | 2751 | comp.clearMiscFailures(); |
| 2721 | if (comp.time_report) |*tr| { | 2752 | comp.last_update_was_cache_hit = false; |
| 2722 | tr.deinit(gpa); // this is information about an old update | 2753 | if (comp.time_report) |*tr| { |
| 2723 | tr.* = .init; | 2754 | tr.deinit(comp.gpa); |
| 2755 | tr.* = .init; | ||
| 2756 | } | ||
| 2757 | if (comp.file_system_inputs) |file_system_inputs| file_system_inputs.clearRetainingCapacity(); | ||
| 2758 | |||
| 2759 | if (comp.zcu) |zcu| { | ||
| 2760 | zcu.skip_analysis_this_update = false; | ||
| 2761 | if (zcu.generation > 0) break :reset; | ||
| 2762 | try zcu.reset(arena); | ||
| 2763 | } | ||
| 2764 | for (comp.failed_c_objects.values()) |bundle| bundle.destroy(comp.gpa); | ||
| 2765 | comp.failed_c_objects.clearRetainingCapacity(); | ||
| 2766 | for (comp.failed_win32_resources.values()) |*bundle| bundle.deinit(comp.gpa); | ||
| 2767 | comp.failed_win32_resources.clearRetainingCapacity(); | ||
| 2724 | } | 2768 | } |
| 2725 | 2769 | ||
| 2726 | var tmp_dir_rand_int: u64 = undefined; | 2770 | var tmp_dir_rand_int: u64 = undefined; |
| ... | @@ -2865,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -2865,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2865 | if (comp.zcu) |zcu| { | 2909 | if (comp.zcu) |zcu| { |
| 2866 | assert(zcu.cur_analysis_timer == null); | 2910 | assert(zcu.cur_analysis_timer == null); |
| 2867 | 2911 | ||
| 2868 | zcu.skip_analysis_this_update = false; | ||
| 2869 | |||
| 2870 | // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! | 2912 | // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! |
| 2871 | for (zcu.embed_table.keys()) |embed_file| { | 2913 | for (zcu.embed_table.keys()) |embed_file| { |
| 2872 | try comp.appendFileSystemInput(embed_file.path); | 2914 | try comp.appendFileSystemInput(embed_file.path); |
| 2873 | } | 2915 | } |
| 2874 | |||
| 2875 | zcu.analysis_roots_len = 0; | ||
| 2876 | |||
| 2877 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; | ||
| 2878 | zcu.analysis_roots_len += 1; | ||
| 2879 | |||
| 2880 | // Normally we rely on importing std to in turn import the root source file in the start code. | ||
| 2881 | // However, the main module is distinct from the root module in tests, so that won't happen there. | ||
| 2882 | if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { | ||
| 2883 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; | ||
| 2884 | zcu.analysis_roots_len += 1; | ||
| 2885 | } | ||
| 2886 | |||
| 2887 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { | ||
| 2888 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; | ||
| 2889 | zcu.analysis_roots_len += 1; | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { | ||
| 2893 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; | ||
| 2894 | zcu.analysis_roots_len += 1; | ||
| 2895 | } | ||
| 2896 | |||
| 2897 | if (zcu.root_mod.deps.get("zigc")) |zigc_mod| { | ||
| 2898 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod; | ||
| 2899 | zcu.analysis_roots_len += 1; | ||
| 2900 | } | ||
| 2901 | } | 2916 | } |
| 2902 | 2917 | ||
| 2903 | // The linker progress node is set up here instead of in `performAllTheWork`, because | 2918 | // The linker progress node is set up here instead of in `performAllTheWork`, because |
| ... | @@ -2919,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -2919,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2919 | comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); | 2934 | comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); |
| 2920 | lf.startProgress(comp.link_prog_node); | 2935 | lf.startProgress(comp.link_prog_node); |
| 2921 | } | 2936 | } |
| 2922 | defer if (comp.bin_file) |lf| { | ||
| 2923 | lf.endProgress(); | ||
| 2924 | comp.link_prog_node.end(); | ||
| 2925 | comp.link_prog_node = .none; | ||
| 2926 | }; | ||
| 2927 | 2937 | ||
| 2928 | try comp.performAllTheWork(main_progress_node, arena); | 2938 | try comp.performAllTheWork(main_progress_node, arena); |
| 2929 | 2939 | ||
| ... | @@ -2969,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -2969,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2969 | comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); | 2979 | comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); |
| 2970 | }; | 2980 | }; |
| 2971 | 2981 | ||
| 2972 | if (anyErrors(comp)) { | 2982 | if (comp.anyErrors()) { |
| 2973 | // Skip flushing and keep source files loaded for error reporting. | 2983 | // Skip flushing and keep source files loaded for error reporting. |
| 2974 | return; | 2984 | return; |
| 2975 | } | 2985 | } |
| ... | @@ -2983,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -2983,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2983 | } | 2993 | } |
| 2984 | 2994 | ||
| 2985 | switch (comp.cache_use) { | 2995 | switch (comp.cache_use) { |
| 2986 | .none, .incremental => try flush(comp, arena), | 2996 | .none, .incremental => try comp.flush(arena), |
| 2987 | .whole => |whole| { | 2997 | .whole => |whole| { |
| 2988 | if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); | 2998 | if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); |
| 2989 | if (comp.parent_whole_cache) |pwc| { | 2999 | if (comp.parent_whole_cache) |pwc| { |
| ... | @@ -3064,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -3064,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3064 | }; | 3074 | }; |
| 3065 | } | 3075 | } |
| 3066 | 3076 | ||
| 3067 | try flush(comp, arena); | 3077 | try comp.flush(arena); |
| 3068 | 3078 | ||
| 3069 | // Calling `flush` may have produced errors, in which case the | 3079 | // Calling `flush` may have produced errors, in which case the |
| 3070 | // cache manifest must not be written. | 3080 | // cache manifest must not be written. |
| 3071 | if (anyErrors(comp)) return; | 3081 | if (comp.anyErrors()) return; |
| 3072 | 3082 | ||
| 3073 | // Release the lock and close the file before writing the manifest. | 3083 | // Release the lock and close the file before writing the manifest. |
| 3074 | // This avoids the potential of another process getting a cache hit and | 3084 | // This avoids the potential of another process getting a cache hit and |
| ... | @@ -3168,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error | ... | @@ -3168,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error |
| 3168 | defer tid.release(io); | 3178 | defer tid.release(io); |
| 3169 | if (comp.zcu) |zcu| { | 3179 | if (comp.zcu) |zcu| { |
| 3170 | if (zcu.llvm_object) |llvm_object| { | 3180 | if (zcu.llvm_object) |llvm_object| { |
| 3171 | |||
| 3172 | // Emit the ZCU object from LLVM now; it's required to flush the output file. | 3181 | // Emit the ZCU object from LLVM now; it's required to flush the output file. |
| 3173 | // If there's an output file, it wants to decide where the LLVM object goes! | 3182 | // If there's an output file, it wants to decide where the LLVM object goes! |
| 3174 | const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0); | 3183 | const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0); |
| ... | @@ -3303,23 +3312,42 @@ fn renameTmpIntoCache( | ... | @@ -3303,23 +3312,42 @@ fn renameTmpIntoCache( |
| 3303 | /// anything from the link cache manifest. | 3312 | /// anything from the link cache manifest. |
| 3304 | pub const link_hash_implementation_version = 14; | 3313 | pub const link_hash_implementation_version = 14; |
| 3305 | 3314 | ||
| 3306 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | 3315 | fn addModuleTableToCacheHash(comp: *Compilation, hash: *Cache.HashHelper) Allocator.Error!void { |
| 3307 | comptime assert(link_hash_implementation_version == 14); | 3316 | const gpa = comp.gpa; |
| 3317 | var mods: std.array_hash_map.Auto(*Module, void) = .empty; | ||
| 3318 | defer mods.deinit(gpa); | ||
| 3319 | |||
| 3320 | try mods.putNoClobber(gpa, comp.root_mod, {}); | ||
| 3321 | if (comp.zcu) |zcu| try mods.put(gpa, zcu.main_mod, {}); | ||
| 3322 | |||
| 3323 | var mod_index: usize = 0; | ||
| 3324 | while (mod_index < mods.count()) : (mod_index += 1) { | ||
| 3325 | const mod = mods.keys()[mod_index]; | ||
| 3308 | 3326 | ||
| 3309 | if (comp.zcu) |zcu| { | ||
| 3310 | // No need to hash the actual file contents here because it is | 3327 | // No need to hash the actual file contents here because it is |
| 3311 | // redundant with the logic in `PerThread.update` which iterates over | 3328 | // redundant with the logic in `PerThread.update` which iterates over |
| 3312 | // `zcu.alive_files` and adds those files discovered via `@import` to | 3329 | // `zcu.alive_files` and adds those files discovered via `@import` to |
| 3313 | // the whole cache manifest. | 3330 | // the whole cache manifest. |
| 3314 | try addModuleTableToCacheHash(zcu, &man.hash); | 3331 | cache_helpers.addModule(hash, mod); |
| 3332 | hash.add(mod.root.root); | ||
| 3333 | hash.addBytes(mod.root.sub_path); | ||
| 3334 | hash.addBytes(mod.root_src_path); | ||
| 3335 | hash.addListOfBytes(mod.deps.keys()); | ||
| 3315 | 3336 | ||
| 3337 | for (mod.deps.values()) |dep_mod| try mods.put(gpa, dep_mod, {}); | ||
| 3338 | } | ||
| 3339 | } | ||
| 3340 | |||
| 3341 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | ||
| 3342 | comptime assert(link_hash_implementation_version == 14); | ||
| 3343 | |||
| 3344 | try comp.addModuleTableToCacheHash(&man.hash); | ||
| 3345 | |||
| 3346 | if (comp.zcu) |zcu| { | ||
| 3316 | // Synchronize with other matching comments: ZigOnlyHashStuff | 3347 | // Synchronize with other matching comments: ZigOnlyHashStuff |
| 3317 | man.hash.addListOfBytes(comp.test_filters); | 3348 | man.hash.addListOfBytes(zcu.test_filters); |
| 3318 | man.hash.add(comp.skip_linker_dependencies); | ||
| 3319 | //man.hash.add(zcu.emit_h != .no); | 3349 | //man.hash.add(zcu.emit_h != .no); |
| 3320 | man.hash.add(zcu.error_limit); | 3350 | man.hash.add(zcu.error_limit); |
| 3321 | } else { | ||
| 3322 | cache_helpers.addModule(&man.hash, comp.root_mod); | ||
| 3323 | } | 3351 | } |
| 3324 | 3352 | ||
| 3325 | try link.hashInputs(man, comp.link_inputs); | 3353 | try link.hashInputs(man, comp.link_inputs); |
| ... | @@ -3788,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void { | ... | @@ -3788,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void { |
| 3788 | } | 3816 | } |
| 3789 | 3817 | ||
| 3790 | /// This function is temporally single-threaded. | 3818 | /// This function is temporally single-threaded. |
| 3791 | pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | 3819 | pub fn getAllErrorsAlloc(comp: *Compilation) Allocator.Error!ErrorBundle { |
| 3792 | const gpa = comp.gpa; | 3820 | const gpa = comp.gpa; |
| 3793 | const io = comp.io; | 3821 | const io = comp.io; |
| 3794 | 3822 | ||
| ... | @@ -3831,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | ... | @@ -3831,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 3831 | } | 3859 | } |
| 3832 | 3860 | ||
| 3833 | if (comp.zcu) |zcu| zcu_errors: { | 3861 | if (comp.zcu) |zcu| zcu_errors: { |
| 3862 | if (zcu.illegal_module_root) |mod| { | ||
| 3863 | try bundle.addRootErrorMessage(.{ | ||
| 3864 | .msg = try bundle.printString( | ||
| 3865 | "this compiler implementation does not support using '{f}/{s}' as the root of module '{s}'", | ||
| 3866 | .{ mod.root.fmt(comp), mod.root_src_path, mod.fully_qualified_name }, | ||
| 3867 | ), | ||
| 3868 | .notes_len = 0, | ||
| 3869 | }); | ||
| 3870 | } | ||
| 3834 | if (zcu.multi_module_err != null) { | 3871 | if (zcu.multi_module_err != null) { |
| 3835 | try zcu.addFileInMultipleModulesError(&bundle); | 3872 | try zcu.addFileInMultipleModulesError(&bundle); |
| 3836 | break :zcu_errors; | 3873 | break :zcu_errors; |
| ... | @@ -4359,7 +4396,9 @@ fn performAllTheWork( | ... | @@ -4359,7 +4396,9 @@ fn performAllTheWork( |
| 4359 | defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); | 4396 | defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); |
| 4360 | if (comp.zcu) |zcu| { | 4397 | if (comp.zcu) |zcu| { |
| 4361 | // Regardless of errors, `comp.zcu` needs to update its generation number. | 4398 | // Regardless of errors, `comp.zcu` needs to update its generation number. |
| 4362 | defer zcu.generation += 1; | 4399 | defer if (comp.config.incremental) { |
| 4400 | zcu.generation += 1; | ||
| 4401 | }; | ||
| 4363 | const active = zcu.acquire(); | 4402 | const active = zcu.acquire(); |
| 4364 | defer active.release(); | 4403 | defer active.release(); |
| 4365 | try active.pt.update(main_progress_node, &decl_work_timer); | 4404 | try active.pt.update(main_progress_node, &decl_work_timer); |
src/Zcu.zig+250-156| ... | @@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit; | ... | @@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit; |
| 40 | const BuiltinFn = std.zig.BuiltinFn; | 40 | const BuiltinFn = std.zig.BuiltinFn; |
| 41 | const codegen = @import("codegen.zig"); | 41 | const codegen = @import("codegen.zig"); |
| 42 | const LlvmObject = @import("codegen/llvm.zig").Object; | 42 | const LlvmObject = @import("codegen/llvm.zig").Object; |
| 43 | const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; | ||
| 43 | const dev = @import("dev.zig"); | 44 | const dev = @import("dev.zig"); |
| 44 | const Zoir = std.zig.Zoir; | 45 | const Zoir = std.zig.Zoir; |
| 45 | const ZonGen = std.zig.ZonGen; | 46 | const ZonGen = std.zig.ZonGen; |
| ... | @@ -69,18 +70,18 @@ root_mod: *Module, | ... | @@ -69,18 +70,18 @@ root_mod: *Module, |
| 69 | /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests. | 70 | /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests. |
| 70 | main_mod: *Module, | 71 | main_mod: *Module, |
| 71 | std_mod: *Module, | 72 | std_mod: *Module, |
| 72 | sema_prog_node: std.Progress.Node = .none, | 73 | sema_prog_node: std.Progress.Node, |
| 73 | codegen_prog_node: std.Progress.Node = .none, | 74 | codegen_prog_node: std.Progress.Node, |
| 74 | /// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value | 75 | /// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value |
| 75 | /// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this | 76 | /// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this |
| 76 | /// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is | 77 | /// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is |
| 77 | /// completed (since semantic analysis could trigger more codegen work). | 78 | /// completed (since semantic analysis could trigger more codegen work). |
| 78 | pending_codegen_jobs: std.atomic.Value(u32) = .init(0), | 79 | pending_codegen_jobs: std.atomic.Value(u32), |
| 79 | 80 | ||
| 80 | /// This is the progress node *under* `sema_prog_node` which is currently running. | 81 | /// This is the progress node *under* `sema_prog_node` which is currently running. |
| 81 | /// When we have to pause to analyze something else, we just temporarily rename this node. | 82 | /// When we have to pause to analyze something else, we just temporarily rename this node. |
| 82 | /// Eventually, when we thread semantic analysis, we will want one of these per thread. | 83 | /// Eventually, when we thread semantic analysis, we will want one of these per thread. |
| 83 | cur_sema_prog_node: std.Progress.Node = .none, | 84 | cur_sema_prog_node: std.Progress.Node, |
| 84 | 85 | ||
| 85 | /// Used by AstGen worker to load and store ZIR cache. | 86 | /// Used by AstGen worker to load and store ZIR cache. |
| 86 | global_zir_cache: Cache.Directory, | 87 | global_zir_cache: Cache.Directory, |
| ... | @@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory, | ... | @@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory, |
| 89 | 90 | ||
| 90 | /// This is where all `Export` values are stored. Not all values here are necessarily valid exports; | 91 | /// This is where all `Export` values are stored. Not all values here are necessarily valid exports; |
| 91 | /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted. | 92 | /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted. |
| 92 | all_exports: std.ArrayList(Export) = .empty, | 93 | all_exports: std.ArrayList(Export), |
| 93 | /// This is a list of free indices in `all_exports`. These indices may be reused by exports from | 94 | /// This is a list of free indices in `all_exports`. These indices may be reused by exports from |
| 94 | /// future semantic analysis. | 95 | /// future semantic analysis. |
| 95 | free_exports: std.ArrayList(Export.Index) = .empty, | 96 | free_exports: std.ArrayList(Export.Index), |
| 96 | /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of | 97 | /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of |
| 97 | /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` | 98 | /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` |
| 98 | /// whose analysis triggered the export. | 99 | /// whose analysis triggered the export. |
| 99 | single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty, | 100 | single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index), |
| 100 | /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. | 101 | /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. |
| 101 | /// The exports are `all_exports.items[index..][0..len]`. | 102 | /// The exports are `all_exports.items[index..][0..len]`. |
| 102 | multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct { | 103 | multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct { |
| 103 | index: u32, | 104 | index: u32, |
| 104 | len: u32, | 105 | len: u32, |
| 105 | }) = .empty, | 106 | }), |
| 106 | |||
| 107 | /// Key is the digest returned by `Builtin.hash`; value is the corresponding module. | ||
| 108 | builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module) = .empty, | ||
| 109 | 107 | ||
| 110 | /// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones. | 108 | /// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones. |
| 111 | /// Modules whose root file is not a Zig or ZON file have the value `.none`. | 109 | /// Modules whose root file is not a Zig or ZON file have the value `.none`. |
| 112 | module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional) = .empty, | 110 | module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional), |
| 111 | /// Key is the digest returned by `Builtin.hash`; value is the corresponding module. | ||
| 112 | builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module), | ||
| 113 | 113 | ||
| 114 | /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in | 114 | /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in |
| 115 | /// order to iterate over it and check which source files have been modified on | 115 | /// order to iterate over it and check which source files have been modified on |
| ... | @@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom( | ... | @@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom( |
| 132 | pub const eql = @compileError("all accesses should be through ImportTableAdapter"); | 132 | pub const eql = @compileError("all accesses should be through ImportTableAdapter"); |
| 133 | }, | 133 | }, |
| 134 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 | 134 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 |
| 135 | ) = .empty, | 135 | ), |
| 136 | |||
| 137 | /// The set of all files in `import_table` which are "alive" this update, meaning | 136 | /// The set of all files in `import_table` which are "alive" this update, meaning |
| 138 | /// they are reachable by traversing imports starting from an analysis root. This | 137 | /// they are reachable by traversing imports starting from an analysis root. This |
| 139 | /// is usually all files in `import_table`, but some could be omitted if an incremental | 138 | /// is usually all files in `import_table`, but some could be omitted if an incremental |
| 140 | /// update removes an import, or if a module specified on the CLI is never imported. | 139 | /// update removes an import, or if a module specified on the CLI is never imported. |
| 141 | /// Reconstructed on every update, after AstGen and before Sema. | 140 | /// Reconstructed on every update, after AstGen and before Sema. |
| 142 | /// Value is why the file is alive. | 141 | /// Value is why the file is alive. |
| 143 | alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty, | 142 | alive_files: std.array_hash_map.Auto(File.Index, File.Reference), |
| 144 | |||
| 145 | /// If this is populated, a "file exists in multiple modules" error should be emitted. | ||
| 146 | /// This causes file errors to not be shown, because we don't really know which files | ||
| 147 | /// should be alive (because the user has messed up their imports somewhere!). | ||
| 148 | /// Cleared and recomputed every update, after AstGen and before Sema. | ||
| 149 | multi_module_err: ?struct { | ||
| 150 | file: File.Index, | ||
| 151 | modules: [2]*Module, | ||
| 152 | refs: [2]File.Reference, | ||
| 153 | } = null, | ||
| 154 | |||
| 155 | /// The set of all the files which have been loaded with `@embedFile` in the Module. | 143 | /// The set of all the files which have been loaded with `@embedFile` in the Module. |
| 156 | /// We keep track of this in order to iterate over it and check which files have been | 144 | /// We keep track of this in order to iterate over it and check which files have been |
| 157 | /// modified on the file system when an update is requested, as well as to cache | 145 | /// modified on the file system when an update is requested, as well as to cache |
| ... | @@ -162,49 +150,19 @@ multi_module_err: ?struct { | ... | @@ -162,49 +150,19 @@ multi_module_err: ?struct { |
| 162 | /// | 150 | /// |
| 163 | /// This table owns all of the `*EmbedFile` memory, which is allocated into gpa. | 151 | /// This table owns all of the `*EmbedFile` memory, which is allocated into gpa. |
| 164 | embed_table: std.array_hash_map.Custom( | 152 | embed_table: std.array_hash_map.Custom( |
| 165 | *EmbedFile, | 153 | EmbedFile, |
| 166 | void, | 154 | void, |
| 167 | struct { | 155 | struct { |
| 168 | pub const hash = @compileError("all accesses should be through EmbedTableAdapter"); | 156 | pub const hash = @compileError("all accesses should be through EmbedTableAdapter"); |
| 169 | pub const eql = @compileError("all accesses should be through EmbedTableAdapter"); | 157 | pub const eql = @compileError("all accesses should be through EmbedTableAdapter"); |
| 170 | }, | 158 | }, |
| 171 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 | 159 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 |
| 172 | ) = .empty, | 160 | ), |
| 173 | 161 | ||
| 174 | /// Stores all Type and Value objects. | 162 | /// Stores all Type and Value objects. |
| 175 | /// The idea is that this will be periodically garbage-collected, but such logic | 163 | /// The idea is that this will be periodically garbage-collected, but such logic |
| 176 | /// is not yet implemented. | 164 | /// is not yet implemented. |
| 177 | intern_pool: InternPool = .empty, | 165 | intern_pool: InternPool, |
| 178 | |||
| 179 | /// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis | ||
| 180 | /// (index 0), and non-`null` for all others. | ||
| 181 | analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason) = .empty, | ||
| 182 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | ||
| 183 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, | ||
| 184 | /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. | ||
| 185 | transitive_failed_analysis: std.array_hash_map.Auto( | ||
| 186 | AnalUnit, | ||
| 187 | if (build_options.enable_debug_extensions) TransitiveFailureReason else void, | ||
| 188 | ) = .empty, | ||
| 189 | /// This `Nav` succeeded analysis, but failed codegen. | ||
| 190 | /// This may be a simple "value" `Nav`, or it may be a function. | ||
| 191 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | ||
| 192 | /// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as | ||
| 193 | /// codegen and linking run on a separate thread. | ||
| 194 | failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty, | ||
| 195 | failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg) = .empty, | ||
| 196 | |||
| 197 | /// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one | ||
| 198 | /// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible | ||
| 199 | /// between compilations. So, instead of (for instance) defining where the dependency loop "starts", | ||
| 200 | /// this map simply exists to allow easily iterating all dependency loops exactly once. | ||
| 201 | dependency_loops: std.array_hash_map.Auto(AnalUnit, void) = .empty, | ||
| 202 | /// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so. | ||
| 203 | /// All units in here form loops. To iterate loops, see `dependency_loops`. | ||
| 204 | dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { | ||
| 205 | unit: AnalUnit, | ||
| 206 | reason: DependencyReason, | ||
| 207 | }) = .empty, | ||
| 208 | 166 | ||
| 209 | /// Keep track of `@compileLog`s per `AnalUnit`. | 167 | /// Keep track of `@compileLog`s per `AnalUnit`. |
| 210 | /// We track the source location of the first `@compileLog` call, and all logged lines as a linked list. | 168 | /// We track the source location of the first `@compileLog` call, and all logged lines as a linked list. |
| ... | @@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct { | ... | @@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct { |
| 220 | .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset), | 178 | .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset), |
| 221 | }; | 179 | }; |
| 222 | } | 180 | } |
| 223 | }) = .empty, | 181 | }), |
| 224 | compile_log_lines: std.ArrayList(CompileLogLine) = .empty, | 182 | compile_log_lines: std.ArrayList(CompileLogLine), |
| 225 | free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty, | 183 | free_compile_log_lines: std.ArrayList(CompileLogLine.Index), |
| 226 | /// This tracks files which triggered errors when generating AST/ZIR/ZOIR. | 184 | |
| 227 | /// If not `null`, the value is a retryable error (the file status is guaranteed | 185 | illegal_module_root: ?*Module, |
| 228 | /// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` | 186 | /// If this is populated, a "file exists in multiple modules" error should be emitted. |
| 229 | /// or `.success`, and there are ZIR/ZOIR errors which should be printed. | 187 | /// This causes file errors to not be shown, because we don't really know which files |
| 230 | /// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source | 188 | /// should be alive (because the user has messed up their imports somewhere!). |
| 231 | /// location is always the entire file. The `[]u8` memory is owned by the map | 189 | /// Cleared and recomputed every update, after AstGen and before Sema. |
| 232 | /// and allocated into `gpa`. | 190 | multi_module_err: ?struct { |
| 233 | failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty, | 191 | file: File.Index, |
| 192 | modules: [2]*Module, | ||
| 193 | refs: [2]File.Reference, | ||
| 194 | }, | ||
| 234 | /// AstGen is not aware of modules, and so cannot determine whether an import | 195 | /// AstGen is not aware of modules, and so cannot determine whether an import |
| 235 | /// string makes sense. That is the job of a traversal after AstGen. | 196 | /// string makes sense. That is the job of a traversal after AstGen. |
| 236 | /// | 197 | /// |
| ... | @@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct { | ... | @@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct { |
| 257 | import_string: Zir.NullTerminatedString, | 218 | import_string: Zir.NullTerminatedString, |
| 258 | import_token: Ast.TokenIndex, | 219 | import_token: Ast.TokenIndex, |
| 259 | kind: enum { file_outside_module_root, illegal_zig_import }, | 220 | kind: enum { file_outside_module_root, illegal_zig_import }, |
| 260 | }) = .empty, | 221 | }), |
| 261 | failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty, | 222 | /// This tracks files which triggered errors when generating AST/ZIR/ZOIR. |
| 262 | /// If analysis failed due to a cimport error, the corresponding Clang errors | 223 | /// If not `null`, the value is a retryable error (the file status is guaranteed |
| 263 | /// are stored here. | 224 | /// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` |
| 264 | cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty, | 225 | /// or `.success`, and there are ZIR/ZOIR errors which should be printed. |
| 226 | /// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source | ||
| 227 | /// location is always the entire file. The `[]u8` memory is owned by the map | ||
| 228 | /// and allocated into `gpa`. | ||
| 229 | failed_files: std.array_hash_map.Auto(File.Index, ?[]u8), | ||
| 230 | /// If `true`, then semantic analysis must not occur on this update due to AstGen errors. | ||
| 231 | /// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. | ||
| 232 | /// Reset to `false` at the start of each update in `Compilation.update`. | ||
| 233 | skip_analysis_this_update: bool, | ||
| 234 | /// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis | ||
| 235 | /// (index 0), and non-`null` for all others. | ||
| 236 | analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason), | ||
| 237 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | ||
| 238 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg), | ||
| 239 | /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. | ||
| 240 | transitive_failed_analysis: std.array_hash_map.Auto( | ||
| 241 | AnalUnit, | ||
| 242 | if (build_options.enable_debug_extensions) TransitiveFailureReason else void, | ||
| 243 | ), | ||
| 244 | /// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one | ||
| 245 | /// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible | ||
| 246 | /// between compilations. So, instead of (for instance) defining where the dependency loop "starts", | ||
| 247 | /// this map simply exists to allow easily iterating all dependency loops exactly once. | ||
| 248 | dependency_loops: std.array_hash_map.Auto(AnalUnit, void), | ||
| 249 | /// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so. | ||
| 250 | /// All units in here form loops. To iterate loops, see `dependency_loops`. | ||
| 251 | dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { | ||
| 252 | unit: AnalUnit, | ||
| 253 | reason: DependencyReason, | ||
| 254 | }), | ||
| 255 | /// This `Nav` succeeded analysis, but failed codegen. | ||
| 256 | /// This may be a simple "value" `Nav`, or it may be a function. | ||
| 257 | /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. | ||
| 258 | /// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as | ||
| 259 | /// codegen and linking run on a separate thread. | ||
| 260 | failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg), | ||
| 261 | failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg), | ||
| 262 | failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg), | ||
| 265 | 263 | ||
| 266 | /// Maximum amount of distinct error values, set by --error-limit | 264 | /// Maximum amount of distinct error values, set by --error-limit |
| 267 | error_limit: ErrorInt, | 265 | error_limit: ErrorInt, |
| ... | @@ -269,14 +267,14 @@ error_limit: ErrorInt, | ... | @@ -269,14 +267,14 @@ error_limit: ErrorInt, |
| 269 | /// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock | 267 | /// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock |
| 270 | /// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the | 268 | /// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the |
| 271 | /// lock is not needed and is compiled out. | 269 | /// lock is not needed and is compiled out. |
| 272 | outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init, | 270 | outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void, |
| 273 | /// Value is the number of PO dependencies of this AnalUnit. | 271 | /// Value is the number of PO dependencies of this AnalUnit. |
| 274 | /// This value will decrease as we perform semantic analysis to learn what is outdated. | 272 | /// This value will decrease as we perform semantic analysis to learn what is outdated. |
| 275 | /// If any of these PO deps is outdated, this value will be moved to `outdated`. | 273 | /// If any of these PO deps is outdated, this value will be moved to `outdated`. |
| 276 | potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | 274 | potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32), |
| 277 | /// Value is the number of PO dependencies of this AnalUnit. | 275 | /// Value is the number of PO dependencies of this AnalUnit. |
| 278 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. | 276 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. |
| 279 | outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | 277 | outdated: std.array_hash_map.Auto(AnalUnit, u32), |
| 280 | /// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0. | 278 | /// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0. |
| 281 | /// Such `AnalUnit`s are ready for immediate re-analysis. | 279 | /// Such `AnalUnit`s are ready for immediate re-analysis. |
| 282 | /// See `findOutdatedToAnalyze` for details. | 280 | /// See `findOutdatedToAnalyze` for details. |
| ... | @@ -286,69 +284,64 @@ outdated_ready: struct { | ... | @@ -286,69 +284,64 @@ outdated_ready: struct { |
| 286 | funcs: std.array_hash_map.Auto(InternPool.Index, void), | 284 | funcs: std.array_hash_map.Auto(InternPool.Index, void), |
| 287 | /// Does not contain `.func` units. | 285 | /// Does not contain `.func` units. |
| 288 | other: std.array_hash_map.Auto(AnalUnit, void), | 286 | other: std.array_hash_map.Auto(AnalUnit, void), |
| 289 | } = .{ .funcs = .empty, .other = .empty }, | 287 | }, |
| 290 | /// This contains a list of AnalUnit whose analysis or codegen failed, but the | 288 | /// This contains a list of AnalUnit whose analysis or codegen failed, but the |
| 291 | /// failure was something like running out of disk space, and trying again may | 289 | /// failure was something like running out of disk space, and trying again may |
| 292 | /// succeed. On the next update, we will flush this list, marking all members of | 290 | /// succeed. On the next update, we will flush this list, marking all members of |
| 293 | /// it as outdated. | 291 | /// it as outdated. |
| 294 | retryable_failures: std.ArrayList(AnalUnit) = .empty, | 292 | retryable_failures: std.ArrayList(AnalUnit), |
| 295 | 293 | ||
| 296 | /// These are the modules which we initially queue for analysis in `Compilation.update`. | 294 | /// These are the modules which we initially queue for analysis in `Compilation.update`. |
| 297 | /// `resolveReferences` will use these as the root of its reachability traversal. | 295 | /// `resolveReferences` will use these as the root of its reachability traversal. |
| 298 | analysis_roots_buffer: [5]*Module, | 296 | analysis_roots_buffer: [5]*Module, |
| 299 | analysis_roots_len: usize = 0, | 297 | analysis_roots_len: usize, |
| 300 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and | 298 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and |
| 301 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). | 299 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). |
| 302 | /// Allocated into `gpa`. | 300 | /// Allocated into `gpa`. |
| 303 | resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null, | 301 | resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference), |
| 304 | |||
| 305 | /// If `true`, then semantic analysis must not occur on this update due to AstGen errors. | ||
| 306 | /// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. | ||
| 307 | /// Reset to `false` at the start of each update in `Compilation.update`. | ||
| 308 | skip_analysis_this_update: bool = false, | ||
| 309 | 302 | ||
| 310 | test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, | 303 | test_filters: []const []const u8, |
| 304 | test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void), | ||
| 311 | 305 | ||
| 312 | global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty, | 306 | global_assembly: std.array_hash_map.Auto(AnalUnit, []u8), |
| 313 | 307 | ||
| 314 | /// Key is the `AnalUnit` *performing* the reference. This representation allows | 308 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 315 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. | 309 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 316 | /// Value is index into `all_references` of the first reference triggered by the unit. | 310 | /// Value is index into `all_references` of the first reference triggered by the unit. |
| 317 | /// The `next` field on the `Reference` forms a linked list of all references | 311 | /// The `next` field on the `Reference` forms a linked list of all references |
| 318 | /// triggered by the key `AnalUnit`. | 312 | /// triggered by the key `AnalUnit`. |
| 319 | reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | 313 | reference_table: std.array_hash_map.Auto(AnalUnit, u32), |
| 320 | all_references: std.ArrayList(Reference) = .empty, | 314 | all_references: std.ArrayList(Reference), |
| 321 | /// Freelist of indices in `all_references`. | 315 | /// Freelist of indices in `all_references`. |
| 322 | free_references: std.ArrayList(u32) = .empty, | 316 | free_references: std.ArrayList(u32), |
| 323 | 317 | ||
| 324 | inline_reference_frames: std.ArrayList(InlineReferenceFrame) = .empty, | 318 | inline_reference_frames: std.ArrayList(InlineReferenceFrame), |
| 325 | free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty, | 319 | free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index), |
| 326 | 320 | ||
| 327 | /// Key is the `AnalUnit` *performing* the reference. This representation allows | 321 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 328 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. | 322 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 329 | /// Value is index into `all_type_reference` of the first reference triggered by the unit. | 323 | /// Value is index into `all_type_reference` of the first reference triggered by the unit. |
| 330 | /// The `next` field on the `TypeReference` forms a linked list of all type references | 324 | /// The `next` field on the `TypeReference` forms a linked list of all type references |
| 331 | /// triggered by the key `AnalUnit`. | 325 | /// triggered by the key `AnalUnit`. |
| 332 | type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | 326 | type_reference_table: std.array_hash_map.Auto(AnalUnit, u32), |
| 333 | all_type_references: std.ArrayList(TypeReference) = .empty, | 327 | all_type_references: std.ArrayList(TypeReference), |
| 334 | /// Freelist of indices in `all_type_references`. | 328 | /// Freelist of indices in `all_type_references`. |
| 335 | free_type_references: std.ArrayList(u32) = .empty, | 329 | free_type_references: std.ArrayList(u32), |
| 336 | 330 | ||
| 337 | /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element. | 331 | /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element. |
| 338 | std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none), | 332 | std_lang_decl_values: StdLangDecl.Memoized, |
| 339 | 333 | ||
| 340 | incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void = | 334 | incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void, |
| 341 | if (build_options.enable_debug_extensions) .init else {}, | ||
| 342 | 335 | ||
| 343 | /// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit, | 336 | /// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit, |
| 344 | /// this timer must be temporarily paused and resumed later. | 337 | /// this timer must be temporarily paused and resumed later. |
| 345 | cur_analysis_timer: ?Compilation.Timer = null, | 338 | cur_analysis_timer: ?Compilation.Timer, |
| 346 | 339 | ||
| 347 | codegen_task_pool: CodegenTaskPool, | 340 | codegen_task_pool: CodegenTaskPool, |
| 348 | 341 | ||
| 349 | generation: u32 = 0, | 342 | generation: u32, |
| 350 | 343 | ||
| 351 | /// Only access from the Sema thread. | 344 | /// Only accessed from the Sema thread. |
| 352 | anon_name_counter: u32, | 345 | anon_name_counter: u32, |
| 353 | 346 | ||
| 354 | pub const DependencyReason = struct { | 347 | pub const DependencyReason = struct { |
| ... | @@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct { | ... | @@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct { |
| 434 | _ = ctx; | 427 | _ = ctx; |
| 435 | return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path)); | 428 | return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path)); |
| 436 | } | 429 | } |
| 437 | pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool { | 430 | pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: EmbedFile, b_index: usize) bool { |
| 438 | _ = ctx; | 431 | _ = ctx; |
| 439 | _ = b_index; | 432 | _ = b_index; |
| 440 | const b_path = b_file.path; | 433 | const b_path = b_file.path; |
| ... | @@ -1250,10 +1243,15 @@ pub const EmbedFile = struct { | ... | @@ -1250,10 +1243,15 @@ pub const EmbedFile = struct { |
| 1250 | 1243 | ||
| 1251 | pub const Index = enum(u32) { | 1244 | pub const Index = enum(u32) { |
| 1252 | _, | 1245 | _, |
| 1253 | pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile { | 1246 | pub fn get(idx: Index, zcu: *const Zcu) *const EmbedFile { |
| 1254 | return zcu.embed_table.keys()[@backingInt(idx)]; | 1247 | return &zcu.embed_table.keys()[@backingInt(idx)]; |
| 1255 | } | 1248 | } |
| 1256 | }; | 1249 | }; |
| 1250 | |||
| 1251 | pub fn deinit(ef: *EmbedFile, gpa: Allocator) void { | ||
| 1252 | ef.path.deinit(gpa); | ||
| 1253 | ef.* = undefined; | ||
| 1254 | } | ||
| 1257 | }; | 1255 | }; |
| 1258 | 1256 | ||
| 1259 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. | 1257 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. |
| ... | @@ -2894,16 +2892,130 @@ pub const CompileError = error{ | ... | @@ -2894,16 +2892,130 @@ pub const CompileError = error{ |
| 2894 | ComptimeBreak, | 2892 | ComptimeBreak, |
| 2895 | }; | 2893 | }; |
| 2896 | 2894 | ||
| 2897 | pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { | ||
| 2898 | try zcu.intern_pool.init(gpa, io, thread_count); | ||
| 2899 | } | ||
| 2900 | |||
| 2901 | /// It is valid to not call this function before `deinit` in error paths. | 2895 | /// It is valid to not call this function before `deinit` in error paths. |
| 2902 | /// Requires the fields on `zcu.comp` to already be initialized. | 2896 | /// Requires the fields on `zcu.comp` to already be initialized. |
| 2903 | pub fn initAfterCompilation(zcu: *Zcu) void { | 2897 | pub fn init(zcu: *Zcu) void { |
| 2904 | zcu.initTracyPlots(); | 2898 | zcu.initTracyPlots(); |
| 2905 | } | 2899 | } |
| 2906 | 2900 | ||
| 2901 | pub fn reset(zcu: *Zcu, arena: Allocator) Allocator.Error!void { | ||
| 2902 | const comp = zcu.comp; | ||
| 2903 | const gpa = comp.gpa; | ||
| 2904 | const io = comp.io; | ||
| 2905 | |||
| 2906 | zcu.all_exports.clearRetainingCapacity(); | ||
| 2907 | zcu.free_exports.clearRetainingCapacity(); | ||
| 2908 | zcu.single_exports.clearRetainingCapacity(); | ||
| 2909 | zcu.multi_exports.clearRetainingCapacity(); | ||
| 2910 | |||
| 2911 | zcu.module_roots.clearRetainingCapacity(); | ||
| 2912 | // builtin modules can still be reused from a previous non-incremental update | ||
| 2913 | |||
| 2914 | for (zcu.import_table.keys()) |file| zcu.destroyFile(file); | ||
| 2915 | zcu.import_table.clearRetainingCapacity(); | ||
| 2916 | zcu.alive_files.clearRetainingCapacity(); | ||
| 2917 | for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa); | ||
| 2918 | zcu.embed_table.clearRetainingCapacity(); | ||
| 2919 | |||
| 2920 | zcu.compile_logs.clearRetainingCapacity(); | ||
| 2921 | zcu.compile_log_lines.clearRetainingCapacity(); | ||
| 2922 | zcu.free_compile_log_lines.clearRetainingCapacity(); | ||
| 2923 | |||
| 2924 | zcu.illegal_module_root = null; | ||
| 2925 | zcu.multi_module_err = null; | ||
| 2926 | zcu.failed_imports.clearRetainingCapacity(); | ||
| 2927 | for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg); | ||
| 2928 | zcu.failed_files.clearRetainingCapacity(); | ||
| 2929 | zcu.analysis_in_progress.clearRetainingCapacity(); | ||
| 2930 | for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa); | ||
| 2931 | zcu.failed_analysis.clearRetainingCapacity(); | ||
| 2932 | zcu.transitive_failed_analysis.clearRetainingCapacity(); | ||
| 2933 | zcu.dependency_loops.clearRetainingCapacity(); | ||
| 2934 | zcu.dependency_loop_nodes.clearRetainingCapacity(); | ||
| 2935 | for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa); | ||
| 2936 | zcu.failed_codegen.clearRetainingCapacity(); | ||
| 2937 | for (zcu.failed_types.values()) |msg| msg.destroy(gpa); | ||
| 2938 | zcu.failed_types.clearRetainingCapacity(); | ||
| 2939 | for (zcu.failed_exports.values()) |msg| msg.destroy(gpa); | ||
| 2940 | zcu.failed_exports.clearRetainingCapacity(); | ||
| 2941 | |||
| 2942 | assert(zcu.potentially_outdated.count() == 0); | ||
| 2943 | assert(zcu.outdated.count() == 0); | ||
| 2944 | assert(zcu.outdated_ready.funcs.count() == 0); | ||
| 2945 | assert(zcu.outdated_ready.other.count() == 0); | ||
| 2946 | zcu.retryable_failures.clearRetainingCapacity(); | ||
| 2947 | |||
| 2948 | zcu.analysis_roots_len = 0; | ||
| 2949 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; | ||
| 2950 | zcu.analysis_roots_len += 1; | ||
| 2951 | // Normally we rely on importing std to in turn import the root source file in the start code. | ||
| 2952 | // However, the main module is distinct from the root module in tests, so that won't happen there. | ||
| 2953 | if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { | ||
| 2954 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; | ||
| 2955 | zcu.analysis_roots_len += 1; | ||
| 2956 | } | ||
| 2957 | if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { | ||
| 2958 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; | ||
| 2959 | zcu.analysis_roots_len += 1; | ||
| 2960 | } | ||
| 2961 | if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { | ||
| 2962 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; | ||
| 2963 | zcu.analysis_roots_len += 1; | ||
| 2964 | } | ||
| 2965 | if (zcu.root_mod.deps.get("zigc")) |zigc_mod| { | ||
| 2966 | zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod; | ||
| 2967 | zcu.analysis_roots_len += 1; | ||
| 2968 | } | ||
| 2969 | zcu.clearCachedResolvedReferences(); | ||
| 2970 | |||
| 2971 | zcu.test_functions.clearRetainingCapacity(); | ||
| 2972 | |||
| 2973 | zcu.global_assembly.clearRetainingCapacity(); | ||
| 2974 | |||
| 2975 | zcu.reference_table.clearRetainingCapacity(); | ||
| 2976 | zcu.all_references.clearRetainingCapacity(); | ||
| 2977 | zcu.free_references.clearRetainingCapacity(); | ||
| 2978 | |||
| 2979 | zcu.inline_reference_frames.clearRetainingCapacity(); | ||
| 2980 | zcu.free_inline_reference_frames.clearRetainingCapacity(); | ||
| 2981 | |||
| 2982 | zcu.type_reference_table.clearRetainingCapacity(); | ||
| 2983 | zcu.all_type_references.clearRetainingCapacity(); | ||
| 2984 | zcu.free_type_references.clearRetainingCapacity(); | ||
| 2985 | |||
| 2986 | zcu.std_lang_decl_values = .initFill(.none); | ||
| 2987 | |||
| 2988 | for (zcu.codegen_task_pool.task_funcs) |task_func| assert(task_func == .none); | ||
| 2989 | |||
| 2990 | assert(zcu.generation == 0); | ||
| 2991 | |||
| 2992 | zcu.anon_name_counter = 0; | ||
| 2993 | |||
| 2994 | zcu.intern_pool.deinit(gpa, io); | ||
| 2995 | zcu.intern_pool = .empty; | ||
| 2996 | try zcu.intern_pool.init(gpa, io, comp.thread_limit); | ||
| 2997 | |||
| 2998 | { | ||
| 2999 | const active = zcu.acquire(); | ||
| 3000 | defer active.release(); | ||
| 3001 | try active.pt.populateModuleRootTable(); | ||
| 3002 | } | ||
| 3003 | |||
| 3004 | assert(zcu.llvm_object == null); | ||
| 3005 | if (comp.config.use_llvm and | ||
| 3006 | (comp.emit_bin != null or | ||
| 3007 | comp.emit_asm != null or | ||
| 3008 | comp.emit_llvm_ir != null or | ||
| 3009 | comp.emit_llvm_bc != null or | ||
| 3010 | log_llvm_ir: { | ||
| 3011 | break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir"); | ||
| 3012 | })) | ||
| 3013 | { | ||
| 3014 | dev.check(.llvm_backend); | ||
| 3015 | zcu.llvm_object = try .create(if (comp.config.incremental) comp.arena else arena, zcu); | ||
| 3016 | } | ||
| 3017 | } | ||
| 3018 | |||
| 2907 | pub fn deinit(zcu: *Zcu) void { | 3019 | pub fn deinit(zcu: *Zcu) void { |
| 2908 | const comp = zcu.comp; | 3020 | const comp = zcu.comp; |
| 2909 | const io = comp.io; | 3021 | const io = comp.io; |
| ... | @@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void { | ... | @@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void { |
| 2911 | { | 3023 | { |
| 2912 | if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); | 3024 | if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); |
| 2913 | 3025 | ||
| 2914 | zcu.builtin_modules.deinit(gpa); | 3026 | zcu.global_zir_cache.handle.close(io); |
| 3027 | zcu.local_zir_cache.handle.close(io); | ||
| 3028 | |||
| 3029 | zcu.all_exports.deinit(gpa); | ||
| 3030 | zcu.free_exports.deinit(gpa); | ||
| 3031 | zcu.single_exports.deinit(gpa); | ||
| 3032 | zcu.multi_exports.deinit(gpa); | ||
| 3033 | |||
| 2915 | zcu.module_roots.deinit(gpa); | 3034 | zcu.module_roots.deinit(gpa); |
| 2916 | for (zcu.import_table.keys()) |file_index| { | 3035 | zcu.builtin_modules.deinit(gpa); |
| 2917 | zcu.destroyFile(file_index); | 3036 | |
| 2918 | } | 3037 | for (zcu.import_table.keys()) |file| zcu.destroyFile(file); |
| 2919 | zcu.import_table.deinit(gpa); | 3038 | zcu.import_table.deinit(gpa); |
| 2920 | zcu.alive_files.deinit(gpa); | 3039 | zcu.alive_files.deinit(gpa); |
| 2921 | 3040 | for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa); | |
| 2922 | for (zcu.embed_table.keys()) |embed_file| { | ||
| 2923 | embed_file.path.deinit(gpa); | ||
| 2924 | gpa.destroy(embed_file); | ||
| 2925 | } | ||
| 2926 | zcu.embed_table.deinit(gpa); | 3041 | zcu.embed_table.deinit(gpa); |
| 2927 | 3042 | ||
| 2928 | zcu.local_zir_cache.handle.close(io); | 3043 | zcu.compile_logs.deinit(gpa); |
| 2929 | zcu.global_zir_cache.handle.close(io); | 3044 | zcu.compile_log_lines.deinit(gpa); |
| 3045 | zcu.free_compile_log_lines.deinit(gpa); | ||
| 2930 | 3046 | ||
| 2931 | for (zcu.failed_analysis.values()) |value| value.destroy(gpa); | 3047 | zcu.failed_imports.deinit(gpa); |
| 2932 | for (zcu.failed_codegen.values()) |value| value.destroy(gpa); | 3048 | for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg); |
| 2933 | for (zcu.failed_types.values()) |value| value.destroy(gpa); | 3049 | zcu.failed_files.deinit(gpa); |
| 2934 | zcu.analysis_in_progress.deinit(gpa); | 3050 | zcu.analysis_in_progress.deinit(gpa); |
| 3051 | for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa); | ||
| 2935 | zcu.failed_analysis.deinit(gpa); | 3052 | zcu.failed_analysis.deinit(gpa); |
| 2936 | zcu.transitive_failed_analysis.deinit(gpa); | 3053 | zcu.transitive_failed_analysis.deinit(gpa); |
| 2937 | zcu.dependency_loops.deinit(gpa); | 3054 | zcu.dependency_loops.deinit(gpa); |
| 2938 | zcu.dependency_loop_nodes.deinit(gpa); | 3055 | zcu.dependency_loop_nodes.deinit(gpa); |
| 3056 | for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa); | ||
| 2939 | zcu.failed_codegen.deinit(gpa); | 3057 | zcu.failed_codegen.deinit(gpa); |
| 3058 | for (zcu.failed_types.values()) |msg| msg.destroy(gpa); | ||
| 2940 | zcu.failed_types.deinit(gpa); | 3059 | zcu.failed_types.deinit(gpa); |
| 2941 | 3060 | for (zcu.failed_exports.values()) |msg| msg.destroy(gpa); | |
| 2942 | for (zcu.failed_files.values()) |value| { | ||
| 2943 | if (value) |msg| gpa.free(msg); | ||
| 2944 | } | ||
| 2945 | zcu.failed_files.deinit(gpa); | ||
| 2946 | zcu.failed_imports.deinit(gpa); | ||
| 2947 | |||
| 2948 | for (zcu.failed_exports.values()) |value| { | ||
| 2949 | value.destroy(gpa); | ||
| 2950 | } | ||
| 2951 | zcu.failed_exports.deinit(gpa); | 3061 | zcu.failed_exports.deinit(gpa); |
| 2952 | 3062 | ||
| 2953 | for (zcu.cimport_errors.values()) |*errs| { | ||
| 2954 | errs.deinit(gpa); | ||
| 2955 | } | ||
| 2956 | zcu.cimport_errors.deinit(gpa); | ||
| 2957 | |||
| 2958 | zcu.compile_logs.deinit(gpa); | ||
| 2959 | zcu.compile_log_lines.deinit(gpa); | ||
| 2960 | zcu.free_compile_log_lines.deinit(gpa); | ||
| 2961 | |||
| 2962 | zcu.all_exports.deinit(gpa); | ||
| 2963 | zcu.free_exports.deinit(gpa); | ||
| 2964 | zcu.single_exports.deinit(gpa); | ||
| 2965 | zcu.multi_exports.deinit(gpa); | ||
| 2966 | |||
| 2967 | zcu.potentially_outdated.deinit(gpa); | 3063 | zcu.potentially_outdated.deinit(gpa); |
| 2968 | zcu.outdated.deinit(gpa); | 3064 | zcu.outdated.deinit(gpa); |
| 2969 | zcu.outdated_ready.funcs.deinit(gpa); | 3065 | zcu.outdated_ready.funcs.deinit(gpa); |
| 2970 | zcu.outdated_ready.other.deinit(gpa); | 3066 | zcu.outdated_ready.other.deinit(gpa); |
| 2971 | zcu.retryable_failures.deinit(gpa); | 3067 | zcu.retryable_failures.deinit(gpa); |
| 2972 | 3068 | ||
| 3069 | if (zcu.resolved_references) |*r| r.deinit(gpa); | ||
| 3070 | |||
| 2973 | zcu.test_functions.deinit(gpa); | 3071 | zcu.test_functions.deinit(gpa); |
| 2974 | 3072 | ||
| 2975 | for (zcu.global_assembly.values()) |s| { | 3073 | for (zcu.global_assembly.values()) |s| gpa.free(s); |
| 2976 | gpa.free(s); | ||
| 2977 | } | ||
| 2978 | zcu.global_assembly.deinit(gpa); | 3074 | zcu.global_assembly.deinit(gpa); |
| 2979 | 3075 | ||
| 2980 | zcu.reference_table.deinit(gpa); | 3076 | zcu.reference_table.deinit(gpa); |
| ... | @@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void { | ... | @@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void { |
| 2988 | zcu.all_type_references.deinit(gpa); | 3084 | zcu.all_type_references.deinit(gpa); |
| 2989 | zcu.free_type_references.deinit(gpa); | 3085 | zcu.free_type_references.deinit(gpa); |
| 2990 | 3086 | ||
| 2991 | if (zcu.resolved_references) |*r| r.deinit(gpa); | ||
| 2992 | |||
| 2993 | if (comp.debugIncremental()) { | 3087 | if (comp.debugIncremental()) { |
| 2994 | zcu.incremental_debug_state.deinit(gpa); | 3088 | zcu.incremental_debug_state.deinit(gpa); |
| 2995 | } | 3089 | } |
| ... | @@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana | ... | @@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana |
| 4352 | .unnamed_test => true, | 4446 | .unnamed_test => true, |
| 4353 | .@"test", .decltest => a: { | 4447 | .@"test", .decltest => a: { |
| 4354 | const fqn_slice = nav.fqn.toSlice(ip); | 4448 | const fqn_slice = nav.fqn.toSlice(ip); |
| 4355 | if (comp.test_filters.len > 0) { | 4449 | if (zcu.test_filters.len > 0) { |
| 4356 | for (comp.test_filters) |test_filter| { | 4450 | for (zcu.test_filters) |test_filter| { |
| 4357 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; | 4451 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; |
| 4358 | } else break :a false; | 4452 | } else break :a false; |
| 4359 | } | 4453 | } |
src/Zcu/PerThread.zig+46-44| ... | @@ -148,6 +148,12 @@ pub fn update( | ... | @@ -148,6 +148,12 @@ pub fn update( |
| 148 | comp.link_queue.finishZcuQueue(comp); | 148 | comp.link_queue.finishZcuQueue(comp); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | if (zcu.illegal_module_root) |_| { | ||
| 152 | // We cannot run AstGen because we failed to set up the module roots. We can return early | ||
| 153 | // because this is a guaranteed compile error. | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 151 | { | 157 | { |
| 152 | const tracy_trace = traceNamed(@src(), "astgen"); | 158 | const tracy_trace = traceNamed(@src(), "astgen"); |
| 153 | defer tracy_trace.end(); | 159 | defer tracy_trace.end(); |
| ... | @@ -203,11 +209,9 @@ pub fn update( | ... | @@ -203,11 +209,9 @@ pub fn update( |
| 203 | // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here | 209 | // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here |
| 204 | // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one | 210 | // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one |
| 205 | // `@embedFile` can't trigger analysis of a new `@embedFile`! | 211 | // `@embedFile` can't trigger analysis of a new `@embedFile`! |
| 206 | for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| { | 212 | for (0.., zcu.embed_table.keys()) |ef_index_usize, *ef| { |
| 207 | const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize)); | 213 | const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize)); |
| 208 | astgen_group.async(io, workerUpdateEmbedFile, .{ | 214 | astgen_group.async(io, workerUpdateEmbedFile, .{ comp, ef_index, ef }); |
| 209 | comp, ef_index, ef, | ||
| 210 | }); | ||
| 211 | } | 215 | } |
| 212 | 216 | ||
| 213 | try astgen_group.await(io); | 217 | try astgen_group.await(io); |
| ... | @@ -219,8 +223,8 @@ pub fn update( | ... | @@ -219,8 +223,8 @@ pub fn update( |
| 219 | // they belong to. | 223 | // they belong to. |
| 220 | const any_fatal_files = try pt.computeAliveFiles(); | 224 | const any_fatal_files = try pt.computeAliveFiles(); |
| 221 | 225 | ||
| 222 | // If the cache mode is `whole`, add every alive source file to the manifest. | ||
| 223 | switch (comp.cache_use) { | 226 | switch (comp.cache_use) { |
| 227 | .none => {}, | ||
| 224 | .whole => |whole| if (whole.cache_manifest) |man| { | 228 | .whole => |whole| if (whole.cache_manifest) |man| { |
| 225 | for (zcu.alive_files.keys()) |file_index| { | 229 | for (zcu.alive_files.keys()) |file_index| { |
| 226 | const file = zcu.fileByIndex(file_index); | 230 | const file = zcu.fileByIndex(file_index); |
| ... | @@ -250,7 +254,11 @@ pub fn update( | ... | @@ -250,7 +254,11 @@ pub fn update( |
| 250 | }; | 254 | }; |
| 251 | } | 255 | } |
| 252 | }, | 256 | }, |
| 253 | .none, .incremental => {}, | 257 | .incremental => { |
| 258 | // Do not include file contents in the cache manifest because we | ||
| 259 | // want the hash to be the same regardless of the contents of the | ||
| 260 | // source files so that incremental can do its thing. | ||
| 261 | }, | ||
| 254 | } | 262 | } |
| 255 | 263 | ||
| 256 | if (comp.time_report) |*tr| { | 264 | if (comp.time_report) |*tr| { |
| ... | @@ -2494,11 +2502,7 @@ pub fn doImport( | ... | @@ -2494,11 +2502,7 @@ pub fn doImport( |
| 2494 | } | 2502 | } |
| 2495 | /// This is called once during `Compilation.create` and never again. "builtin" modules don't yet | 2503 | /// This is called once during `Compilation.create` and never again. "builtin" modules don't yet |
| 2496 | /// exist, so are not added to `module_roots` here. They must be added when they are created. | 2504 | /// exist, so are not added to `module_roots` here. They must be added when they are created. |
| 2497 | pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ | 2505 | pub fn populateModuleRootTable(pt: Zcu.PerThread) Allocator.Error!void { |
| 2498 | OutOfMemory, | ||
| 2499 | /// One of the specified modules had its root source file at an illegal path. | ||
| 2500 | IllegalZigImport, | ||
| 2501 | }!void { | ||
| 2502 | const zcu = pt.zcu; | 2506 | const zcu = pt.zcu; |
| 2503 | const comp = zcu.comp; | 2507 | const comp = zcu.comp; |
| 2504 | const gpa = comp.gpa; | 2508 | const gpa = comp.gpa; |
| ... | @@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ | ... | @@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ |
| 2507 | // We'll initially add [mod, undefined] pairs, and when we reach the pair while | 2511 | // We'll initially add [mod, undefined] pairs, and when we reach the pair while |
| 2508 | // iterating, rewrite the undefined value. | 2512 | // iterating, rewrite the undefined value. |
| 2509 | const roots = &zcu.module_roots; | 2513 | const roots = &zcu.module_roots; |
| 2510 | roots.clearRetainingCapacity(); | 2514 | assert(roots.count() == 0); |
| 2511 | 2515 | ||
| 2512 | // Start with: | 2516 | // Start with: |
| 2513 | // * `std_mod`, which is the main root of analysis | 2517 | // * `std_mod`, which is the main root of analysis |
| ... | @@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ | ... | @@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ |
| 2542 | errdefer path.deinit(gpa); | 2546 | errdefer path.deinit(gpa); |
| 2543 | 2547 | ||
| 2544 | if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) { | 2548 | if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) { |
| 2545 | return error.IllegalZigImport; | 2549 | // One of the specified modules had its root source file at an illegal path. |
| 2550 | zcu.illegal_module_root = mod; | ||
| 2551 | return; | ||
| 2546 | } | 2552 | } |
| 2547 | 2553 | ||
| 2548 | const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu }); | 2554 | const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu }); |
| ... | @@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct | ... | @@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct |
| 2781 | const gpa = comp.gpa; | 2787 | const gpa = comp.gpa; |
| 2782 | const io = comp.io; | 2788 | const io = comp.io; |
| 2783 | 2789 | ||
| 2784 | const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); | 2790 | const mod: *Module = mod: { |
| 2785 | if (gop.found_existing) return .{ // the `File` is up-to-date | 2791 | const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); |
| 2786 | .file = zcu.module_roots.get(gop.value_ptr.*).?.unwrap().?, | 2792 | if (!gop.found_existing) { |
| 2787 | .module_root = gop.value_ptr.*, | 2793 | errdefer _ = zcu.builtin_modules.pop(); |
| 2794 | gop.value_ptr.* = try .createBuiltin(comp.arena, opts, comp.dirs); | ||
| 2795 | } | ||
| 2796 | const mod = gop.value_ptr.*; | ||
| 2797 | assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin | ||
| 2798 | break :mod mod; | ||
| 2788 | }; | 2799 | }; |
| 2789 | errdefer _ = zcu.builtin_modules.pop(); | ||
| 2790 | 2800 | ||
| 2791 | const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs); | 2801 | if (zcu.module_roots.get(mod)) |file| { |
| 2792 | assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin | 2802 | // We have already loaded this builtin.zig before! |
| 2803 | return .{ .file = file.unwrap().?, .module_root = mod }; | ||
| 2804 | } | ||
| 2793 | 2805 | ||
| 2794 | const path = try mod.root.join(gpa, comp.dirs, "builtin.zig"); | 2806 | const path = try mod.root.join(gpa, comp.dirs, "builtin.zig"); |
| 2795 | errdefer path.deinit(gpa); | 2807 | errdefer path.deinit(gpa); |
| ... | @@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct | ... | @@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct |
| 2827 | .root_type = .none, | 2839 | .root_type = .none, |
| 2828 | }); | 2840 | }); |
| 2829 | 2841 | ||
| 2830 | gop.value_ptr.* = mod; | ||
| 2831 | file_gop.key_ptr.* = file_index; | 2842 | file_gop.key_ptr.* = file_index; |
| 2832 | zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional()); | 2843 | zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional()); |
| 2833 | try opts.populateFile(gpa, file); | 2844 | try opts.populateFile(gpa, file); |
| ... | @@ -2883,22 +2894,19 @@ pub fn embedFile( | ... | @@ -2883,22 +2894,19 @@ pub fn embedFile( |
| 2883 | return @fromBackingInt(@intCast(gop.index)); | 2894 | return @fromBackingInt(@intCast(gop.index)); |
| 2884 | } | 2895 | } |
| 2885 | errdefer _ = zcu.embed_table.pop(); | 2896 | errdefer _ = zcu.embed_table.pop(); |
| 2886 | gop.key_ptr.* = try pt.newEmbedFile(path); | 2897 | try pt.initEmbedFile(gop.key_ptr, path); |
| 2887 | return @fromBackingInt(@intCast(gop.index)); | 2898 | return @fromBackingInt(@intCast(gop.index)); |
| 2888 | } | 2899 | } |
| 2889 | 2900 | ||
| 2890 | const embed_file: *Zcu.EmbedFile, const embed_file_idx: Zcu.EmbedFile.Index = ef: { | 2901 | const embed_file, const embed_file_idx: Zcu.EmbedFile.Index = ef: { |
| 2891 | const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string); | 2902 | const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string); |
| 2892 | errdefer path.deinit(gpa); | 2903 | errdefer path.deinit(gpa); |
| 2893 | const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{}); | 2904 | const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{}); |
| 2894 | if (gop.found_existing) { | 2905 | if (!gop.found_existing) { |
| 2895 | path.deinit(gpa); // we're not using this key | ||
| 2896 | break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) }; | ||
| 2897 | } else { | ||
| 2898 | errdefer _ = zcu.embed_table.pop(); | 2906 | errdefer _ = zcu.embed_table.pop(); |
| 2899 | gop.key_ptr.* = try pt.newEmbedFile(path); | 2907 | try pt.initEmbedFile(gop.key_ptr, path); |
| 2900 | break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) }; | 2908 | } else path.deinit(gpa); // we're not using this key |
| 2901 | } | 2909 | break :ef .{ gop.key_ptr, @fromBackingInt(@intCast(gop.index)) }; |
| 2902 | }; | 2910 | }; |
| 2903 | 2911 | ||
| 2904 | switch (embed_file.path.isNested(cur_file.mod.?.root)) { | 2912 | switch (embed_file.path.isNested(cur_file.mod.?.root)) { |
| ... | @@ -2913,7 +2921,7 @@ pub fn updateEmbedFile( | ... | @@ -2913,7 +2921,7 @@ pub fn updateEmbedFile( |
| 2913 | pt: Zcu.PerThread, | 2921 | pt: Zcu.PerThread, |
| 2914 | ef: *Zcu.EmbedFile, | 2922 | ef: *Zcu.EmbedFile, |
| 2915 | /// If not `null`, the interned file data is stored here, if it was loaded. | 2923 | /// If not `null`, the interned file data is stored here, if it was loaded. |
| 2916 | /// `newEmbedFile` uses this to add the file to the `whole` cache manifest. | 2924 | /// `initEmbedFile` uses this to add the file to the `whole` cache manifest. |
| 2917 | ip_str_out: ?*?InternPool.String, | 2925 | ip_str_out: ?*?InternPool.String, |
| 2918 | ) Allocator.Error!void { | 2926 | ) Allocator.Error!void { |
| 2919 | pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) { | 2927 | pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) { |
| ... | @@ -3000,17 +3008,13 @@ fn updateEmbedFileInner( | ... | @@ -3000,17 +3008,13 @@ fn updateEmbedFileInner( |
| 3000 | } | 3008 | } |
| 3001 | 3009 | ||
| 3002 | /// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success. | 3010 | /// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success. |
| 3003 | fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.EmbedFile { | 3011 | fn initEmbedFile(pt: Zcu.PerThread, ef: *Zcu.EmbedFile, path: Compilation.Path) EmbedFileError!void { |
| 3004 | const zcu = pt.zcu; | 3012 | const zcu = pt.zcu; |
| 3005 | const comp = zcu.comp; | 3013 | const comp = zcu.comp; |
| 3006 | const io = comp.io; | 3014 | const io = comp.io; |
| 3007 | const gpa = comp.gpa; | ||
| 3008 | const ip = &zcu.intern_pool; | 3015 | const ip = &zcu.intern_pool; |
| 3009 | 3016 | ||
| 3010 | const new_file = try gpa.create(Zcu.EmbedFile); | 3017 | ef.* = .{ |
| 3011 | errdefer gpa.destroy(new_file); | ||
| 3012 | |||
| 3013 | new_file.* = .{ | ||
| 3014 | .path = path, | 3018 | .path = path, |
| 3015 | .val = .none, | 3019 | .val = .none, |
| 3016 | .err = null, | 3020 | .err = null, |
| ... | @@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E | ... | @@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E |
| 3018 | }; | 3022 | }; |
| 3019 | 3023 | ||
| 3020 | var opt_ip_str: ?InternPool.String = null; | 3024 | var opt_ip_str: ?InternPool.String = null; |
| 3021 | try pt.updateEmbedFile(new_file, &opt_ip_str); | 3025 | try pt.updateEmbedFile(ef, &opt_ip_str); |
| 3022 | 3026 | ||
| 3023 | try comp.appendFileSystemInput(path); | 3027 | try comp.appendFileSystemInput(path); |
| 3024 | 3028 | ||
| ... | @@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E | ... | @@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E |
| 3031 | const man = whole.cache_manifest orelse break :cache; | 3035 | const man = whole.cache_manifest orelse break :cache; |
| 3032 | const ip_str = opt_ip_str orelse break :cache; // this will be a compile error | 3036 | const ip_str = opt_ip_str orelse break :cache; // this will be a compile error |
| 3033 | 3037 | ||
| 3034 | const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu); | 3038 | const array_len = Value.fromInterned(ef.val).typeOf(zcu).childType(zcu).arrayLen(zcu); |
| 3035 | const contents = ip_str.toSlice(array_len, ip); | 3039 | const contents = ip_str.toSlice(array_len, ip); |
| 3036 | 3040 | ||
| 3037 | try whole.cache_manifest_mutex.lock(io); | 3041 | try whole.cache_manifest_mutex.lock(io); |
| 3038 | defer whole.cache_manifest_mutex.unlock(io); | 3042 | defer whole.cache_manifest_mutex.unlock(io); |
| 3039 | 3043 | ||
| 3040 | path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, new_file.stat) catch |err| switch (err) { | 3044 | path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, ef.stat) catch |err| switch (err) { |
| 3041 | error.FileSystemFailure => unreachable, // contents and stat are both provided | 3045 | error.FileSystemFailure => unreachable, // contents and stat are both provided |
| 3042 | else => |e| return e, | 3046 | else => |e| return e, |
| 3043 | }; | 3047 | }; |
| 3044 | } | 3048 | } |
| 3045 | |||
| 3046 | return new_file; | ||
| 3047 | } | 3049 | } |
| 3048 | 3050 | ||
| 3049 | pub fn scanNamespace( | 3051 | pub fn scanNamespace( |
| ... | @@ -3242,9 +3244,9 @@ const ScanDeclIter = struct { | ... | @@ -3242,9 +3244,9 @@ const ScanDeclIter = struct { |
| 3242 | // Perhaps we should add all test indiscriminately and filter at the end of the update. | 3244 | // Perhaps we should add all test indiscriminately and filter at the end of the update. |
| 3243 | if (!comp.config.is_test) break :a false; | 3245 | if (!comp.config.is_test) break :a false; |
| 3244 | if (file.mod != zcu.main_mod) break :a false; | 3246 | if (file.mod != zcu.main_mod) break :a false; |
| 3245 | if (is_named and comp.test_filters.len > 0) { | 3247 | if (is_named and zcu.test_filters.len > 0) { |
| 3246 | const fqn_slice = fqn.toSlice(ip); | 3248 | const fqn_slice = fqn.toSlice(ip); |
| 3247 | for (comp.test_filters) |test_filter| { | 3249 | for (zcu.test_filters) |test_filter| { |
| 3248 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; | 3250 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; |
| 3249 | } else break :a false; | 3251 | } else break :a false; |
| 3250 | } | 3252 | } |
src/main.zig+1-4| ... | @@ -4413,13 +4413,12 @@ fn serve( | ... | @@ -4413,13 +4413,12 @@ fn serve( |
| 4413 | switch (hdr.tag) { | 4413 | switch (hdr.tag) { |
| 4414 | .exit => return cleanExit(io), | 4414 | .exit => return cleanExit(io), |
| 4415 | .update => { | 4415 | .update => { |
| 4416 | file_system_inputs.clearRetainingCapacity(); | ||
| 4417 | |||
| 4418 | if (arg_mode == .translate_c) { | 4416 | if (arg_mode == .translate_c) { |
| 4419 | var arena_instance = std.heap.ArenaAllocator.init(gpa); | 4417 | var arena_instance = std.heap.ArenaAllocator.init(gpa); |
| 4420 | defer arena_instance.deinit(); | 4418 | defer arena_instance.deinit(); |
| 4421 | const arena = arena_instance.allocator(); | 4419 | const arena = arena_instance.allocator(); |
| 4422 | var output: Compilation.TranslateCResult = undefined; | 4420 | var output: Compilation.TranslateCResult = undefined; |
| 4421 | file_system_inputs.clearRetainingCapacity(); | ||
| 4423 | try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); | 4422 | try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); |
| 4424 | defer output.deinit(gpa); | 4423 | defer output.deinit(gpa); |
| 4425 | 4424 | ||
| ... | @@ -4437,7 +4436,6 @@ fn serve( | ... | @@ -4437,7 +4436,6 @@ fn serve( |
| 4437 | 4436 | ||
| 4438 | continue; | 4437 | continue; |
| 4439 | } | 4438 | } |
| 4440 | |||
| 4441 | try comp.makeBinFileWritable(); | 4439 | try comp.makeBinFileWritable(); |
| 4442 | try comp.update(main_progress_node); | 4440 | try comp.update(main_progress_node); |
| 4443 | try comp.makeBinFileExecutable(); | 4441 | try comp.makeBinFileExecutable(); |
| ... | @@ -4463,7 +4461,6 @@ fn serve( | ... | @@ -4463,7 +4461,6 @@ fn serve( |
| 4463 | //); | 4461 | //); |
| 4464 | }, | 4462 | }, |
| 4465 | .hot_update => { | 4463 | .hot_update => { |
| 4466 | file_system_inputs.clearRetainingCapacity(); | ||
| 4467 | if (child_pid) |pid| { | 4464 | if (child_pid) |pid| { |
| 4468 | try comp.hotCodeSwap(main_progress_node, pid); | 4465 | try comp.hotCodeSwap(main_progress_node, pid); |
| 4469 | try serveUpdateResults(&server, comp); | 4466 | try serveUpdateResults(&server, comp); |
test/src/Cases.zig-1| ... | @@ -75,7 +75,6 @@ pub const Case = struct { | ... | @@ -75,7 +75,6 @@ pub const Case = struct { |
| 75 | 75 | ||
| 76 | emit_asm: bool = false, | 76 | emit_asm: bool = false, |
| 77 | emit_bin: bool = true, | 77 | emit_bin: bool = true, |
| 78 | emit_h: bool = false, | ||
| 79 | is_test: bool = false, | 78 | is_test: bool = false, |
| 80 | expect_exact: bool = false, | 79 | expect_exact: bool = false, |
| 81 | backend: Backend = .auto, | 80 | backend: Backend = .auto, |