authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 14:33:46-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 14:42:50-04:00
logafa66fa392f5a32d16da7f4705c59dad369f6d48
tree4872284bc454b34c14f25559ea46ea9bd6bf2deb
parentf290b54f891a67af456529da0f4f824a1e27b4ef

InternPool: make `tracked_insts` thread-safe


5 files changed, 382 insertions(+), 216 deletions(-)

src/Compilation.zig+22-53
...@@ -2675,7 +2675,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {...@@ -2675,7 +2675,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2675 .import => |import| try Zcu.ErrorMsg.init(2675 .import => |import| try Zcu.ErrorMsg.init(
2676 gpa,2676 gpa,
2677 .{2677 .{
2678 .base_node_inst = try ip.trackZir(gpa, import.file, .main_struct_inst),2678 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2679 .file = import.file,
2680 .inst = .main_struct_inst,
2681 }),
2679 .offset = .{ .token_abs = import.token },2682 .offset = .{ .token_abs = import.token },
2680 },2683 },
2681 "imported from module {s}",2684 "imported from module {s}",
...@@ -2684,7 +2687,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {...@@ -2684,7 +2687,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2684 .root => |pkg| try Zcu.ErrorMsg.init(2687 .root => |pkg| try Zcu.ErrorMsg.init(
2685 gpa,2688 gpa,
2686 .{2689 .{
2687 .base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),2690 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2691 .file = file_index,
2692 .inst = .main_struct_inst,
2693 }),
2688 .offset = .entire_file,2694 .offset = .entire_file,
2689 },2695 },
2690 "root of module {s}",2696 "root of module {s}",
...@@ -2698,7 +2704,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {...@@ -2698,7 +2704,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2698 notes[num_notes] = try Zcu.ErrorMsg.init(2704 notes[num_notes] = try Zcu.ErrorMsg.init(
2699 gpa,2705 gpa,
2700 .{2706 .{
2701 .base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),2707 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2708 .file = file_index,
2709 .inst = .main_struct_inst,
2710 }),
2702 .offset = .entire_file,2711 .offset = .entire_file,
2703 },2712 },
2704 "{} more references omitted",2713 "{} more references omitted",
...@@ -2710,7 +2719,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {...@@ -2710,7 +2719,10 @@ fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2710 const err = try Zcu.ErrorMsg.create(2719 const err = try Zcu.ErrorMsg.create(
2711 gpa,2720 gpa,
2712 .{2721 .{
2713 .base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),2722 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2723 .file = file_index,
2724 .inst = .main_struct_inst,
2725 }),
2714 .offset = .entire_file,2726 .offset = .entire_file,
2715 },2727 },
2716 "file exists in multiple modules",2728 "file exists in multiple modules",
...@@ -2776,7 +2788,7 @@ const Header = extern struct {...@@ -2776,7 +2788,7 @@ const Header = extern struct {
2776 //extra_len: u32,2788 //extra_len: u32,
2777 //limbs_len: u32,2789 //limbs_len: u32,
2778 //string_bytes_len: u32,2790 //string_bytes_len: u32,
2779 tracked_insts_len: u32,2791 //tracked_insts_len: u32,
2780 src_hash_deps_len: u32,2792 src_hash_deps_len: u32,
2781 decl_val_deps_len: u32,2793 decl_val_deps_len: u32,
2782 namespace_deps_len: u32,2794 namespace_deps_len: u32,
...@@ -2805,7 +2817,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2805,7 +2817,7 @@ pub fn saveState(comp: *Compilation) !void {
2805 //.extra_len = @intCast(ip.extra.items.len),2817 //.extra_len = @intCast(ip.extra.items.len),
2806 //.limbs_len = @intCast(ip.limbs.items.len),2818 //.limbs_len = @intCast(ip.limbs.items.len),
2807 //.string_bytes_len = @intCast(ip.string_bytes.items.len),2819 //.string_bytes_len = @intCast(ip.string_bytes.items.len),
2808 .tracked_insts_len = @intCast(ip.tracked_insts.count()),2820 //.tracked_insts_len = @intCast(ip.tracked_insts.count()),
2809 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),2821 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2810 .decl_val_deps_len = @intCast(ip.decl_val_deps.count()),2822 .decl_val_deps_len = @intCast(ip.decl_val_deps.count()),
2811 .namespace_deps_len = @intCast(ip.namespace_deps.count()),2823 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
...@@ -2822,7 +2834,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2822,7 +2834,7 @@ pub fn saveState(comp: *Compilation) !void {
2822 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));2834 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));
2823 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));2835 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));
2824 //addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);2836 //addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
2825 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));2837 //addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));
28262838
2827 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.keys()));2839 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.keys()));
2828 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.values()));2840 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.values()));
...@@ -4134,14 +4146,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -4134,14 +4146,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
4134 };4146 };
4135}4147}
41364148
4137const AstGenSrc = union(enum) {
4138 root,
4139 import: struct {
4140 importing_file: Zcu.File.Index,
4141 import_tok: std.zig.Ast.TokenIndex,
4142 },
4143};
4144
4145fn workerAstGenFile(4149fn workerAstGenFile(
4146 tid: usize,4150 tid: usize,
4147 comp: *Compilation,4151 comp: *Compilation,
...@@ -4151,7 +4155,7 @@ fn workerAstGenFile(...@@ -4151,7 +4155,7 @@ fn workerAstGenFile(
4151 root_decl: Zcu.Decl.OptionalIndex,4155 root_decl: Zcu.Decl.OptionalIndex,
4152 prog_node: std.Progress.Node,4156 prog_node: std.Progress.Node,
4153 wg: *WaitGroup,4157 wg: *WaitGroup,
4154 src: AstGenSrc,4158 src: Zcu.AstGenSrc,
4155) void {4159) void {
4156 const child_prog_node = prog_node.start(file.sub_file_path, 0);4160 const child_prog_node = prog_node.start(file.sub_file_path, 0);
4157 defer child_prog_node.end();4161 defer child_prog_node.end();
...@@ -4161,7 +4165,7 @@ fn workerAstGenFile(...@@ -4161,7 +4165,7 @@ fn workerAstGenFile(
4161 error.AnalysisFail => return,4165 error.AnalysisFail => return,
4162 else => {4166 else => {
4163 file.status = .retryable_failure;4167 file.status = .retryable_failure;
4164 comp.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {4168 pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {
4165 // Swallowing this error is OK because it's implied to be OOM when4169 // Swallowing this error is OK because it's implied to be OOM when
4166 // there is a missing `failed_files` error message.4170 // there is a missing `failed_files` error message.
4167 error.OutOfMemory => {},4171 error.OutOfMemory => {},
...@@ -4207,7 +4211,7 @@ fn workerAstGenFile(...@@ -4207,7 +4211,7 @@ fn workerAstGenFile(
4207 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{4211 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
4208 file.sub_file_path, import_path, import_result.file.sub_file_path,4212 file.sub_file_path, import_path, import_result.file.sub_file_path,
4209 });4213 });
4210 const sub_src: AstGenSrc = .{ .import = .{4214 const sub_src: Zcu.AstGenSrc = .{ .import = .{
4211 .importing_file = file_index,4215 .importing_file = file_index,
4212 .import_tok = item.data.token,4216 .import_tok = item.data.token,
4213 } };4217 } };
...@@ -4560,41 +4564,6 @@ fn reportRetryableWin32ResourceError(...@@ -4560,41 +4564,6 @@ fn reportRetryableWin32ResourceError(
4560 }4564 }
4561}4565}
45624566
4563fn reportRetryableAstGenError(
4564 comp: *Compilation,
4565 src: AstGenSrc,
4566 file_index: Zcu.File.Index,
4567 err: anyerror,
4568) error{OutOfMemory}!void {
4569 const zcu = comp.module.?;
4570 const gpa = zcu.gpa;
4571
4572 const file = zcu.fileByIndex(file_index);
4573 file.status = .retryable_failure;
4574
4575 const src_loc: Zcu.LazySrcLoc = switch (src) {
4576 .root => .{
4577 .base_node_inst = try zcu.intern_pool.trackZir(gpa, file_index, .main_struct_inst),
4578 .offset = .entire_file,
4579 },
4580 .import => |info| .{
4581 .base_node_inst = try zcu.intern_pool.trackZir(gpa, info.importing_file, .main_struct_inst),
4582 .offset = .{ .token_abs = info.import_tok },
4583 },
4584 };
4585
4586 const err_msg = try Zcu.ErrorMsg.create(gpa, src_loc, "unable to load '{}{s}': {s}", .{
4587 file.mod.root, file.sub_file_path, @errorName(err),
4588 });
4589 errdefer err_msg.destroy(gpa);
4590
4591 {
4592 comp.mutex.lock();
4593 defer comp.mutex.unlock();
4594 try zcu.failed_files.putNoClobber(gpa, file, err_msg);
4595 }
4596}
4597
4598fn reportRetryableEmbedFileError(4567fn reportRetryableEmbedFileError(
4599 comp: *Compilation,4568 comp: *Compilation,
4600 embed_file: *Zcu.EmbedFile,4569 embed_file: *Zcu.EmbedFile,
src/InternPool.zig+156-26
...@@ -20,10 +20,6 @@ tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_th...@@ -20,10 +20,6 @@ tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32) = if (single_th
20/// These are not serialized; it is computed upon deserialization.20/// These are not serialized; it is computed upon deserialization.
21maps: std.ArrayListUnmanaged(FieldMap) = .{},21maps: std.ArrayListUnmanaged(FieldMap) = .{},
2222
23/// An index into `tracked_insts` gives a reference to a single ZIR instruction which
24/// persists across incremental updates.
25tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},
26
27/// Dependencies on the source code hash associated with a ZIR instruction.23/// Dependencies on the source code hash associated with a ZIR instruction.
28/// * For a `declaration`, this is the entire declaration body.24/// * For a `declaration`, this is the entire declaration body.
29/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).25/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).
...@@ -76,12 +72,15 @@ pub const TrackedInst = extern struct {...@@ -76,12 +72,15 @@ pub const TrackedInst = extern struct {
76 }72 }
77 pub const Index = enum(u32) {73 pub const Index = enum(u32) {
78 _,74 _,
79 pub fn resolveFull(i: TrackedInst.Index, ip: *const InternPool) TrackedInst {75 pub fn resolveFull(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) TrackedInst {
80 return ip.tracked_insts.keys()[@intFromEnum(i)];76 const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip);
77 const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire();
78 return tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index];
81 }79 }
82 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {80 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
83 return i.resolveFull(ip).inst;81 return i.resolveFull(ip).inst;
84 }82 }
83
85 pub fn toOptional(i: TrackedInst.Index) Optional {84 pub fn toOptional(i: TrackedInst.Index) Optional {
86 return @enumFromInt(@intFromEnum(i));85 return @enumFromInt(@intFromEnum(i));
87 }86 }
...@@ -95,21 +94,124 @@ pub const TrackedInst = extern struct {...@@ -95,21 +94,124 @@ pub const TrackedInst = extern struct {
95 };94 };
96 }95 }
97 };96 };
97
98 pub const Unwrapped = struct {
99 tid: Zcu.PerThread.Id,
100 index: u32,
101
102 pub fn wrap(unwrapped: Unwrapped, ip: *const InternPool) TrackedInst.Index {
103 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
104 assert(unwrapped.index <= ip.getIndexMask(u32));
105 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
106 unwrapped.index);
107 }
108 };
109 pub fn unwrap(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) Unwrapped {
110 return .{
111 .tid = @enumFromInt(@intFromEnum(tracked_inst_index) >> ip.tid_shift_32 & ip.getTidMask()),
112 .index = @intFromEnum(tracked_inst_index) & ip.getIndexMask(u32),
113 };
114 }
98 };115 };
99};116};
100117
101pub fn trackZir(118pub fn trackZir(
102 ip: *InternPool,119 ip: *InternPool,
103 gpa: Allocator,120 gpa: Allocator,
104 file: FileIndex,121 tid: Zcu.PerThread.Id,
105 inst: Zir.Inst.Index,122 key: TrackedInst,
106) Allocator.Error!TrackedInst.Index {123) Allocator.Error!TrackedInst.Index {
107 const key: TrackedInst = .{124 const full_hash = Hash.hash(0, std.mem.asBytes(&key));
108 .file = file,125 const hash: u32 = @truncate(full_hash >> 32);
109 .inst = inst,126 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
110 };127 var map = shard.shared.tracked_inst_map.acquire();
111 const gop = try ip.tracked_insts.getOrPut(gpa, key);128 const Map = @TypeOf(map);
112 return @enumFromInt(gop.index);129 var map_mask = map.header().mask();
130 var map_index = hash;
131 while (true) : (map_index += 1) {
132 map_index &= map_mask;
133 const entry = &map.entries[map_index];
134 const index = entry.acquire().unwrap() orelse break;
135 if (entry.hash != hash) continue;
136 if (std.meta.eql(index.resolveFull(ip), key)) return index;
137 }
138 shard.mutate.tracked_inst_map.mutex.lock();
139 defer shard.mutate.tracked_inst_map.mutex.unlock();
140 if (map.entries != shard.shared.tracked_inst_map.entries) {
141 shard.mutate.tracked_inst_map.len += 1;
142 map = shard.shared.tracked_inst_map;
143 map_mask = map.header().mask();
144 map_index = hash;
145 }
146 while (true) : (map_index += 1) {
147 map_index &= map_mask;
148 const entry = &map.entries[map_index];
149 const index = entry.acquire().unwrap() orelse break;
150 if (entry.hash != hash) continue;
151 if (std.meta.eql(index.resolveFull(ip), key)) return index;
152 }
153 defer shard.mutate.tracked_inst_map.len += 1;
154 const local = ip.getLocal(tid);
155 local.mutate.tracked_insts.mutex.lock();
156 defer local.mutate.tracked_insts.mutex.unlock();
157 const list = local.getMutableTrackedInsts(gpa);
158 try list.ensureUnusedCapacity(1);
159 const map_header = map.header().*;
160 if (shard.mutate.tracked_inst_map.len < map_header.capacity * 3 / 5) {
161 const entry = &map.entries[map_index];
162 entry.hash = hash;
163 const index = (TrackedInst.Index.Unwrapped{
164 .tid = tid,
165 .index = list.mutate.len,
166 }).wrap(ip);
167 list.appendAssumeCapacity(.{key});
168 entry.release(index.toOptional());
169 return index;
170 }
171 const arena_state = &local.mutate.arena;
172 var arena = arena_state.promote(gpa);
173 defer arena_state.* = arena.state;
174 const new_map_capacity = map_header.capacity * 2;
175 const new_map_buf = try arena.allocator().alignedAlloc(
176 u8,
177 Map.alignment,
178 Map.entries_offset + new_map_capacity * @sizeOf(Map.Entry),
179 );
180 const new_map: Map = .{ .entries = @ptrCast(new_map_buf[Map.entries_offset..].ptr) };
181 new_map.header().* = .{ .capacity = new_map_capacity };
182 @memset(new_map.entries[0..new_map_capacity], .{ .value = .none, .hash = undefined });
183 const new_map_mask = new_map.header().mask();
184 map_index = 0;
185 while (map_index < map_header.capacity) : (map_index += 1) {
186 const entry = &map.entries[map_index];
187 const index = entry.value.unwrap() orelse continue;
188 const item_hash = entry.hash;
189 var new_map_index = item_hash;
190 while (true) : (new_map_index += 1) {
191 new_map_index &= new_map_mask;
192 const new_entry = &new_map.entries[new_map_index];
193 if (new_entry.value != .none) continue;
194 new_entry.* = .{
195 .value = index.toOptional(),
196 .hash = item_hash,
197 };
198 break;
199 }
200 }
201 map = new_map;
202 map_index = hash;
203 while (true) : (map_index += 1) {
204 map_index &= new_map_mask;
205 if (map.entries[map_index].value == .none) break;
206 }
207 const index = (TrackedInst.Index.Unwrapped{
208 .tid = tid,
209 .index = list.mutate.len,
210 }).wrap(ip);
211 list.appendAssumeCapacity(.{key});
212 map.entries[map_index] = .{ .value = index.toOptional(), .hash = hash };
213 shard.shared.tracked_inst_map.release(new_map);
214 return index;
113}215}
114216
115/// Analysis Unit. Represents a single entity which undergoes semantic analysis.217/// Analysis Unit. Represents a single entity which undergoes semantic analysis.
...@@ -324,6 +426,7 @@ const Local = struct {...@@ -324,6 +426,7 @@ const Local = struct {
324 extra: ListMutate,426 extra: ListMutate,
325 limbs: ListMutate,427 limbs: ListMutate,
326 strings: ListMutate,428 strings: ListMutate,
429 tracked_insts: MutexListMutate,
327 files: ListMutate,430 files: ListMutate,
328431
329 decls: BucketListMutate,432 decls: BucketListMutate,
...@@ -335,6 +438,7 @@ const Local = struct {...@@ -335,6 +438,7 @@ const Local = struct {
335 extra: Extra,438 extra: Extra,
336 limbs: Limbs,439 limbs: Limbs,
337 strings: Strings,440 strings: Strings,
441 tracked_insts: TrackedInsts,
338 files: List(File),442 files: List(File),
339443
340 decls: Decls,444 decls: Decls,
...@@ -356,6 +460,7 @@ const Local = struct {...@@ -356,6 +460,7 @@ const Local = struct {
356 else => @compileError("unsupported host"),460 else => @compileError("unsupported host"),
357 };461 };
358 const Strings = List(struct { u8 });462 const Strings = List(struct { u8 });
463 const TrackedInsts = List(struct { TrackedInst });
359464
360 const decls_bucket_width = 8;465 const decls_bucket_width = 8;
361 const decls_bucket_mask = (1 << decls_bucket_width) - 1;466 const decls_bucket_mask = (1 << decls_bucket_width) - 1;
...@@ -375,6 +480,16 @@ const Local = struct {...@@ -375,6 +480,16 @@ const Local = struct {
375 };480 };
376 };481 };
377482
483 const MutexListMutate = struct {
484 mutex: std.Thread.Mutex,
485 list: ListMutate,
486
487 const empty: MutexListMutate = .{
488 .mutex = .{},
489 .list = ListMutate.empty,
490 };
491 };
492
378 const BucketListMutate = struct {493 const BucketListMutate = struct {
379 last_bucket_len: u32,494 last_bucket_len: u32,
380 buckets_list: ListMutate,495 buckets_list: ListMutate,
...@@ -396,7 +511,7 @@ const Local = struct {...@@ -396,7 +511,7 @@ const Local = struct {
396511
397 const ListSelf = @This();512 const ListSelf = @This();
398 const Mutable = struct {513 const Mutable = struct {
399 gpa: std.mem.Allocator,514 gpa: Allocator,
400 arena: *std.heap.ArenaAllocator.State,515 arena: *std.heap.ArenaAllocator.State,
401 mutate: *ListMutate,516 mutate: *ListMutate,
402 list: *ListSelf,517 list: *ListSelf,
...@@ -564,7 +679,7 @@ const Local = struct {...@@ -564,7 +679,7 @@ const Local = struct {
564 mutable.list.release(new_list);679 mutable.list.release(new_list);
565 }680 }
566681
567 fn view(mutable: Mutable) View {682 pub fn view(mutable: Mutable) View {
568 const capacity = mutable.list.header().capacity;683 const capacity = mutable.list.header().capacity;
569 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`684 assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
570 return .{685 return .{
...@@ -614,7 +729,7 @@ const Local = struct {...@@ -614,7 +729,7 @@ const Local = struct {
614 };729 };
615 }730 }
616731
617 pub fn getMutableItems(local: *Local, gpa: std.mem.Allocator) List(Item).Mutable {732 pub fn getMutableItems(local: *Local, gpa: Allocator) List(Item).Mutable {
618 return .{733 return .{
619 .gpa = gpa,734 .gpa = gpa,
620 .arena = &local.mutate.arena,735 .arena = &local.mutate.arena,
...@@ -623,7 +738,7 @@ const Local = struct {...@@ -623,7 +738,7 @@ const Local = struct {
623 };738 };
624 }739 }
625740
626 pub fn getMutableExtra(local: *Local, gpa: std.mem.Allocator) Extra.Mutable {741 pub fn getMutableExtra(local: *Local, gpa: Allocator) Extra.Mutable {
627 return .{742 return .{
628 .gpa = gpa,743 .gpa = gpa,
629 .arena = &local.mutate.arena,744 .arena = &local.mutate.arena,
...@@ -636,7 +751,7 @@ const Local = struct {...@@ -636,7 +751,7 @@ const Local = struct {
636 /// On 64-bit systems, this array is used for big integers and associated metadata.751 /// On 64-bit systems, this array is used for big integers and associated metadata.
637 /// Use the helper methods instead of accessing this directly in order to not752 /// Use the helper methods instead of accessing this directly in order to not
638 /// violate the above mechanism.753 /// violate the above mechanism.
639 pub fn getMutableLimbs(local: *Local, gpa: std.mem.Allocator) Limbs.Mutable {754 pub fn getMutableLimbs(local: *Local, gpa: Allocator) Limbs.Mutable {
640 return switch (@sizeOf(Limb)) {755 return switch (@sizeOf(Limb)) {
641 @sizeOf(u32) => local.getMutableExtra(gpa),756 @sizeOf(u32) => local.getMutableExtra(gpa),
642 @sizeOf(u64) => .{757 @sizeOf(u64) => .{
...@@ -654,7 +769,7 @@ const Local = struct {...@@ -654,7 +769,7 @@ const Local = struct {
654 /// is referencing the data here whether they want to store both index and length,769 /// is referencing the data here whether they want to store both index and length,
655 /// thus allowing null bytes, or store only index, and use null-termination. The770 /// thus allowing null bytes, or store only index, and use null-termination. The
656 /// `strings` array is agnostic to either usage.771 /// `strings` array is agnostic to either usage.
657 pub fn getMutableStrings(local: *Local, gpa: std.mem.Allocator) Strings.Mutable {772 pub fn getMutableStrings(local: *Local, gpa: Allocator) Strings.Mutable {
658 return .{773 return .{
659 .gpa = gpa,774 .gpa = gpa,
660 .arena = &local.mutate.arena,775 .arena = &local.mutate.arena,
...@@ -663,6 +778,17 @@ const Local = struct {...@@ -663,6 +778,17 @@ const Local = struct {
663 };778 };
664 }779 }
665780
781 /// An index into `tracked_insts` gives a reference to a single ZIR instruction which
782 /// persists across incremental updates.
783 pub fn getMutableTrackedInsts(local: *Local, gpa: Allocator) TrackedInsts.Mutable {
784 return .{
785 .gpa = gpa,
786 .arena = &local.mutate.arena,
787 .mutate = &local.mutate.tracked_insts.list,
788 .list = &local.shared.tracked_insts,
789 };
790 }
791
666 /// Elements are ordered identically to the `import_table` field of `Zcu`.792 /// Elements are ordered identically to the `import_table` field of `Zcu`.
667 ///793 ///
668 /// Unlike `import_table`, this data is serialized as part of incremental794 /// Unlike `import_table`, this data is serialized as part of incremental
...@@ -672,7 +798,7 @@ const Local = struct {...@@ -672,7 +798,7 @@ const Local = struct {
672 /// `InternPool.TrackedInst`.798 /// `InternPool.TrackedInst`.
673 ///799 ///
674 /// Value is the `Decl` of the struct that represents this `File`.800 /// Value is the `Decl` of the struct that represents this `File`.
675 pub fn getMutableFiles(local: *Local, gpa: std.mem.Allocator) List(File).Mutable {801 pub fn getMutableFiles(local: *Local, gpa: Allocator) List(File).Mutable {
676 return .{802 return .{
677 .gpa = gpa,803 .gpa = gpa,
678 .arena = &local.mutate.arena,804 .arena = &local.mutate.arena,
...@@ -691,7 +817,7 @@ const Local = struct {...@@ -691,7 +817,7 @@ const Local = struct {
691 /// serialization trivial.817 /// serialization trivial.
692 /// * It provides a unique integer to be used for anonymous symbol names, avoiding818 /// * It provides a unique integer to be used for anonymous symbol names, avoiding
693 /// multi-threaded contention on an atomic counter.819 /// multi-threaded contention on an atomic counter.
694 pub fn getMutableDecls(local: *Local, gpa: std.mem.Allocator) Decls.Mutable {820 pub fn getMutableDecls(local: *Local, gpa: Allocator) Decls.Mutable {
695 return .{821 return .{
696 .gpa = gpa,822 .gpa = gpa,
697 .arena = &local.mutate.arena,823 .arena = &local.mutate.arena,
...@@ -701,7 +827,7 @@ const Local = struct {...@@ -701,7 +827,7 @@ const Local = struct {
701 }827 }
702828
703 /// Same pattern as with `getMutableDecls`.829 /// Same pattern as with `getMutableDecls`.
704 pub fn getMutableNamespaces(local: *Local, gpa: std.mem.Allocator) Namespaces.Mutable {830 pub fn getMutableNamespaces(local: *Local, gpa: Allocator) Namespaces.Mutable {
705 return .{831 return .{
706 .gpa = gpa,832 .gpa = gpa,
707 .arena = &local.mutate.arena,833 .arena = &local.mutate.arena,
...@@ -723,11 +849,13 @@ const Shard = struct {...@@ -723,11 +849,13 @@ const Shard = struct {
723 shared: struct {849 shared: struct {
724 map: Map(Index),850 map: Map(Index),
725 string_map: Map(OptionalNullTerminatedString),851 string_map: Map(OptionalNullTerminatedString),
852 tracked_inst_map: Map(TrackedInst.Index.Optional),
726 } align(std.atomic.cache_line),853 } align(std.atomic.cache_line),
727 mutate: struct {854 mutate: struct {
728 // TODO: measure cost of sharing unrelated mutate state855 // TODO: measure cost of sharing unrelated mutate state
729 map: Mutate align(std.atomic.cache_line),856 map: Mutate align(std.atomic.cache_line),
730 string_map: Mutate align(std.atomic.cache_line),857 string_map: Mutate align(std.atomic.cache_line),
858 tracked_inst_map: Mutate align(std.atomic.cache_line),
731 },859 },
732860
733 const Mutate = struct {861 const Mutate = struct {
...@@ -5240,6 +5368,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5240,6 +5368,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5240 .extra = Local.Extra.empty,5368 .extra = Local.Extra.empty,
5241 .limbs = Local.Limbs.empty,5369 .limbs = Local.Limbs.empty,
5242 .strings = Local.Strings.empty,5370 .strings = Local.Strings.empty,
5371 .tracked_insts = Local.TrackedInsts.empty,
5243 .files = Local.List(File).empty,5372 .files = Local.List(File).empty,
52445373
5245 .decls = Local.Decls.empty,5374 .decls = Local.Decls.empty,
...@@ -5252,6 +5381,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5252,6 +5381,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5252 .extra = Local.ListMutate.empty,5381 .extra = Local.ListMutate.empty,
5253 .limbs = Local.ListMutate.empty,5382 .limbs = Local.ListMutate.empty,
5254 .strings = Local.ListMutate.empty,5383 .strings = Local.ListMutate.empty,
5384 .tracked_insts = Local.MutexListMutate.empty,
5255 .files = Local.ListMutate.empty,5385 .files = Local.ListMutate.empty,
52565386
5257 .decls = Local.BucketListMutate.empty,5387 .decls = Local.BucketListMutate.empty,
...@@ -5267,10 +5397,12 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -5267,10 +5397,12 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
5267 .shared = .{5397 .shared = .{
5268 .map = Shard.Map(Index).empty,5398 .map = Shard.Map(Index).empty,
5269 .string_map = Shard.Map(OptionalNullTerminatedString).empty,5399 .string_map = Shard.Map(OptionalNullTerminatedString).empty,
5400 .tracked_inst_map = Shard.Map(TrackedInst.Index.Optional).empty,
5270 },5401 },
5271 .mutate = .{5402 .mutate = .{
5272 .map = Shard.Mutate.empty,5403 .map = Shard.Mutate.empty,
5273 .string_map = Shard.Mutate.empty,5404 .string_map = Shard.Mutate.empty,
5405 .tracked_inst_map = Shard.Mutate.empty,
5274 },5406 },
5275 });5407 });
52765408
...@@ -5311,8 +5443,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -5311,8 +5443,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
5311 for (ip.maps.items) |*map| map.deinit(gpa);5443 for (ip.maps.items) |*map| map.deinit(gpa);
5312 ip.maps.deinit(gpa);5444 ip.maps.deinit(gpa);
53135445
5314 ip.tracked_insts.deinit(gpa);
5315
5316 ip.src_hash_deps.deinit(gpa);5446 ip.src_hash_deps.deinit(gpa);
5317 ip.decl_val_deps.deinit(gpa);5447 ip.decl_val_deps.deinit(gpa);
5318 ip.func_ies_deps.deinit(gpa);5448 ip.func_ies_deps.deinit(gpa);
...@@ -9887,7 +10017,7 @@ pub fn getOrPutTrailingString(...@@ -9887,7 +10017,7 @@ pub fn getOrPutTrailingString(
9887 }10017 }
9888 const key: []const u8 = strings.view().items(.@"0")[start..];10018 const key: []const u8 = strings.view().items(.@"0")[start..];
9889 const value: embedded_nulls.StringType() =10019 const value: embedded_nulls.StringType() =
9890 @enumFromInt(@as(u32, @intFromEnum(tid)) << ip.tid_shift_32 | start);10020 @enumFromInt(@intFromEnum((String.Unwrapped{ .tid = tid, .index = start }).wrap(ip)));
9891 const has_embedded_null = std.mem.indexOfScalar(u8, key, 0) != null;10021 const has_embedded_null = std.mem.indexOfScalar(u8, key, 0) != null;
9892 switch (embedded_nulls) {10022 switch (embedded_nulls) {
9893 .no_embedded_nulls => assert(!has_embedded_null),10023 .no_embedded_nulls => assert(!has_embedded_null),
src/Sema.zig+5-6
...@@ -835,12 +835,11 @@ pub const Block = struct {...@@ -835,12 +835,11 @@ pub const Block = struct {
835 }835 }
836836
837 fn trackZir(block: *Block, inst: Zir.Inst.Index) Allocator.Error!InternPool.TrackedInst.Index {837 fn trackZir(block: *Block, inst: Zir.Inst.Index) Allocator.Error!InternPool.TrackedInst.Index {
838 const sema = block.sema;838 const pt = block.sema.pt;
839 const gpa = sema.gpa;839 return pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
840 const zcu = sema.pt.zcu;840 .file = block.getFileScopeIndex(pt.zcu),
841 const ip = &zcu.intern_pool;841 .inst = inst,
842 const file_index = block.getFileScopeIndex(zcu);842 });
843 return ip.trackZir(gpa, file_index, inst);
844 }843 }
845};844};
846845
src/Zcu.zig+8-35
...@@ -1018,6 +1018,14 @@ pub const ErrorMsg = struct {...@@ -1018,6 +1018,14 @@ pub const ErrorMsg = struct {
1018 }1018 }
1019};1019};
10201020
1021pub const AstGenSrc = union(enum) {
1022 root,
1023 import: struct {
1024 importing_file: Zcu.File.Index,
1025 import_tok: std.zig.Ast.TokenIndex,
1026 },
1027};
1028
1021/// Canonical reference to a position within a source file.1029/// Canonical reference to a position within a source file.
1022pub const SrcLoc = struct {1030pub const SrcLoc = struct {
1023 file_scope: *File,1031 file_scope: *File,
...@@ -3186,41 +3194,6 @@ pub fn handleUpdateExports(...@@ -3186,41 +3194,6 @@ pub fn handleUpdateExports(
3186 };3194 };
3187}3195}
31883196
3189pub fn reportRetryableFileError(
3190 zcu: *Zcu,
3191 file_index: File.Index,
3192 comptime format: []const u8,
3193 args: anytype,
3194) error{OutOfMemory}!void {
3195 const gpa = zcu.gpa;
3196 const ip = &zcu.intern_pool;
3197
3198 const file = zcu.fileByIndex(file_index);
3199 file.status = .retryable_failure;
3200
3201 const err_msg = try ErrorMsg.create(
3202 gpa,
3203 .{
3204 .base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),
3205 .offset = .entire_file,
3206 },
3207 format,
3208 args,
3209 );
3210 errdefer err_msg.destroy(gpa);
3211
3212 zcu.comp.mutex.lock();
3213 defer zcu.comp.mutex.unlock();
3214
3215 const gop = try zcu.failed_files.getOrPut(gpa, file);
3216 if (gop.found_existing) {
3217 if (gop.value_ptr.*) |old_err_msg| {
3218 old_err_msg.destroy(gpa);
3219 }
3220 }
3221 gop.value_ptr.* = err_msg;
3222}
3223
3224pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {3197pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {
3225 const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);3198 const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
3226 if (gop.found_existing) {3199 if (gop.found_existing) {
src/Zcu/PerThread.zig+191-96
...@@ -342,6 +342,7 @@ pub fn astGenFile(...@@ -342,6 +342,7 @@ pub fn astGenFile(
342/// the Compilation mutex when acting on shared state.342/// the Compilation mutex when acting on shared state.
343fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index, old_zir: Zir) !void {343fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index, old_zir: Zir) !void {
344 const zcu = pt.zcu;344 const zcu = pt.zcu;
345 const ip = &zcu.intern_pool;
345 const gpa = zcu.gpa;346 const gpa = zcu.gpa;
346 const new_zir = file.zir;347 const new_zir = file.zir;
347348
...@@ -355,109 +356,117 @@ fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index,...@@ -355,109 +356,117 @@ fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index,
355356
356 // TODO: this should be done after all AstGen workers complete, to avoid357 // TODO: this should be done after all AstGen workers complete, to avoid
357 // iterating over this full set for every updated file.358 // iterating over this full set for every updated file.
358 for (zcu.intern_pool.tracked_insts.keys(), 0..) |*ti, idx_raw| {359 for (ip.locals, 0..) |*local, tid| {
359 const ti_idx: InternPool.TrackedInst.Index = @enumFromInt(idx_raw);360 local.mutate.tracked_insts.mutex.lock();
360 if (ti.file != file_index) continue;361 defer local.mutate.tracked_insts.mutex.unlock();
361 const old_inst = ti.inst;362 const tracked_insts_list = local.getMutableTrackedInsts(gpa);
362 ti.inst = inst_map.get(ti.inst) orelse {363 for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {
363 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.364 if (tracked_inst.file != file_index) continue;
364 zcu.comp.mutex.lock();365 const old_inst = tracked_inst.inst;
365 defer zcu.comp.mutex.unlock();366 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
366 log.debug("tracking failed for %{d}", .{old_inst});367 .tid = @enumFromInt(tid),
367 try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });368 .index = @intCast(tracked_inst_unwrapped_index),
368 continue;369 }).wrap(ip);
369 };370 tracked_inst.inst = inst_map.get(old_inst) orelse {
371 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
372 zcu.comp.mutex.lock();
373 defer zcu.comp.mutex.unlock();
374 log.debug("tracking failed for %{d}", .{old_inst});
375 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
376 continue;
377 };
370378
371 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {379 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
372 if (new_zir.getAssociatedSrcHash(ti.inst)) |new_hash| {380 if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| {
373 if (std.zig.srcHashEql(old_hash, new_hash)) {381 if (std.zig.srcHashEql(old_hash, new_hash)) {
374 break :hash_changed;382 break :hash_changed;
383 }
384 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
385 old_inst,
386 tracked_inst.inst,
387 std.fmt.fmtSliceHexLower(&old_hash),
388 std.fmt.fmtSliceHexLower(&new_hash),
389 });
375 }390 }
376 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{391 // The source hash associated with this instruction changed - invalidate relevant dependencies.
377 old_inst,392 zcu.comp.mutex.lock();
378 ti.inst,393 defer zcu.comp.mutex.unlock();
379 std.fmt.fmtSliceHexLower(&old_hash),394 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
380 std.fmt.fmtSliceHexLower(&new_hash),
381 });
382 }395 }
383 // The source hash associated with this instruction changed - invalidate relevant dependencies.
384 zcu.comp.mutex.lock();
385 defer zcu.comp.mutex.unlock();
386 try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
387 }
388396
389 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.397 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
390 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {398 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
391 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {399 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
392 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,400 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
401 else => false,
402 },
393 else => false,403 else => false,
394 },404 };
395 else => false,405 if (!has_namespace) continue;
396 };406
397 if (!has_namespace) continue;407 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
398408 defer old_names.deinit(zcu.gpa);
399 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};409 {
400 defer old_names.deinit(zcu.gpa);410 var it = old_zir.declIterator(old_inst);
401 {411 while (it.next()) |decl_inst| {
402 var it = old_zir.declIterator(old_inst);412 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
403 while (it.next()) |decl_inst| {413 switch (decl_name) {
404 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;414 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
405 switch (decl_name) {415 _ => if (decl_name.isNamedTest(old_zir)) continue,
406 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,416 }
407 _ => if (decl_name.isNamedTest(old_zir)) continue,417 const name_zir = decl_name.toString(old_zir).?;
418 const name_ip = try zcu.intern_pool.getOrPutString(
419 zcu.gpa,
420 pt.tid,
421 old_zir.nullTerminatedString(name_zir),
422 .no_embedded_nulls,
423 );
424 try old_names.put(zcu.gpa, name_ip, {});
408 }425 }
409 const name_zir = decl_name.toString(old_zir).?;
410 const name_ip = try zcu.intern_pool.getOrPutString(
411 zcu.gpa,
412 pt.tid,
413 old_zir.nullTerminatedString(name_zir),
414 .no_embedded_nulls,
415 );
416 try old_names.put(zcu.gpa, name_ip, {});
417 }426 }
418 }427 var any_change = false;
419 var any_change = false;428 {
420 {429 var it = new_zir.declIterator(tracked_inst.inst);
421 var it = new_zir.declIterator(ti.inst);430 while (it.next()) |decl_inst| {
422 while (it.next()) |decl_inst| {431 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
423 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;432 switch (decl_name) {
424 switch (decl_name) {433 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
425 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,434 _ => if (decl_name.isNamedTest(old_zir)) continue,
426 _ => if (decl_name.isNamedTest(old_zir)) continue,435 }
436 const name_zir = decl_name.toString(old_zir).?;
437 const name_ip = try zcu.intern_pool.getOrPutString(
438 zcu.gpa,
439 pt.tid,
440 old_zir.nullTerminatedString(name_zir),
441 .no_embedded_nulls,
442 );
443 if (!old_names.swapRemove(name_ip)) continue;
444 // Name added
445 any_change = true;
446 zcu.comp.mutex.lock();
447 defer zcu.comp.mutex.unlock();
448 try zcu.markDependeeOutdated(.{ .namespace_name = .{
449 .namespace = tracked_inst_index,
450 .name = name_ip,
451 } });
427 }452 }
428 const name_zir = decl_name.toString(old_zir).?;453 }
429 const name_ip = try zcu.intern_pool.getOrPutString(454 // The only elements remaining in `old_names` now are any names which were removed.
430 zcu.gpa,455 for (old_names.keys()) |name_ip| {
431 pt.tid,
432 old_zir.nullTerminatedString(name_zir),
433 .no_embedded_nulls,
434 );
435 if (!old_names.swapRemove(name_ip)) continue;
436 // Name added
437 any_change = true;456 any_change = true;
438 zcu.comp.mutex.lock();457 zcu.comp.mutex.lock();
439 defer zcu.comp.mutex.unlock();458 defer zcu.comp.mutex.unlock();
440 try zcu.markDependeeOutdated(.{ .namespace_name = .{459 try zcu.markDependeeOutdated(.{ .namespace_name = .{
441 .namespace = ti_idx,460 .namespace = tracked_inst_index,
442 .name = name_ip,461 .name = name_ip,
443 } });462 } });
444 }463 }
445 }
446 // The only elements remaining in `old_names` now are any names which were removed.
447 for (old_names.keys()) |name_ip| {
448 any_change = true;
449 zcu.comp.mutex.lock();
450 defer zcu.comp.mutex.unlock();
451 try zcu.markDependeeOutdated(.{ .namespace_name = .{
452 .namespace = ti_idx,
453 .name = name_ip,
454 } });
455 }
456464
457 if (any_change) {465 if (any_change) {
458 zcu.comp.mutex.lock();466 zcu.comp.mutex.lock();
459 defer zcu.comp.mutex.unlock();467 defer zcu.comp.mutex.unlock();
460 try zcu.markDependeeOutdated(.{ .namespace = ti_idx });468 try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index });
469 }
461 }470 }
462 }471 }
463}472}
...@@ -854,7 +863,10 @@ fn getFileRootStruct(...@@ -854,7 +863,10 @@ fn getFileRootStruct(
854 const decls = file.zir.bodySlice(extra_index, decls_len);863 const decls = file.zir.bodySlice(extra_index, decls_len);
855 extra_index += decls_len;864 extra_index += decls_len;
856865
857 const tracked_inst = try ip.trackZir(gpa, file_index, .main_struct_inst);866 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
867 .file = file_index,
868 .inst = .main_struct_inst,
869 });
858 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{870 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
859 .layout = .auto,871 .layout = .auto,
860 .fields_len = fields_len,872 .fields_len = fields_len,
...@@ -1015,7 +1027,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -1015,7 +1027,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1015 switch (zcu.comp.cache_use) {1027 switch (zcu.comp.cache_use) {
1016 .whole => |whole| if (whole.cache_manifest) |man| {1028 .whole => |whole| if (whole.cache_manifest) |man| {
1017 const source = file.getSource(gpa) catch |err| {1029 const source = file.getSource(gpa) catch |err| {
1018 try Zcu.reportRetryableFileError(zcu, file_index, "unable to load source: {s}", .{@errorName(err)});1030 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
1019 return error.AnalysisFail;1031 return error.AnalysisFail;
1020 };1032 };
10211033
...@@ -1024,7 +1036,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -1024,7 +1036,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1024 file.mod.root.sub_path,1036 file.mod.root.sub_path,
1025 file.sub_file_path,1037 file.sub_file_path,
1026 }) catch |err| {1038 }) catch |err| {
1027 try Zcu.reportRetryableFileError(zcu, file_index, "unable to resolve path: {s}", .{@errorName(err)});1039 try pt.reportRetryableFileError(file_index, "unable to resolve path: {s}", .{@errorName(err)});
1028 return error.AnalysisFail;1040 return error.AnalysisFail;
1029 };1041 };
1030 errdefer gpa.free(resolved_path);1042 errdefer gpa.free(resolved_path);
...@@ -1148,11 +1160,10 @@ fn semaDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {...@@ -1148,11 +1160,10 @@ fn semaDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {
1148 defer sema.deinit();1160 defer sema.deinit();
11491161
1150 // Every Decl (other than file root Decls, which do not have a ZIR index) has a dependency on its own source.1162 // Every Decl (other than file root Decls, which do not have a ZIR index) has a dependency on its own source.
1151 try sema.declareDependency(.{ .src_hash = try ip.trackZir(1163 try sema.declareDependency(.{ .src_hash = try ip.trackZir(gpa, pt.tid, .{
1152 gpa,1164 .file = decl.getFileScopeIndex(zcu),
1153 decl.getFileScopeIndex(zcu),1165 .inst = decl_inst,
1154 decl_inst,1166 }) });
1155 ) });
11561167
1157 var block_scope: Sema.Block = .{1168 var block_scope: Sema.Block = .{
1158 .parent = null,1169 .parent = null,
...@@ -1890,7 +1901,10 @@ const ScanDeclIter = struct {...@@ -1890,7 +1901,10 @@ const ScanDeclIter = struct {
1890 }1901 }
18911902
1892 const parent_file_scope_index = iter.parent_decl.getFileScopeIndex(zcu);1903 const parent_file_scope_index = iter.parent_decl.getFileScopeIndex(zcu);
1893 const tracked_inst = try ip.trackZir(gpa, parent_file_scope_index, decl_inst);1904 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
1905 .file = parent_file_scope_index,
1906 .inst = decl_inst,
1907 });
18941908
1895 // We create a Decl for it regardless of analysis status.1909 // We create a Decl for it regardless of analysis status.
18961910
...@@ -2611,6 +2625,87 @@ pub fn linkerUpdateDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !void {...@@ -2611,6 +2625,87 @@ pub fn linkerUpdateDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !void {
2611 }2625 }
2612}2626}
26132627
2628pub fn reportRetryableAstGenError(
2629 pt: Zcu.PerThread,
2630 src: Zcu.AstGenSrc,
2631 file_index: Zcu.File.Index,
2632 err: anyerror,
2633) error{OutOfMemory}!void {
2634 const zcu = pt.zcu;
2635 const gpa = zcu.gpa;
2636 const ip = &zcu.intern_pool;
2637
2638 const file = zcu.fileByIndex(file_index);
2639 file.status = .retryable_failure;
2640
2641 const src_loc: Zcu.LazySrcLoc = switch (src) {
2642 .root => .{
2643 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2644 .file = file_index,
2645 .inst = .main_struct_inst,
2646 }),
2647 .offset = .entire_file,
2648 },
2649 .import => |info| .{
2650 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2651 .file = info.importing_file,
2652 .inst = .main_struct_inst,
2653 }),
2654 .offset = .{ .token_abs = info.import_tok },
2655 },
2656 };
2657
2658 const err_msg = try Zcu.ErrorMsg.create(gpa, src_loc, "unable to load '{}{s}': {s}", .{
2659 file.mod.root, file.sub_file_path, @errorName(err),
2660 });
2661 errdefer err_msg.destroy(gpa);
2662
2663 {
2664 zcu.comp.mutex.lock();
2665 defer zcu.comp.mutex.unlock();
2666 try zcu.failed_files.putNoClobber(gpa, file, err_msg);
2667 }
2668}
2669
2670pub fn reportRetryableFileError(
2671 pt: Zcu.PerThread,
2672 file_index: Zcu.File.Index,
2673 comptime format: []const u8,
2674 args: anytype,
2675) error{OutOfMemory}!void {
2676 const zcu = pt.zcu;
2677 const gpa = zcu.gpa;
2678 const ip = &zcu.intern_pool;
2679
2680 const file = zcu.fileByIndex(file_index);
2681 file.status = .retryable_failure;
2682
2683 const err_msg = try Zcu.ErrorMsg.create(
2684 gpa,
2685 .{
2686 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2687 .file = file_index,
2688 .inst = .main_struct_inst,
2689 }),
2690 .offset = .entire_file,
2691 },
2692 format,
2693 args,
2694 );
2695 errdefer err_msg.destroy(gpa);
2696
2697 zcu.comp.mutex.lock();
2698 defer zcu.comp.mutex.unlock();
2699
2700 const gop = try zcu.failed_files.getOrPut(gpa, file);
2701 if (gop.found_existing) {
2702 if (gop.value_ptr.*) |old_err_msg| {
2703 old_err_msg.destroy(gpa);
2704 }
2705 }
2706 gop.value_ptr.* = err_msg;
2707}
2708
2614/// Shortcut for calling `intern_pool.get`.2709/// Shortcut for calling `intern_pool.get`.
2615pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index {2710pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index {
2616 return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key);2711 return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key);