authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-22 20:09:34+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-22 20:09:34+01:00
log985a3565c6130c7279319e9c36642f0b958e6944
tree30f4a6bed794330daefb4d3d7ef6f900e21d24b9
parent3af842f0e89125e65a87e5752234bf7e0051aa12
parent23e5a17187dc3a1f61dcb40b681f6730334d3667

Merge pull request 'Replace uses of `std.Thread.Pool` with `std.Io`, and remove `std.Thread.Pool`' (#30557) from compiler-std.Io into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30557 Reviewed-by: Andrew Kelley <andrewrk@noreply.codeberg.org>

41 files changed, 2318 insertions(+), 2096 deletions(-)

CMakeLists.txt-1
......@@ -411,7 +411,6 @@ set(ZIG_STAGE2_SOURCES
411411 lib/std/Thread.zig
412412 lib/std/Thread/Futex.zig
413413 lib/std/Thread/Mutex.zig
414 lib/std/Thread/Pool.zig
415414 lib/std/Thread/WaitGroup.zig
416415 lib/std/array_hash_map.zig
417416 lib/std/array_list.zig
lib/std/Io.zig+19-6
......@@ -1016,9 +1016,14 @@ pub fn Future(Result: type) type {
10161016pub const Group = struct {
10171017 state: usize,
10181018 context: ?*anyopaque,
1019 token: ?*anyopaque,
1019 /// This value indicates whether or not a group has pending tasks. `null`
1020 /// means there are no pending tasks, and no resources associated with the
1021 /// group, so `await` and `cancel` return immediately without calling the
1022 /// implementation. This means that `token` must be accessed atomically to
1023 /// avoid racing with the check in `await` and `cancel`.
1024 token: std.atomic.Value(?*anyopaque),
10201025
1021 pub const init: Group = .{ .state = 0, .context = null, .token = null };
1026 pub const init: Group = .{ .state = 0, .context = null, .token = .init(null) };
10221027
10231028 /// Calls `function` with `args` asynchronously. The resource spawned is
10241029 /// owned by the group.
......@@ -1081,10 +1086,14 @@ pub const Group = struct {
10811086 /// cancellation requests propagate to all members of the group.
10821087 ///
10831088 /// Idempotent. Not threadsafe.
1089 ///
1090 /// It is safe to call this function concurrently with `Group.async` or
1091 /// `Group.concurrent`, provided that the group does not complete until
1092 /// the call to `Group.async` or `Group.concurrent` returns.
10841093 pub fn wait(g: *Group, io: Io) void {
1085 const token = g.token orelse return;
1086 g.token = null;
1094 const token = g.token.load(.acquire) orelse return;
10871095 io.vtable.groupWait(io.userdata, g, token);
1096 assert(g.token.raw == null);
10881097 }
10891098
10901099 /// Equivalent to `wait` but immediately requests cancellation on all
......@@ -1093,10 +1102,14 @@ pub const Group = struct {
10931102 /// For a description of cancelation and cancelation points, see `Future.cancel`.
10941103 ///
10951104 /// Idempotent. Not threadsafe.
1105 ///
1106 /// It is safe to call this function concurrently with `Group.async` or
1107 /// `Group.concurrent`, provided that the group does not complete until
1108 /// the call to `Group.async` or `Group.concurrent` returns.
10961109 pub fn cancel(g: *Group, io: Io) void {
1097 const token = g.token orelse return;
1098 g.token = null;
1110 const token = g.token.load(.acquire) orelse return;
10991111 io.vtable.groupCancel(io.userdata, g, token);
1112 assert(g.token.raw == null);
11001113 }
11011114};
11021115
lib/std/Io/Dir.zig+1-1
......@@ -322,7 +322,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!Make
322322 var status: MakePathStatus = .existed;
323323 var component = it.last() orelse return error.BadPathName;
324324 while (true) {
325 if (makeDir(dir, io, component.path)) |_| {
325 if (makeDir(dir, io, component.path)) {
326326 status = .created;
327327 } else |err| switch (err) {
328328 error.PathAlreadyExists => {
lib/std/Io/File.zig+1-1
......@@ -419,7 +419,7 @@ pub const Reader = struct {
419419 },
420420 .streaming, .streaming_reading => {
421421 const seek_err = r.seek_err orelse e: {
422 if (io.vtable.fileSeekBy(io.userdata, r.file, offset)) |_| {
422 if (io.vtable.fileSeekBy(io.userdata, r.file, offset)) {
423423 setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset));
424424 return;
425425 } else |err| {
lib/std/Io/Threaded.zig+32-26
......@@ -1117,8 +1117,8 @@ fn groupAsync(
11171117 }
11181118
11191119 // Append to the group linked list inside the mutex to make `Io.Group.async` thread-safe.
1120 gc.node = .{ .next = @ptrCast(@alignCast(group.token)) };
1121 group.token = &gc.node;
1120 gc.node = .{ .next = @ptrCast(@alignCast(group.token.load(.monotonic))) };
1121 group.token.store(&gc.node, .monotonic);
11221122
11231123 t.run_queue.prepend(&gc.closure.node);
11241124
......@@ -1169,8 +1169,8 @@ fn groupConcurrent(
11691169 }
11701170
11711171 // Append to the group linked list inside the mutex to make `Io.Group.concurrent` thread-safe.
1172 gc.node = .{ .next = @ptrCast(@alignCast(group.token)) };
1173 group.token = &gc.node;
1172 gc.node = .{ .next = @ptrCast(@alignCast(group.token.load(.monotonic))) };
1173 group.token.store(&gc.node, .monotonic);
11741174
11751175 t.run_queue.prepend(&gc.closure.node);
11761176
......@@ -1183,11 +1183,13 @@ fn groupConcurrent(
11831183 t.cond.signal();
11841184}
11851185
1186fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
1186fn groupWait(userdata: ?*anyopaque, group: *Io.Group, initial_token: *anyopaque) void {
11871187 const t: *Threaded = @ptrCast(@alignCast(userdata));
11881188 const gpa = t.allocator;
11891189
1190 if (builtin.single_threaded) return;
1190 _ = initial_token; // we need to load `token` *after* the group finishes
1191
1192 if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null`
11911193
11921194 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
11931195 const event: *Io.Event = @ptrCast(&group.context);
......@@ -1195,37 +1197,40 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
11951197 assert(prev_state & GroupClosure.sync_is_waiting == 0);
11961198 if ((prev_state / GroupClosure.sync_one_pending) > 0) event.wait(ioBasic(t)) catch |err| switch (err) {
11971199 error.Canceled => {
1198 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
1199 while (true) {
1200 var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.load(.monotonic)));
1201 while (it) |node| : (it = node.next) {
12001202 const gc: *GroupClosure = @fieldParentPtr("node", node);
12011203 gc.closure.requestCancel(t);
1202 node = node.next orelse break;
12031204 }
12041205 event.waitUncancelable(ioBasic(t));
12051206 },
12061207 };
12071208
1208 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
1209 while (true) {
1209 // Since the group has now finished, it's illegal to add more tasks to it until we return. It's
1210 // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only
1211 // thread who can access `group` right now.
1212 var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.raw));
1213 group.token.raw = null;
1214 while (it) |node| {
1215 it = node.next; // update `it` now, because `deinit` will invalidate `node`
12101216 const gc: *GroupClosure = @fieldParentPtr("node", node);
1211 const node_next = node.next;
12121217 gc.deinit(gpa);
1213 node = node_next orelse break;
12141218 }
12151219}
12161220
1217fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
1221fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, initial_token: *anyopaque) void {
12181222 const t: *Threaded = @ptrCast(@alignCast(userdata));
12191223 const gpa = t.allocator;
12201224
1221 if (builtin.single_threaded) return;
1225 _ = initial_token; // we need to load `token` *after* the group finishes
1226
1227 if (builtin.single_threaded) unreachable; // we never set `group.token` to non-`null`
12221228
12231229 {
1224 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
1225 while (true) {
1230 var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.load(.monotonic)));
1231 while (it) |node| : (it = node.next) {
12261232 const gc: *GroupClosure = @fieldParentPtr("node", node);
12271233 gc.closure.requestCancel(t);
1228 node = node.next orelse break;
12291234 }
12301235 }
12311236
......@@ -1235,14 +1240,15 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
12351240 assert(prev_state & GroupClosure.sync_is_waiting == 0);
12361241 if ((prev_state / GroupClosure.sync_one_pending) > 0) event.waitUncancelable(ioBasic(t));
12371242
1238 {
1239 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
1240 while (true) {
1241 const gc: *GroupClosure = @fieldParentPtr("node", node);
1242 const node_next = node.next;
1243 gc.deinit(gpa);
1244 node = node_next orelse break;
1245 }
1243 // Since the group has now finished, it's illegal to add more tasks to it until we return. It's
1244 // also illegal for us to race with another `await` or `cancel`. Therefore, we must be the only
1245 // thread who can access `group` right now.
1246 var it: ?*std.SinglyLinkedList.Node = @ptrCast(@alignCast(group.token.raw));
1247 group.token.raw = null;
1248 while (it) |node| {
1249 it = node.next; // update `it` now, because `deinit` will invalidate `node`
1250 const gc: *GroupClosure = @fieldParentPtr("node", node);
1251 gc.deinit(gpa);
12461252 }
12471253}
12481254
lib/std/Thread.zig+2-2
......@@ -18,9 +18,10 @@ pub const Mutex = @import("Thread/Mutex.zig");
1818pub const Semaphore = @import("Thread/Semaphore.zig");
1919pub const Condition = @import("Thread/Condition.zig");
2020pub const RwLock = @import("Thread/RwLock.zig");
21pub const Pool = @import("Thread/Pool.zig");
2221pub const WaitGroup = @import("Thread/WaitGroup.zig");
2322
23pub const Pool = @compileError("deprecated; consider using 'std.Io.Group' with 'std.Io.Threaded'");
24
2425pub const use_pthreads = native_os != .windows and native_os != .wasi and builtin.link_libc;
2526
2627/// A thread-safe logical boolean value which can be `set` and `unset`.
......@@ -1754,7 +1755,6 @@ test {
17541755 _ = Semaphore;
17551756 _ = Condition;
17561757 _ = RwLock;
1757 _ = Pool;
17581758}
17591759
17601760fn testIncrementNotify(value: *usize, event: *ResetEvent) void {
lib/std/Thread/Pool.zig deleted-326
......@@ -1,326 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Pool = @This();
4const WaitGroup = @import("WaitGroup.zig");
5
6mutex: std.Thread.Mutex = .{},
7cond: std.Thread.Condition = .{},
8run_queue: std.SinglyLinkedList = .{},
9is_running: bool = true,
10allocator: std.mem.Allocator,
11threads: if (builtin.single_threaded) [0]std.Thread else []std.Thread,
12ids: if (builtin.single_threaded) struct {
13 inline fn deinit(_: @This(), _: std.mem.Allocator) void {}
14 fn getIndex(_: @This(), _: std.Thread.Id) usize {
15 return 0;
16 }
17} else std.AutoArrayHashMapUnmanaged(std.Thread.Id, void),
18
19const Runnable = struct {
20 runFn: RunProto,
21 node: std.SinglyLinkedList.Node = .{},
22};
23
24const RunProto = *const fn (*Runnable, id: ?usize) void;
25
26pub const Options = struct {
27 allocator: std.mem.Allocator,
28 n_jobs: ?usize = null,
29 track_ids: bool = false,
30 stack_size: usize = std.Thread.SpawnConfig.default_stack_size,
31};
32
33pub fn init(pool: *Pool, options: Options) !void {
34 const allocator = options.allocator;
35
36 pool.* = .{
37 .allocator = allocator,
38 .threads = if (builtin.single_threaded) .{} else &.{},
39 .ids = .{},
40 };
41
42 if (builtin.single_threaded) {
43 return;
44 }
45
46 const thread_count = options.n_jobs orelse @max(1, std.Thread.getCpuCount() catch 1);
47 if (options.track_ids) {
48 try pool.ids.ensureTotalCapacity(allocator, 1 + thread_count);
49 pool.ids.putAssumeCapacityNoClobber(std.Thread.getCurrentId(), {});
50 }
51
52 // kill and join any threads we spawned and free memory on error.
53 pool.threads = try allocator.alloc(std.Thread, thread_count);
54 var spawned: usize = 0;
55 errdefer pool.join(spawned);
56
57 for (pool.threads) |*thread| {
58 thread.* = try std.Thread.spawn(.{
59 .stack_size = options.stack_size,
60 .allocator = allocator,
61 }, worker, .{pool});
62 spawned += 1;
63 }
64}
65
66pub fn deinit(pool: *Pool) void {
67 pool.join(pool.threads.len); // kill and join all threads.
68 pool.ids.deinit(pool.allocator);
69 pool.* = undefined;
70}
71
72fn join(pool: *Pool, spawned: usize) void {
73 if (builtin.single_threaded) {
74 return;
75 }
76
77 {
78 pool.mutex.lock();
79 defer pool.mutex.unlock();
80
81 // ensure future worker threads exit the dequeue loop
82 pool.is_running = false;
83 }
84
85 // wake up any sleeping threads (this can be done outside the mutex)
86 // then wait for all the threads we know are spawned to complete.
87 pool.cond.broadcast();
88 for (pool.threads[0..spawned]) |thread| {
89 thread.join();
90 }
91
92 pool.allocator.free(pool.threads);
93}
94
95/// Runs `func` in the thread pool, calling `WaitGroup.start` beforehand, and
96/// `WaitGroup.finish` after it returns.
97///
98/// In the case that queuing the function call fails to allocate memory, or the
99/// target is single-threaded, the function is called directly.
100pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args: anytype) void {
101 wait_group.start();
102
103 if (builtin.single_threaded) {
104 @call(.auto, func, args);
105 wait_group.finish();
106 return;
107 }
108
109 const Args = @TypeOf(args);
110 const Closure = struct {
111 arguments: Args,
112 pool: *Pool,
113 runnable: Runnable = .{ .runFn = runFn },
114 wait_group: *WaitGroup,
115
116 fn runFn(runnable: *Runnable, _: ?usize) void {
117 const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable));
118 @call(.auto, func, closure.arguments);
119 closure.wait_group.finish();
120
121 // The thread pool's allocator is protected by the mutex.
122 const mutex = &closure.pool.mutex;
123 mutex.lock();
124 defer mutex.unlock();
125
126 closure.pool.allocator.destroy(closure);
127 }
128 };
129
130 {
131 pool.mutex.lock();
132
133 const closure = pool.allocator.create(Closure) catch {
134 pool.mutex.unlock();
135 @call(.auto, func, args);
136 wait_group.finish();
137 return;
138 };
139 closure.* = .{
140 .arguments = args,
141 .pool = pool,
142 .wait_group = wait_group,
143 };
144
145 pool.run_queue.prepend(&closure.runnable.node);
146 pool.mutex.unlock();
147 }
148
149 // Notify waiting threads outside the lock to try and keep the critical section small.
150 pool.cond.signal();
151}
152
153/// Runs `func` in the thread pool, calling `WaitGroup.start` beforehand, and
154/// `WaitGroup.finish` after it returns.
155///
156/// The first argument passed to `func` is a dense `usize` thread id, the rest
157/// of the arguments are passed from `args`. Requires the pool to have been
158/// initialized with `.track_ids = true`.
159///
160/// In the case that queuing the function call fails to allocate memory, or the
161/// target is single-threaded, the function is called directly.
162pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args: anytype) void {
163 wait_group.start();
164
165 if (builtin.single_threaded) {
166 @call(.auto, func, .{0} ++ args);
167 wait_group.finish();
168 return;
169 }
170
171 const Args = @TypeOf(args);
172 const Closure = struct {
173 arguments: Args,
174 pool: *Pool,
175 runnable: Runnable = .{ .runFn = runFn },
176 wait_group: *WaitGroup,
177
178 fn runFn(runnable: *Runnable, id: ?usize) void {
179 const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable));
180 @call(.auto, func, .{id.?} ++ closure.arguments);
181 closure.wait_group.finish();
182
183 // The thread pool's allocator is protected by the mutex.
184 const mutex = &closure.pool.mutex;
185 mutex.lock();
186 defer mutex.unlock();
187
188 closure.pool.allocator.destroy(closure);
189 }
190 };
191
192 {
193 pool.mutex.lock();
194
195 const closure = pool.allocator.create(Closure) catch {
196 const id: ?usize = pool.ids.getIndex(std.Thread.getCurrentId());
197 pool.mutex.unlock();
198 @call(.auto, func, .{id.?} ++ args);
199 wait_group.finish();
200 return;
201 };
202 closure.* = .{
203 .arguments = args,
204 .pool = pool,
205 .wait_group = wait_group,
206 };
207
208 pool.run_queue.prepend(&closure.runnable.node);
209 pool.mutex.unlock();
210 }
211
212 // Notify waiting threads outside the lock to try and keep the critical section small.
213 pool.cond.signal();
214}
215
216pub fn spawn(pool: *Pool, comptime func: anytype, args: anytype) !void {
217 if (builtin.single_threaded) {
218 @call(.auto, func, args);
219 return;
220 }
221
222 const Args = @TypeOf(args);
223 const Closure = struct {
224 arguments: Args,
225 pool: *Pool,
226 runnable: Runnable = .{ .runFn = runFn },
227
228 fn runFn(runnable: *Runnable, _: ?usize) void {
229 const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable));
230 @call(.auto, func, closure.arguments);
231
232 // The thread pool's allocator is protected by the mutex.
233 const mutex = &closure.pool.mutex;
234 mutex.lock();
235 defer mutex.unlock();
236
237 closure.pool.allocator.destroy(closure);
238 }
239 };
240
241 {
242 pool.mutex.lock();
243 defer pool.mutex.unlock();
244
245 const closure = try pool.allocator.create(Closure);
246 closure.* = .{
247 .arguments = args,
248 .pool = pool,
249 };
250
251 pool.run_queue.prepend(&closure.runnable.node);
252 }
253
254 // Notify waiting threads outside the lock to try and keep the critical section small.
255 pool.cond.signal();
256}
257
258test spawn {
259 const TestFn = struct {
260 fn checkRun(completed: *bool) void {
261 completed.* = true;
262 }
263 };
264
265 var completed: bool = false;
266
267 {
268 var pool: Pool = undefined;
269 try pool.init(.{
270 .allocator = std.testing.allocator,
271 });
272 defer pool.deinit();
273 try pool.spawn(TestFn.checkRun, .{&completed});
274 }
275
276 try std.testing.expectEqual(true, completed);
277}
278
279fn worker(pool: *Pool) void {
280 pool.mutex.lock();
281 defer pool.mutex.unlock();
282
283 const id: ?usize = if (pool.ids.count() > 0) @intCast(pool.ids.count()) else null;
284 if (id) |_| pool.ids.putAssumeCapacityNoClobber(std.Thread.getCurrentId(), {});
285
286 while (true) {
287 while (pool.run_queue.popFirst()) |run_node| {
288 // Temporarily unlock the mutex in order to execute the run_node
289 pool.mutex.unlock();
290 defer pool.mutex.lock();
291
292 const runnable: *Runnable = @fieldParentPtr("node", run_node);
293 runnable.runFn(runnable, id);
294 }
295
296 // Stop executing instead of waiting if the thread pool is no longer running.
297 if (pool.is_running) {
298 pool.cond.wait(&pool.mutex);
299 } else {
300 break;
301 }
302 }
303}
304
305pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {
306 var id: ?usize = null;
307
308 while (!wait_group.isDone()) {
309 pool.mutex.lock();
310 if (pool.run_queue.popFirst()) |run_node| {
311 id = id orelse pool.ids.getIndex(std.Thread.getCurrentId());
312 pool.mutex.unlock();
313 const runnable: *Runnable = @fieldParentPtr("node", run_node);
314 runnable.runFn(runnable, id);
315 continue;
316 }
317
318 pool.mutex.unlock();
319 wait_group.wait();
320 return;
321 }
322}
323
324pub fn getIdCount(pool: *Pool) usize {
325 return @intCast(1 + pool.threads.len);
326}
src/Compilation.zig+421-466
......@@ -10,8 +10,6 @@ const Allocator = std.mem.Allocator;
1010const assert = std.debug.assert;
1111const log = std.log.scoped(.compilation);
1212const Target = std.Target;
13const ThreadPool = std.Thread.Pool;
14const WaitGroup = std.Thread.WaitGroup;
1513const ErrorBundle = std.zig.ErrorBundle;
1614const fatal = std.process.fatal;
1715
......@@ -56,6 +54,7 @@ gpa: Allocator,
5654/// threads at once.
5755arena: Allocator,
5856io: Io,
57thread_limit: usize,
5958/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
6059zcu: ?*Zcu,
6160/// Contains different state depending on the `CacheMode` used by this `Compilation`.
......@@ -110,7 +109,14 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa
110109} = .{},
111110
112111link_diags: link.Diags,
113link_task_queue: link.Queue = .empty,
112link_queue: link.Queue = .empty,
113
114/// This is populated during `Compilation.create` with a set of prelink tasks which need to be
115/// queued on the first update. In `update`, we will send these tasks to the linker, and clear
116/// them from this list.
117///
118/// Allocated into `gpa`.
119oneshot_prelink_tasks: std.ArrayList(link.PrelinkTask),
114120
115121/// Set of work that can be represented by only flags to determine whether the
116122/// work is queued or not.
......@@ -198,7 +204,6 @@ libc_include_dir_list: []const []const u8,
198204libc_framework_dir_list: []const []const u8,
199205rc_includes: std.zig.RcIncludes,
200206mingw_unicode_entry_point: bool,
201thread_pool: *ThreadPool,
202207
203208/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
204209/// and resolved before calling linker.flush().
......@@ -248,16 +253,10 @@ crt_files: std.StringHashMapUnmanaged(CrtFile) = .empty,
248253reference_trace: ?u32 = null,
249254
250255/// This mutex guards all `Compilation` mutable state.
251/// Disabled in single-threaded mode because the thread pool spawns in the same thread.
252mutex: if (builtin.single_threaded) struct {
253 pub inline fn tryLock(_: @This()) void {}
254 pub inline fn lock(_: @This()) void {}
255 pub inline fn unlock(_: @This()) void {}
256} else std.Thread.Mutex = .{},
256mutex: std.Io.Mutex = .init,
257257
258258test_filters: []const []const u8,
259259
260link_task_wait_group: WaitGroup = .{},
261260link_prog_node: std.Progress.Node = .none,
262261
263262llvm_opt_bisect_limit: c_int,
......@@ -1568,7 +1567,7 @@ pub const CacheMode = enum {
15681567
15691568pub const ParentWholeCache = struct {
15701569 manifest: *Cache.Manifest,
1571 mutex: *std.Thread.Mutex,
1570 mutex: *std.Io.Mutex,
15721571 prefix_map: [4]u8,
15731572};
15741573
......@@ -1596,7 +1595,7 @@ const CacheUse = union(CacheMode) {
15961595 lf_open_opts: link.File.OpenOptions,
15971596 /// This is a pointer to a local variable inside `update`.
15981597 cache_manifest: ?*Cache.Manifest,
1599 cache_manifest_mutex: std.Thread.Mutex,
1598 cache_manifest_mutex: std.Io.Mutex,
16001599 /// This is non-`null` for most of the body of `update`. It is the temporary directory which
16011600 /// we initially emit our artifacts to. After the main part of the update is done, it will
16021601 /// be closed and moved to its final location, and this field set to `null`.
......@@ -1636,7 +1635,7 @@ const CacheUse = union(CacheMode) {
16361635
16371636pub const CreateOptions = struct {
16381637 dirs: Directories,
1639 thread_pool: *ThreadPool,
1638 thread_limit: usize,
16401639 self_exe_path: ?[]const u8 = null,
16411640
16421641 /// Options that have been resolved by calling `resolveDefaults`.
......@@ -2211,8 +2210,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
22112210 .llvm_object = null,
22122211 .analysis_roots_buffer = undefined,
22132212 .analysis_roots_len = 0,
2213 .codegen_task_pool = try .init(arena),
22142214 };
2215 try zcu.init(options.thread_pool.getIdCount());
2215 try zcu.init(gpa, io, options.thread_limit);
22162216 break :blk zcu;
22172217 } else blk: {
22182218 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu);
......@@ -2224,6 +2224,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
22242224 .gpa = gpa,
22252225 .arena = arena,
22262226 .io = io,
2227 .thread_limit = options.thread_limit,
22272228 .zcu = opt_zcu,
22282229 .cache_use = undefined, // populated below
22292230 .bin_file = null, // populated below if necessary
......@@ -2241,7 +2242,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
22412242 .libc_framework_dir_list = libc_dirs.libc_framework_dir_list,
22422243 .rc_includes = options.rc_includes,
22432244 .mingw_unicode_entry_point = options.mingw_unicode_entry_point,
2244 .thread_pool = options.thread_pool,
22452245 .clang_passthrough_mode = options.clang_passthrough_mode,
22462246 .clang_preprocessor_mode = options.clang_preprocessor_mode,
22472247 .verbose_cc = options.verbose_cc,
......@@ -2282,7 +2282,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
22822282 .global_cc_argv = options.global_cc_argv,
22832283 .file_system_inputs = options.file_system_inputs,
22842284 .parent_whole_cache = options.parent_whole_cache,
2285 .link_diags = .init(gpa),
2285 .link_diags = .init(gpa, io),
2286 .oneshot_prelink_tasks = .empty,
22862287 .emit_bin = try options.emit_bin.resolve(arena, &options, .bin),
22872288 .emit_asm = try options.emit_asm.resolve(arena, &options, .@"asm"),
22882289 .emit_implib = try options.emit_implib.resolve(arena, &options, .implib),
......@@ -2468,7 +2469,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
24682469 whole.* = .{
24692470 .lf_open_opts = lf_open_opts,
24702471 .cache_manifest = null,
2471 .cache_manifest_mutex = .{},
2472 .cache_manifest_mutex = .init,
24722473 .tmp_artifact_directory = null,
24732474 .lock = null,
24742475 };
......@@ -2553,14 +2554,14 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
25532554 };
25542555
25552556 const fields = @typeInfo(@TypeOf(paths)).@"struct".fields;
2556 try comp.link_task_queue.queued_prelink.ensureUnusedCapacity(gpa, fields.len + 1);
2557 try comp.oneshot_prelink_tasks.ensureUnusedCapacity(gpa, fields.len + 1);
25572558 inline for (fields) |field| {
25582559 if (@field(paths, field.name)) |path| {
2559 comp.link_task_queue.queued_prelink.appendAssumeCapacity(.{ .load_object = path });
2560 comp.oneshot_prelink_tasks.appendAssumeCapacity(.{ .load_object = path });
25602561 }
25612562 }
25622563 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`.
2563 comp.link_task_queue.queued_prelink.appendAssumeCapacity(.load_host_libc);
2564 comp.oneshot_prelink_tasks.appendAssumeCapacity(.load_host_libc);
25642565 } else if (target.isMuslLibC()) {
25652566 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable);
25662567
......@@ -2629,10 +2630,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
26292630 for (0..count) |i| {
26302631 try comp.queueJob(.{ .windows_import_lib = i });
26312632 }
2632 // when integrating coff linker with prelink, the above
2633 // queueJob will need to change into something else since those
2634 // jobs are dispatched *after* the link_task_wait_group.wait()
2635 // that happens when separateCodegenThreadOk() is false.
2633 // when integrating coff linker with prelink, the above `queueJob` will need to move
2634 // to something in `dispatchPrelinkWork`, which must queue all prelink link tasks
2635 // *before* we begin working on the main job queue.
26362636 }
26372637 if (comp.wantBuildLibUnwindFromSource()) {
26382638 comp.queued_jobs.libunwind = true;
......@@ -2681,19 +2681,15 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
26812681 }
26822682 }
26832683
2684 try comp.link_task_queue.queued_prelink.append(gpa, .load_explicitly_provided);
2684 try comp.oneshot_prelink_tasks.append(gpa, .load_explicitly_provided);
26852685 }
2686 log.debug("queued prelink tasks: {d}", .{comp.link_task_queue.queued_prelink.items.len});
2686 log.debug("queued oneshot prelink tasks: {d}", .{comp.oneshot_prelink_tasks.items.len});
26872687 return comp;
26882688}
26892689
26902690pub fn destroy(comp: *Compilation) void {
26912691 const gpa = comp.gpa;
26922692
2693 // This needs to be destroyed first, because it might contain MIR which we only know
2694 // how to interpret (which kind of MIR it is) from `comp.bin_file`.
2695 comp.link_task_queue.deinit(comp);
2696
26972693 if (comp.bin_file) |lf| lf.destroy();
26982694 if (comp.zcu) |zcu| zcu.deinit();
26992695 comp.cache_use.deinit();
......@@ -2760,6 +2756,7 @@ pub fn destroy(comp: *Compilation) void {
27602756 if (comp.time_report) |*tr| tr.deinit(gpa);
27612757
27622758 comp.link_diags.deinit();
2759 comp.oneshot_prelink_tasks.deinit(gpa);
27632760
27642761 comp.clearMiscFailures();
27652762
......@@ -2865,8 +2862,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28652862 const tracy_trace = trace(@src());
28662863 defer tracy_trace.end();
28672864
2868 // This arena is scoped to this one update.
28692865 const gpa = comp.gpa;
2866 const io = comp.io;
2867
2868 // This arena is scoped to this one update.
28702869 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
28712870 defer arena_allocator.deinit();
28722871 const arena = arena_allocator.allocator();
......@@ -2946,8 +2945,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
29462945 // In this case the cache hit contains the full set of file system inputs. Nice!
29472946 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
29482947 if (comp.parent_whole_cache) |pwc| {
2949 pwc.mutex.lock();
2950 defer pwc.mutex.unlock();
2948 try pwc.mutex.lock(io);
2949 defer pwc.mutex.unlock(io);
29512950 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
29522951 }
29532952
......@@ -3066,7 +3065,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
30663065 comp.link_prog_node = .none;
30673066 };
30683067
3069 try comp.performAllTheWork(main_progress_node);
3068 try comp.performAllTheWork(main_progress_node, arena);
30703069
30713070 if (comp.zcu) |zcu| {
30723071 const pt: Zcu.PerThread = .activate(zcu, .main);
......@@ -3132,8 +3131,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
31323131 .whole => |whole| {
31333132 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
31343133 if (comp.parent_whole_cache) |pwc| {
3135 pwc.mutex.lock();
3136 defer pwc.mutex.unlock();
3134 try pwc.mutex.lock(io);
3135 defer pwc.mutex.unlock(io);
31373136 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
31383137 }
31393138
......@@ -3234,6 +3233,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
32343233/// Thread-safe. Assumes that `comp.mutex` is *not* already held by the caller.
32353234pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocator.Error!void {
32363235 const gpa = comp.gpa;
3236 const io = comp.io;
32373237 const fsi = comp.file_system_inputs orelse return;
32383238 const prefixes = comp.cache_parent.prefixes();
32393239
......@@ -3253,8 +3253,8 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
32533253 );
32543254
32553255 // There may be concurrent calls to this function from C object workers and/or the main thread.
3256 comp.mutex.lock();
3257 defer comp.mutex.unlock();
3256 comp.mutex.lockUncancelable(io);
3257 defer comp.mutex.unlock(io);
32583258
32593259 try fsi.ensureUnusedCapacity(gpa, path.sub_path.len + 3);
32603260 if (fsi.items.len > 0) fsi.appendAssumeCapacity(0);
......@@ -3305,6 +3305,7 @@ fn flush(
33053305 arena: Allocator,
33063306 tid: Zcu.PerThread.Id,
33073307) Allocator.Error!void {
3308 const io = comp.io;
33083309 if (comp.zcu) |zcu| {
33093310 if (zcu.llvm_object) |llvm_object| {
33103311 const pt: Zcu.PerThread = .activate(zcu, tid);
......@@ -3317,8 +3318,8 @@ fn flush(
33173318
33183319 var timer = comp.startTimer();
33193320 defer if (timer.finish()) |ns| {
3320 comp.mutex.lock();
3321 defer comp.mutex.unlock();
3321 comp.mutex.lockUncancelable(io);
3322 defer comp.mutex.unlock(io);
33223323 comp.time_report.?.stats.real_ns_llvm_emit = ns;
33233324 };
33243325
......@@ -3362,8 +3363,8 @@ fn flush(
33623363 if (comp.bin_file) |lf| {
33633364 var timer = comp.startTimer();
33643365 defer if (timer.finish()) |ns| {
3365 comp.mutex.lock();
3366 defer comp.mutex.unlock();
3366 comp.mutex.lockUncancelable(io);
3367 defer comp.mutex.unlock(io);
33673368 comp.time_report.?.stats.real_ns_link_flush = ns;
33683369 };
33693370 // This is needed before reading the error flags.
......@@ -4575,44 +4576,277 @@ pub fn unableToLoadZcuFile(
45754576fn performAllTheWork(
45764577 comp: *Compilation,
45774578 main_progress_node: std.Progress.Node,
4579 update_arena: Allocator,
45784580) JobError!void {
4579 // Regardless of errors, `comp.zcu` needs to update its generation number.
45804581 defer if (comp.zcu) |zcu| {
4582 zcu.codegen_task_pool.cancel(zcu);
4583 // Regardless of errors, `comp.zcu` needs to update its generation number.
45814584 zcu.generation += 1;
45824585 };
45834586
4587 const io = comp.io;
4588
45844589 // This is awkward: we don't want to start the timer until later, but we won't want to stop it
45854590 // until the wait groups finish. That means we need do do this.
45864591 var decl_work_timer: ?Timer = null;
45874592 defer commit_timer: {
45884593 const t = &(decl_work_timer orelse break :commit_timer);
45894594 const ns = t.finish() orelse break :commit_timer;
4590 comp.mutex.lock();
4591 defer comp.mutex.unlock();
4595 comp.mutex.lockUncancelable(io);
4596 defer comp.mutex.unlock(io);
45924597 comp.time_report.?.stats.real_ns_decls = ns;
45934598 }
45944599
4595 // Here we queue up all the AstGen tasks first, followed by C object compilation.
4596 // We wait until the AstGen tasks are all completed before proceeding to the
4597 // (at least for now) single-threaded main work queue. However, C object compilation
4598 // only needs to be finished by the end of this function.
4599
4600 var work_queue_wait_group: WaitGroup = .{};
4601 defer work_queue_wait_group.wait();
4600 var misc_group: Io.Group = .init;
4601 defer misc_group.cancel(io);
46024602
4603 comp.link_task_wait_group.reset();
4604 defer comp.link_task_wait_group.wait();
4603 try comp.link_queue.start(comp, update_arena);
4604 defer comp.link_queue.cancel(io);
46054605
4606 // Already-queued prelink tasks
4607 comp.link_prog_node.increaseEstimatedTotalItems(comp.link_task_queue.queued_prelink.items.len);
4608 comp.link_task_queue.start(comp);
4606 misc_group.concurrent(io, dispatchPrelinkWork, .{ comp, main_progress_node }) catch |err| switch (err) {
4607 error.ConcurrencyUnavailable => {
4608 // Do it immediately so that the link queue isn't blocked
4609 dispatchPrelinkWork(comp, main_progress_node);
4610 },
4611 };
46094612
46104613 if (comp.emit_docs != null) {
46114614 dev.check(.docs_emit);
4612 comp.thread_pool.spawnWg(&work_queue_wait_group, workerDocsCopy, .{comp});
4613 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
4615 misc_group.async(io, workerDocsCopy, .{comp});
4616 misc_group.async(io, workerDocsWasm, .{ comp, main_progress_node });
4617 }
4618
4619 if (comp.zcu) |zcu| {
4620 const astgen_frame = tracy.namedFrame("astgen");
4621 defer astgen_frame.end();
4622
4623 const zir_prog_node = main_progress_node.start("AST Lowering", 0);
4624 defer zir_prog_node.end();
4625
4626 var timer = comp.startTimer();
4627 defer if (timer.finish()) |ns| {
4628 comp.mutex.lockUncancelable(io);
4629 defer comp.mutex.unlock(io);
4630 comp.time_report.?.stats.real_ns_files = ns;
4631 };
4632
4633 const gpa = comp.gpa;
4634
4635 var astgen_group: Io.Group = .init;
4636 defer astgen_group.cancel(io);
4637
4638 // We cannot reference `zcu.import_table` after we spawn any `workerUpdateFile` jobs,
4639 // because on single-threaded targets the worker will be run eagerly, meaning the
4640 // `import_table` could be mutated, and not even holding `comp.mutex` will save us. So,
4641 // build up a list of the files to update *before* we spawn any jobs.
4642 var astgen_work_items: std.MultiArrayList(struct {
4643 file_index: Zcu.File.Index,
4644 file: *Zcu.File,
4645 }) = .empty;
4646 defer astgen_work_items.deinit(gpa);
4647 // Not every item in `import_table` will need updating, because some are builtin.zig
4648 // files. However, most will, so let's just reserve sufficient capacity upfront.
4649 try astgen_work_items.ensureTotalCapacity(gpa, zcu.import_table.count());
4650 for (zcu.import_table.keys()) |file_index| {
4651 const file = zcu.fileByIndex(file_index);
4652 if (file.is_builtin) {
4653 // This is a `builtin.zig`, so updating is redundant. However, we want to make
4654 // sure the file contents are still correct on disk, since it can improve the
4655 // debugging experience better. That job only needs `file`, so we can kick it
4656 // off right now.
4657 astgen_group.async(io, workerUpdateBuiltinFile, .{ comp, file });
4658 continue;
4659 }
4660 astgen_work_items.appendAssumeCapacity(.{
4661 .file_index = file_index,
4662 .file = file,
4663 });
4664 }
4665
4666 // Now that we're not going to touch `zcu.import_table` again, we can spawn `workerUpdateFile` jobs.
4667 for (astgen_work_items.items(.file_index), astgen_work_items.items(.file)) |file_index, file| {
4668 astgen_group.async(io, workerUpdateFile, .{
4669 comp, file, file_index, zir_prog_node, &astgen_group,
4670 });
4671 }
4672
4673 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
4674 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
4675 // `@embedFile` can't trigger analysis of a new `@embedFile`!
4676 for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {
4677 const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
4678 astgen_group.async(io, workerUpdateEmbedFile, .{
4679 comp, ef_index, ef,
4680 });
4681 }
4682
4683 astgen_group.wait(io);
4684 }
4685
4686 if (comp.zcu) |zcu| {
4687 const pt: Zcu.PerThread = .activate(zcu, .main);
4688 defer pt.deactivate();
4689
4690 const gpa = zcu.gpa;
4691
4692 // On an incremental update, a source file might become "dead", in that all imports of
4693 // the file were removed. This could even change what module the file belongs to! As such,
4694 // we do a traversal over the files, to figure out which ones are alive and the modules
4695 // they belong to.
4696 const any_fatal_files = try pt.computeAliveFiles();
4697
4698 // If the cache mode is `whole`, add every alive source file to the manifest.
4699 switch (comp.cache_use) {
4700 .whole => |whole| if (whole.cache_manifest) |man| {
4701 for (zcu.alive_files.keys()) |file_index| {
4702 const file = zcu.fileByIndex(file_index);
4703
4704 switch (file.status) {
4705 .never_loaded => unreachable, // AstGen tried to load it
4706 .retryable_failure => continue, // the file cannot be read; this is a guaranteed error
4707 .astgen_failure, .success => {}, // the file was read successfully
4708 }
4709
4710 const path = try file.path.toAbsolute(comp.dirs, gpa);
4711 defer gpa.free(path);
4712
4713 const result = res: {
4714 try whole.cache_manifest_mutex.lock(io);
4715 defer whole.cache_manifest_mutex.unlock(io);
4716 if (file.source) |source| {
4717 break :res man.addFilePostContents(path, source, file.stat);
4718 } else {
4719 break :res man.addFilePost(path);
4720 }
4721 };
4722 result catch |err| switch (err) {
4723 error.OutOfMemory => |e| return e,
4724 else => {
4725 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
4726 continue;
4727 },
4728 };
4729 }
4730 },
4731 .none, .incremental => {},
4732 }
4733
4734 if (any_fatal_files or
4735 zcu.multi_module_err != null or
4736 zcu.failed_imports.items.len > 0 or
4737 comp.alloc_failure_occurred)
4738 {
4739 // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
4740 // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
4741 // However, this means our analysis data is invalid, so we want to omit all analysis errors.
4742 zcu.skip_analysis_this_update = true;
4743 // Since we're skipping analysis, there are no ZCU link tasks.
4744 comp.link_queue.finishZcuQueue(comp);
4745 // Let other compilation work finish to collect as many errors as possible.
4746 misc_group.wait(io);
4747 comp.link_queue.wait(io);
4748 return;
4749 }
4750
4751 if (comp.time_report) |*tr| {
4752 tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());
4753 }
4754
4755 if (comp.config.incremental) {
4756 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
4757 defer update_zir_refs_node.end();
4758 try pt.updateZirRefs();
4759 }
4760 try zcu.flushRetryableFailures();
4761
4762 // It's analysis time! Queue up our initial analysis.
4763 for (zcu.analysisRoots()) |mod| {
4764 try comp.queueJob(.{ .analyze_mod = mod });
4765 }
4766
4767 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
4768 if (comp.bin_file != null) {
4769 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
4770 }
4771 // We increment `pending_codegen_jobs` so that it doesn't reach 0 until after analysis finishes.
4772 // That prevents the "Code Generation" node from constantly disappearing and reappearing when
4773 // we're probably going to analyze more functions at some point.
4774 assert(zcu.pending_codegen_jobs.swap(1, .monotonic) == 0); // don't let this become 0 until analysis finishes
4775 }
4776 // When analysis ends, delete the progress nodes for "Semantic Analysis" and possibly "Code Generation".
4777 defer if (comp.zcu) |zcu| {
4778 zcu.sema_prog_node.end();
4779 zcu.sema_prog_node = .none;
4780 if (zcu.pending_codegen_jobs.fetchSub(1, .monotonic) == 1) {
4781 // Decremented to 0, so all done.
4782 zcu.codegen_prog_node.end();
4783 zcu.codegen_prog_node = .none;
4784 }
4785 };
4786
4787 if (comp.zcu) |zcu| {
4788 if (!zcu.backendSupportsFeature(.separate_thread)) {
4789 // Close the ZCU task queue. Prelink may still be running, but the closed
4790 // queue will cause the linker task to exit once prelink finishes. The
4791 // closed queue also communicates to `enqueueZcu` that it should wait for
4792 // the linker task to finish and then run ZCU tasks serially.
4793 comp.link_queue.finishZcuQueue(comp);
4794 }
4795 }
4796
4797 if (comp.zcu != null) {
4798 // Start the timer for the "decls" part of the pipeline (Sema, CodeGen, link).
4799 decl_work_timer = comp.startTimer();
46144800 }
46154801
4802 work: while (true) {
4803 for (&comp.work_queues) |*work_queue| if (work_queue.popFront()) |job| {
4804 try processOneJob(
4805 @intFromEnum(Zcu.PerThread.Id.main),
4806 comp,
4807 job,
4808 );
4809 continue :work;
4810 };
4811 if (comp.zcu) |zcu| {
4812 // If there's no work queued, check if there's anything outdated
4813 // which we need to work on, and queue it if so.
4814 if (try zcu.findOutdatedToAnalyze()) |outdated| {
4815 try comp.queueJob(switch (outdated.unwrap()) {
4816 .func => |f| .{ .analyze_func = f },
4817 .memoized_state,
4818 .@"comptime",
4819 .nav_ty,
4820 .nav_val,
4821 .type,
4822 => .{ .analyze_comptime_unit = outdated },
4823 });
4824 continue;
4825 }
4826 zcu.sema_prog_node.end();
4827 zcu.sema_prog_node = .none;
4828 }
4829 break;
4830 }
4831
4832 comp.link_queue.finishZcuQueue(comp);
4833
4834 // Main thread work is all done, now just wait for all async work.
4835 misc_group.wait(io);
4836 comp.link_queue.wait(io);
4837}
4838
4839fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node) void {
4840 const io = comp.io;
4841
4842 var prelink_group: Io.Group = .init;
4843 defer prelink_group.cancel(io);
4844
4845 comp.queuePrelinkTasks(comp.oneshot_prelink_tasks.items) catch |err| switch (err) {
4846 error.Canceled => return,
4847 };
4848 comp.oneshot_prelink_tasks.clearRetainingCapacity();
4849
46164850 // In case it failed last time, try again. `clearMiscFailures` was already
46174851 // called at the start of `update`.
46184852 if (comp.queued_jobs.compiler_rt_lib and comp.compiler_rt_lib == null) {
......@@ -4620,8 +4854,7 @@ fn performAllTheWork(
46204854 // compiler-rt due to LLD bugs as well, e.g.:
46214855 //
46224856 // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611
4623 comp.link_task_queue.startPrelinkItem();
4624 comp.link_task_wait_group.spawnManager(buildRt, .{
4857 prelink_group.async(io, buildRt, .{
46254858 comp,
46264859 "compiler_rt.zig",
46274860 "compiler_rt",
......@@ -4638,8 +4871,7 @@ fn performAllTheWork(
46384871 }
46394872
46404873 if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) {
4641 comp.link_task_queue.startPrelinkItem();
4642 comp.link_task_wait_group.spawnManager(buildRt, .{
4874 prelink_group.async(io, buildRt, .{
46434875 comp,
46444876 "compiler_rt.zig",
46454877 "compiler_rt",
......@@ -4657,8 +4889,7 @@ fn performAllTheWork(
46574889
46584890 // hack for stage2_x86_64 + coff
46594891 if (comp.queued_jobs.compiler_rt_dyn_lib and comp.compiler_rt_dyn_lib == null) {
4660 comp.link_task_queue.startPrelinkItem();
4661 comp.link_task_wait_group.spawnManager(buildRt, .{
4892 prelink_group.async(io, buildRt, .{
46624893 comp,
46634894 "compiler_rt.zig",
46644895 "compiler_rt",
......@@ -4675,8 +4906,7 @@ fn performAllTheWork(
46754906 }
46764907
46774908 if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) {
4678 comp.link_task_queue.startPrelinkItem();
4679 comp.link_task_wait_group.spawnManager(buildRt, .{
4909 prelink_group.async(io, buildRt, .{
46804910 comp,
46814911 "fuzzer.zig",
46824912 "fuzzer",
......@@ -4690,8 +4920,7 @@ fn performAllTheWork(
46904920 }
46914921
46924922 if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) {
4693 comp.link_task_queue.startPrelinkItem();
4694 comp.link_task_wait_group.spawnManager(buildRt, .{
4923 prelink_group.async(io, buildRt, .{
46954924 comp,
46964925 "ubsan_rt.zig",
46974926 "ubsan_rt",
......@@ -4707,8 +4936,7 @@ fn performAllTheWork(
47074936 }
47084937
47094938 if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) {
4710 comp.link_task_queue.startPrelinkItem();
4711 comp.link_task_wait_group.spawnManager(buildRt, .{
4939 prelink_group.async(io, buildRt, .{
47124940 comp,
47134941 "ubsan_rt.zig",
47144942 "ubsan_rt",
......@@ -4724,310 +4952,93 @@ fn performAllTheWork(
47244952 }
47254953
47264954 if (comp.queued_jobs.glibc_shared_objects) {
4727 comp.link_task_queue.startPrelinkItem();
4728 comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });
4955 prelink_group.async(io, buildGlibcSharedObjects, .{ comp, main_progress_node });
47294956 }
47304957
47314958 if (comp.queued_jobs.freebsd_shared_objects) {
4732 comp.link_task_queue.startPrelinkItem();
4733 comp.link_task_wait_group.spawnManager(buildFreeBSDSharedObjects, .{ comp, main_progress_node });
4959 prelink_group.async(io, buildFreeBSDSharedObjects, .{ comp, main_progress_node });
47344960 }
47354961
47364962 if (comp.queued_jobs.netbsd_shared_objects) {
4737 comp.link_task_queue.startPrelinkItem();
4738 comp.link_task_wait_group.spawnManager(buildNetBSDSharedObjects, .{ comp, main_progress_node });
4963 prelink_group.async(io, buildNetBSDSharedObjects, .{ comp, main_progress_node });
47394964 }
47404965
47414966 if (comp.queued_jobs.libunwind) {
4742 comp.link_task_queue.startPrelinkItem();
4743 comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });
4967 prelink_group.async(io, buildLibUnwind, .{ comp, main_progress_node });
47444968 }
47454969
47464970 if (comp.queued_jobs.libcxx) {
4747 comp.link_task_queue.startPrelinkItem();
4748 comp.link_task_wait_group.spawnManager(buildLibCxx, .{ comp, main_progress_node });
4971 prelink_group.async(io, buildLibCxx, .{ comp, main_progress_node });
47494972 }
47504973
47514974 if (comp.queued_jobs.libcxxabi) {
4752 comp.link_task_queue.startPrelinkItem();
4753 comp.link_task_wait_group.spawnManager(buildLibCxxAbi, .{ comp, main_progress_node });
4975 prelink_group.async(io, buildLibCxxAbi, .{ comp, main_progress_node });
47544976 }
47554977
47564978 if (comp.queued_jobs.libtsan) {
4757 comp.link_task_queue.startPrelinkItem();
4758 comp.link_task_wait_group.spawnManager(buildLibTsan, .{ comp, main_progress_node });
4979 prelink_group.async(io, buildLibTsan, .{ comp, main_progress_node });
47594980 }
47604981
47614982 if (comp.queued_jobs.zigc_lib and comp.zigc_static_lib == null) {
4762 comp.link_task_queue.startPrelinkItem();
4763 comp.link_task_wait_group.spawnManager(buildLibZigC, .{ comp, main_progress_node });
4983 prelink_group.async(io, buildLibZigC, .{ comp, main_progress_node });
47644984 }
47654985
47664986 for (0..@typeInfo(musl.CrtFile).@"enum".fields.len) |i| {
47674987 if (comp.queued_jobs.musl_crt_file[i]) {
47684988 const tag: musl.CrtFile = @enumFromInt(i);
4769 comp.link_task_queue.startPrelinkItem();
4770 comp.link_task_wait_group.spawnManager(buildMuslCrtFile, .{ comp, tag, main_progress_node });
4989 prelink_group.async(io, buildMuslCrtFile, .{ comp, tag, main_progress_node });
47714990 }
47724991 }
47734992
47744993 for (0..@typeInfo(glibc.CrtFile).@"enum".fields.len) |i| {
47754994 if (comp.queued_jobs.glibc_crt_file[i]) {
47764995 const tag: glibc.CrtFile = @enumFromInt(i);
4777 comp.link_task_queue.startPrelinkItem();
4778 comp.link_task_wait_group.spawnManager(buildGlibcCrtFile, .{ comp, tag, main_progress_node });
4996 prelink_group.async(io, buildGlibcCrtFile, .{ comp, tag, main_progress_node });
47794997 }
47804998 }
47814999
47825000 for (0..@typeInfo(freebsd.CrtFile).@"enum".fields.len) |i| {
47835001 if (comp.queued_jobs.freebsd_crt_file[i]) {
47845002 const tag: freebsd.CrtFile = @enumFromInt(i);
4785 comp.link_task_queue.startPrelinkItem();
4786 comp.link_task_wait_group.spawnManager(buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });
5003 prelink_group.async(io, buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });
47875004 }
47885005 }
47895006
47905007 for (0..@typeInfo(netbsd.CrtFile).@"enum".fields.len) |i| {
47915008 if (comp.queued_jobs.netbsd_crt_file[i]) {
47925009 const tag: netbsd.CrtFile = @enumFromInt(i);
4793 comp.link_task_queue.startPrelinkItem();
4794 comp.link_task_wait_group.spawnManager(buildNetBSDCrtFile, .{ comp, tag, main_progress_node });
5010 prelink_group.async(io, buildNetBSDCrtFile, .{ comp, tag, main_progress_node });
47955011 }
47965012 }
47975013
47985014 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {
47995015 if (comp.queued_jobs.wasi_libc_crt_file[i]) {
48005016 const tag: wasi_libc.CrtFile = @enumFromInt(i);
4801 comp.link_task_queue.startPrelinkItem();
4802 comp.link_task_wait_group.spawnManager(buildWasiLibcCrtFile, .{ comp, tag, main_progress_node });
5017 prelink_group.async(io, buildWasiLibcCrtFile, .{ comp, tag, main_progress_node });
48035018 }
48045019 }
48055020
48065021 for (0..@typeInfo(mingw.CrtFile).@"enum".fields.len) |i| {
48075022 if (comp.queued_jobs.mingw_crt_file[i]) {
48085023 const tag: mingw.CrtFile = @enumFromInt(i);
4809 comp.link_task_queue.startPrelinkItem();
4810 comp.link_task_wait_group.spawnManager(buildMingwCrtFile, .{ comp, tag, main_progress_node });
4811 }
4812 }
4813
4814 {
4815 const astgen_frame = tracy.namedFrame("astgen");
4816 defer astgen_frame.end();
4817
4818 const zir_prog_node = main_progress_node.start("AST Lowering", 0);
4819 defer zir_prog_node.end();
4820
4821 var timer = comp.startTimer();
4822 defer if (timer.finish()) |ns| {
4823 comp.mutex.lock();
4824 defer comp.mutex.unlock();
4825 comp.time_report.?.stats.real_ns_files = ns;
4826 };
4827
4828 var astgen_wait_group: WaitGroup = .{};
4829 defer astgen_wait_group.wait();
4830
4831 if (comp.zcu) |zcu| {
4832 const gpa = zcu.gpa;
4833
4834 // We cannot reference `zcu.import_table` after we spawn any `workerUpdateFile` jobs,
4835 // because on single-threaded targets the worker will be run eagerly, meaning the
4836 // `import_table` could be mutated, and not even holding `comp.mutex` will save us. So,
4837 // build up a list of the files to update *before* we spawn any jobs.
4838 var astgen_work_items: std.MultiArrayList(struct {
4839 file_index: Zcu.File.Index,
4840 file: *Zcu.File,
4841 }) = .empty;
4842 defer astgen_work_items.deinit(gpa);
4843 // Not every item in `import_table` will need updating, because some are builtin.zig
4844 // files. However, most will, so let's just reserve sufficient capacity upfront.
4845 try astgen_work_items.ensureTotalCapacity(gpa, zcu.import_table.count());
4846 for (zcu.import_table.keys()) |file_index| {
4847 const file = zcu.fileByIndex(file_index);
4848 if (file.is_builtin) {
4849 // This is a `builtin.zig`, so updating is redundant. However, we want to make
4850 // sure the file contents are still correct on disk, since it can improve the
4851 // debugging experience better. That job only needs `file`, so we can kick it
4852 // off right now.
4853 comp.thread_pool.spawnWg(&astgen_wait_group, workerUpdateBuiltinFile, .{ comp, file });
4854 continue;
4855 }
4856 astgen_work_items.appendAssumeCapacity(.{
4857 .file_index = file_index,
4858 .file = file,
4859 });
4860 }
4861
4862 // Now that we're not going to touch `zcu.import_table` again, we can spawn `workerUpdateFile` jobs.
4863 for (astgen_work_items.items(.file_index), astgen_work_items.items(.file)) |file_index, file| {
4864 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateFile, .{
4865 comp, file, file_index, zir_prog_node, &astgen_wait_group,
4866 });
4867 }
4868
4869 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
4870 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
4871 // `@embedFile` can't trigger analysis of a new `@embedFile`!
4872 for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {
4873 const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
4874 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateEmbedFile, .{
4875 comp, ef_index, ef,
4876 });
4877 }
4878 }
4879
4880 while (comp.c_object_work_queue.popFront()) |c_object| {
4881 comp.link_task_queue.startPrelinkItem();
4882 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateCObject, .{
4883 comp, c_object, main_progress_node,
4884 });
4885 }
4886
4887 while (comp.win32_resource_work_queue.popFront()) |win32_resource| {
4888 comp.link_task_queue.startPrelinkItem();
4889 comp.thread_pool.spawnWg(&comp.link_task_wait_group, workerUpdateWin32Resource, .{
4890 comp, win32_resource, main_progress_node,
4891 });
4892 }
4893 }
4894
4895 if (comp.zcu) |zcu| {
4896 const pt: Zcu.PerThread = .activate(zcu, .main);
4897 defer pt.deactivate();
4898
4899 const gpa = zcu.gpa;
4900
4901 // On an incremental update, a source file might become "dead", in that all imports of
4902 // the file were removed. This could even change what module the file belongs to! As such,
4903 // we do a traversal over the files, to figure out which ones are alive and the modules
4904 // they belong to.
4905 const any_fatal_files = try pt.computeAliveFiles();
4906
4907 // If the cache mode is `whole`, add every alive source file to the manifest.
4908 switch (comp.cache_use) {
4909 .whole => |whole| if (whole.cache_manifest) |man| {
4910 for (zcu.alive_files.keys()) |file_index| {
4911 const file = zcu.fileByIndex(file_index);
4912
4913 switch (file.status) {
4914 .never_loaded => unreachable, // AstGen tried to load it
4915 .retryable_failure => continue, // the file cannot be read; this is a guaranteed error
4916 .astgen_failure, .success => {}, // the file was read successfully
4917 }
4918
4919 const path = try file.path.toAbsolute(comp.dirs, gpa);
4920 defer gpa.free(path);
4921
4922 const result = res: {
4923 whole.cache_manifest_mutex.lock();
4924 defer whole.cache_manifest_mutex.unlock();
4925 if (file.source) |source| {
4926 break :res man.addFilePostContents(path, source, file.stat);
4927 } else {
4928 break :res man.addFilePost(path);
4929 }
4930 };
4931 result catch |err| switch (err) {
4932 error.OutOfMemory => |e| return e,
4933 else => {
4934 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
4935 continue;
4936 },
4937 };
4938 }
4939 },
4940 .none, .incremental => {},
4941 }
4942
4943 if (any_fatal_files or
4944 zcu.multi_module_err != null or
4945 zcu.failed_imports.items.len > 0 or
4946 comp.alloc_failure_occurred)
4947 {
4948 // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
4949 // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
4950 // However, this means our analysis data is invalid, so we want to omit all analysis errors.
4951 zcu.skip_analysis_this_update = true;
4952 return;
4953 }
4954
4955 if (comp.time_report) |*tr| {
4956 tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());
4957 }
4958
4959 if (comp.config.incremental) {
4960 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
4961 defer update_zir_refs_node.end();
4962 try pt.updateZirRefs();
4963 }
4964 try zcu.flushRetryableFailures();
4965
4966 // It's analysis time! Queue up our initial analysis.
4967 for (zcu.analysisRoots()) |mod| {
4968 try comp.queueJob(.{ .analyze_mod = mod });
4969 }
4970
4971 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
4972 if (comp.bin_file != null) {
4973 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
5024 prelink_group.async(io, buildMingwCrtFile, .{ comp, tag, main_progress_node });
49745025 }
4975 // We increment `pending_codegen_jobs` so that it doesn't reach 0 until after analysis finishes.
4976 // That prevents the "Code Generation" node from constantly disappearing and reappearing when
4977 // we're probably going to analyze more functions at some point.
4978 assert(zcu.pending_codegen_jobs.swap(1, .monotonic) == 0); // don't let this become 0 until analysis finishes
49795026 }
4980 // When analysis ends, delete the progress nodes for "Semantic Analysis" and possibly "Code Generation".
4981 defer if (comp.zcu) |zcu| {
4982 zcu.sema_prog_node.end();
4983 zcu.sema_prog_node = .none;
4984 if (zcu.pending_codegen_jobs.rmw(.Sub, 1, .monotonic) == 1) {
4985 // Decremented to 0, so all done.
4986 zcu.codegen_prog_node.end();
4987 zcu.codegen_prog_node = .none;
4988 }
4989 };
4990
4991 // We aren't going to queue any more prelink tasks.
4992 comp.link_task_queue.finishPrelinkItem(comp);
49935027
4994 if (!comp.separateCodegenThreadOk()) {
4995 // Waits until all input files have been parsed.
4996 comp.link_task_wait_group.wait();
4997 comp.link_task_wait_group.reset();
4998 std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{});
5028 while (comp.c_object_work_queue.popFront()) |c_object| {
5029 prelink_group.async(io, workerUpdateCObject, .{
5030 comp, c_object, main_progress_node,
5031 });
49995032 }
50005033
5001 if (comp.zcu != null) {
5002 // Start the timer for the "decls" part of the pipeline (Sema, CodeGen, link).
5003 decl_work_timer = comp.startTimer();
5034 while (comp.win32_resource_work_queue.popFront()) |win32_resource| {
5035 prelink_group.async(io, workerUpdateWin32Resource, .{
5036 comp, win32_resource, main_progress_node,
5037 });
50045038 }
50055039
5006 work: while (true) {
5007 for (&comp.work_queues) |*work_queue| if (work_queue.popFront()) |job| {
5008 try processOneJob(@intFromEnum(Zcu.PerThread.Id.main), comp, job);
5009 continue :work;
5010 };
5011 if (comp.zcu) |zcu| {
5012 // If there's no work queued, check if there's anything outdated
5013 // which we need to work on, and queue it if so.
5014 if (try zcu.findOutdatedToAnalyze()) |outdated| {
5015 try comp.queueJob(switch (outdated.unwrap()) {
5016 .func => |f| .{ .analyze_func = f },
5017 .memoized_state,
5018 .@"comptime",
5019 .nav_ty,
5020 .nav_val,
5021 .type,
5022 => .{ .analyze_comptime_unit = outdated },
5023 });
5024 continue;
5025 }
5026 zcu.sema_prog_node.end();
5027 zcu.sema_prog_node = .none;
5028 }
5029 break;
5030 }
5040 prelink_group.wait(io);
5041 comp.link_queue.finishPrelinkQueue(comp);
50315042}
50325043
50335044const JobError = Allocator.Error || Io.Cancelable;
......@@ -5040,58 +5051,38 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
50405051 for (jobs) |job| try comp.queueJob(job);
50415052}
50425053
5043fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
5054fn processOneJob(
5055 tid: usize,
5056 comp: *Compilation,
5057 job: Job,
5058) JobError!void {
50445059 switch (job) {
50455060 .codegen_func => |func| {
50465061 const zcu = comp.zcu.?;
50475062 const gpa = zcu.gpa;
5048 var air = func.air;
5049 errdefer {
5050 zcu.codegen_prog_node.completeOne();
5051 comp.link_prog_node.completeOne();
5052 air.deinit(gpa);
5053 }
5054 if (!air.typesFullyResolved(zcu)) {
5063 var owned_air: ?Air = func.air;
5064 defer if (owned_air) |*air| air.deinit(gpa);
5065
5066 if (!owned_air.?.typesFullyResolved(zcu)) {
50555067 // Type resolution failed in a way which affects this function. This is a transitive
50565068 // failure, but it doesn't need recording, because this function semantically depends
50575069 // on the failed type, so when it is changed the function is updated.
50585070 zcu.codegen_prog_node.completeOne();
50595071 comp.link_prog_node.completeOne();
5060 air.deinit(gpa);
50615072 return;
50625073 }
5063 const shared_mir = try gpa.create(link.ZcuTask.LinkFunc.SharedMir);
5064 shared_mir.* = .{
5065 .status = .init(.pending),
5066 .value = undefined,
5067 };
5068 assert(zcu.pending_codegen_jobs.rmw(.Add, 1, .monotonic) > 0); // the "Code Generation" node hasn't been ended
5069 // This value is used as a heuristic to avoid queueing too much AIR/MIR at once (hence
5070 // using a lot of memory). If this would cause too many AIR bytes to be in-flight, we
5071 // will block on the `dispatchZcuLinkTask` call below.
5072 const air_bytes: u32 = @intCast(air.instructions.len * 5 + air.extra.items.len * 4);
5073 if (comp.separateCodegenThreadOk()) {
5074 // `workerZcuCodegen` takes ownership of `air`.
5075 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, workerZcuCodegen, .{ comp, func.func, air, shared_mir });
5076 comp.dispatchZcuLinkTask(tid, .{ .link_func = .{
5077 .func = func.func,
5078 .mir = shared_mir,
5079 .air_bytes = air_bytes,
5080 } });
5081 } else {
5082 {
5083 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
5084 defer pt.deactivate();
5085 pt.runCodegen(func.func, &air, shared_mir);
5086 }
5087 assert(shared_mir.status.load(.monotonic) != .pending);
5088 comp.dispatchZcuLinkTask(tid, .{ .link_func = .{
5089 .func = func.func,
5090 .mir = shared_mir,
5091 .air_bytes = air_bytes,
5092 } });
5093 air.deinit(gpa);
5094 }
5074
5075 // Some linkers need to refer to the AIR. In that case, the linker is not running
5076 // concurrently, so we'll just keep ownership of the AIR for ourselves instead of
5077 // letting the codegen job destroy it.
5078 const disown_air = zcu.backendSupportsFeature(.separate_thread);
5079
5080 // Begin the codegen task. If the codegen/link queue is backed up, this might
5081 // block until the linker is able to process some tasks.
5082 const codegen_task = try zcu.codegen_task_pool.start(zcu, func.func, &owned_air.?, disown_air);
5083 if (disown_air) owned_air = null;
5084
5085 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_func = codegen_task });
50955086 },
50965087 .link_nav => |nav_index| {
50975088 const zcu = comp.zcu.?;
......@@ -5111,7 +5102,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
51115102 comp.link_prog_node.completeOne();
51125103 return;
51135104 }
5114 comp.dispatchZcuLinkTask(tid, .{ .link_nav = nav_index });
5105 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index });
51155106 },
51165107 .link_type => |ty| {
51175108 const zcu = comp.zcu.?;
......@@ -5123,10 +5114,10 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
51235114 comp.link_prog_node.completeOne();
51245115 return;
51255116 }
5126 comp.dispatchZcuLinkTask(tid, .{ .link_type = ty });
5117 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty });
51275118 },
5128 .update_line_number => |ti| {
5129 comp.dispatchZcuLinkTask(tid, .{ .update_line_number = ti });
5119 .update_line_number => |tracked_inst| {
5120 try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst });
51305121 },
51315122 .analyze_func => |func| {
51325123 const named_frame = tracy.namedFrame("analyze_func");
......@@ -5220,12 +5211,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
52205211 }
52215212}
52225213
5223pub fn separateCodegenThreadOk(comp: *const Compilation) bool {
5224 if (InternPool.single_threaded) return false;
5225 const zcu = comp.zcu orelse return true;
5226 return zcu.backendSupportsFeature(.separate_thread);
5227}
5228
52295214fn createDepFile(
52305215 comp: *Compilation,
52315216 depfile: []const u8,
......@@ -5480,6 +5465,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
54805465
54815466 var sub_create_diag: CreateDiagnostic = undefined;
54825467 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{
5468 .thread_limit = comp.thread_limit,
54835469 .dirs = dirs,
54845470 .self_exe_path = comp.self_exe_path,
54855471 .config = config,
......@@ -5487,7 +5473,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
54875473 .entry = .disabled,
54885474 .cache_mode = .whole,
54895475 .root_name = root_name,
5490 .thread_pool = comp.thread_pool,
54915476 .libc_installation = comp.libc_installation,
54925477 .emit_bin = .yes_cache,
54935478 .verbose_cc = comp.verbose_cc,
......@@ -5541,13 +5526,15 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
55415526}
55425527
55435528fn workerUpdateFile(
5544 tid: usize,
55455529 comp: *Compilation,
55465530 file: *Zcu.File,
55475531 file_index: Zcu.File.Index,
55485532 prog_node: std.Progress.Node,
5549 wg: *WaitGroup,
5533 group: *Io.Group,
55505534) void {
5535 const tid = Compilation.getTid();
5536 const io = comp.io;
5537
55515538 const child_prog_node = prog_node.start(fs.path.basename(file.path.sub_path), 0);
55525539 defer child_prog_node.end();
55535540
......@@ -5556,8 +5543,8 @@ fn workerUpdateFile(
55565543 pt.updateFile(file_index, file) catch |err| {
55575544 pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
55585545 error.OutOfMemory => {
5559 comp.mutex.lock();
5560 defer comp.mutex.unlock();
5546 comp.mutex.lockUncancelable(io);
5547 defer comp.mutex.unlock(io);
55615548 comp.setAllocFailure();
55625549 },
55635550 };
......@@ -5587,14 +5574,14 @@ fn workerUpdateFile(
55875574 if (pt.discoverImport(file.path, import_path)) |res| switch (res) {
55885575 .module, .existing_file => {},
55895576 .new_file => |new| {
5590 comp.thread_pool.spawnWgId(wg, workerUpdateFile, .{
5591 comp, new.file, new.index, prog_node, wg,
5577 group.async(io, workerUpdateFile, .{
5578 comp, new.file, new.index, prog_node, group,
55925579 });
55935580 },
55945581 } else |err| switch (err) {
55955582 error.OutOfMemory => {
5596 comp.mutex.lock();
5597 defer comp.mutex.unlock();
5583 comp.mutex.lockUncancelable(io);
5584 defer comp.mutex.unlock(io);
55985585 comp.setAllocFailure();
55995586 },
56005587 }
......@@ -5610,17 +5597,20 @@ fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void {
56105597 );
56115598}
56125599
5613fn workerUpdateEmbedFile(tid: usize, comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {
5600fn workerUpdateEmbedFile(comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {
5601 const tid = Compilation.getTid();
5602 const io = comp.io;
56145603 comp.detectEmbedFileUpdate(@enumFromInt(tid), ef_index, ef) catch |err| switch (err) {
56155604 error.OutOfMemory => {
5616 comp.mutex.lock();
5617 defer comp.mutex.unlock();
5605 comp.mutex.lockUncancelable(io);
5606 defer comp.mutex.unlock(io);
56185607 comp.setAllocFailure();
56195608 },
56205609 };
56215610}
56225611
56235612fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) !void {
5613 const io = comp.io;
56245614 const zcu = comp.zcu.?;
56255615 const pt: Zcu.PerThread = .activate(zcu, tid);
56265616 defer pt.deactivate();
......@@ -5633,8 +5623,8 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc
56335623 if (ef.val != .none and ef.val == old_val) return; // success, value unchanged
56345624 if (ef.val == .none and old_val == .none and ef.err == old_err) return; // failure, error unchanged
56355625
5636 comp.mutex.lock();
5637 defer comp.mutex.unlock();
5626 comp.mutex.lockUncancelable(io);
5627 defer comp.mutex.unlock(io);
56385628
56395629 try zcu.markDependeeOutdated(.not_marked_po, .{ .embed_file = ef_index });
56405630}
......@@ -5777,8 +5767,8 @@ pub fn translateC(
57775767
57785768 switch (comp.cache_use) {
57795769 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
5780 whole.cache_manifest_mutex.lock();
5781 defer whole.cache_manifest_mutex.unlock();
5770 try whole.cache_manifest_mutex.lock(io);
5771 defer whole.cache_manifest_mutex.unlock(io);
57825772 try whole_cache_manifest.addDepFilePost(cache_tmp_dir, dep_basename);
57835773 },
57845774 .incremental, .none => {},
......@@ -5879,7 +5869,6 @@ fn workerUpdateCObject(
58795869 c_object: *CObject,
58805870 progress_node: std.Progress.Node,
58815871) void {
5882 defer comp.link_task_queue.finishPrelinkItem(comp);
58835872 comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
58845873 error.AnalysisFail => return,
58855874 else => {
......@@ -5897,7 +5886,6 @@ fn workerUpdateWin32Resource(
58975886 win32_resource: *Win32Resource,
58985887 progress_node: std.Progress.Node,
58995888) void {
5900 defer comp.link_task_queue.finishPrelinkItem(comp);
59015889 comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) {
59025890 error.AnalysisFail => return,
59035891 else => {
......@@ -5915,21 +5903,6 @@ pub const RtOptions = struct {
59155903 allow_lto: bool = true,
59165904};
59175905
5918fn workerZcuCodegen(
5919 tid: usize,
5920 comp: *Compilation,
5921 func_index: InternPool.Index,
5922 orig_air: Air,
5923 out: *link.ZcuTask.LinkFunc.SharedMir,
5924) void {
5925 var air = orig_air;
5926 // We own `air` now, so we are responsbile for freeing it.
5927 defer air.deinit(comp.gpa);
5928 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
5929 defer pt.deactivate();
5930 pt.runCodegen(func_index, &air, out);
5931}
5932
59335906fn buildRt(
59345907 comp: *Compilation,
59355908 root_source_name: []const u8,
......@@ -5941,7 +5914,6 @@ fn buildRt(
59415914 options: RtOptions,
59425915 out: *?CrtFile,
59435916) void {
5944 defer comp.link_task_queue.finishPrelinkItem(comp);
59455917 comp.buildOutputFromZig(
59465918 root_source_name,
59475919 root_name,
......@@ -5960,7 +5932,6 @@ fn buildRt(
59605932}
59615933
59625934fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.Progress.Node) void {
5963 defer comp.link_task_queue.finishPrelinkItem(comp);
59645935 if (musl.buildCrtFile(comp, crt_file, prog_node)) |_| {
59655936 comp.queued_jobs.musl_crt_file[@intFromEnum(crt_file)] = false;
59665937 } else |err| switch (err) {
......@@ -5972,7 +5943,6 @@ fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.P
59725943}
59735944
59745945fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std.Progress.Node) void {
5975 defer comp.link_task_queue.finishPrelinkItem(comp);
59765946 if (glibc.buildCrtFile(comp, crt_file, prog_node)) |_| {
59775947 comp.queued_jobs.glibc_crt_file[@intFromEnum(crt_file)] = false;
59785948 } else |err| switch (err) {
......@@ -5984,7 +5954,6 @@ fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std
59845954}
59855955
59865956fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
5987 defer comp.link_task_queue.finishPrelinkItem(comp);
59885957 if (glibc.buildSharedObjects(comp, prog_node)) |_| {
59895958 // The job should no longer be queued up since it succeeded.
59905959 comp.queued_jobs.glibc_shared_objects = false;
......@@ -5995,7 +5964,6 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi
59955964}
59965965
59975966fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {
5998 defer comp.link_task_queue.finishPrelinkItem(comp);
59995967 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
60005968 comp.queued_jobs.freebsd_crt_file[@intFromEnum(crt_file)] = false;
60015969 } else |err| switch (err) {
......@@ -6007,7 +5975,6 @@ fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node:
60075975}
60085976
60095977fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
6010 defer comp.link_task_queue.finishPrelinkItem(comp);
60115978 if (freebsd.buildSharedObjects(comp, prog_node)) |_| {
60125979 // The job should no longer be queued up since it succeeded.
60135980 comp.queued_jobs.freebsd_shared_objects = false;
......@@ -6020,7 +5987,6 @@ fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) v
60205987}
60215988
60225989fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: std.Progress.Node) void {
6023 defer comp.link_task_queue.finishPrelinkItem(comp);
60245990 if (netbsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
60255991 comp.queued_jobs.netbsd_crt_file[@intFromEnum(crt_file)] = false;
60265992 } else |err| switch (err) {
......@@ -6032,7 +5998,6 @@ fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: s
60325998}
60335999
60346000fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
6035 defer comp.link_task_queue.finishPrelinkItem(comp);
60366001 if (netbsd.buildSharedObjects(comp, prog_node)) |_| {
60376002 // The job should no longer be queued up since it succeeded.
60386003 comp.queued_jobs.netbsd_shared_objects = false;
......@@ -6045,7 +6010,6 @@ fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) vo
60456010}
60466011
60476012fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {
6048 defer comp.link_task_queue.finishPrelinkItem(comp);
60496013 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {
60506014 comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;
60516015 } else |err| switch (err) {
......@@ -6057,7 +6021,6 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std
60576021}
60586022
60596023fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void {
6060 defer comp.link_task_queue.finishPrelinkItem(comp);
60616024 if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| {
60626025 comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false;
60636026 } else |err| switch (err) {
......@@ -6069,7 +6032,6 @@ fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_no
60696032}
60706033
60716034fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {
6072 defer comp.link_task_queue.finishPrelinkItem(comp);
60736035 if (libunwind.buildStaticLib(comp, prog_node)) |_| {
60746036 comp.queued_jobs.libunwind = false;
60756037 } else |err| switch (err) {
......@@ -6079,7 +6041,6 @@ fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void {
60796041}
60806042
60816043fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {
6082 defer comp.link_task_queue.finishPrelinkItem(comp);
60836044 if (libcxx.buildLibCxx(comp, prog_node)) |_| {
60846045 comp.queued_jobs.libcxx = false;
60856046 } else |err| switch (err) {
......@@ -6089,7 +6050,6 @@ fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void {
60896050}
60906051
60916052fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {
6092 defer comp.link_task_queue.finishPrelinkItem(comp);
60936053 if (libcxx.buildLibCxxAbi(comp, prog_node)) |_| {
60946054 comp.queued_jobs.libcxxabi = false;
60956055 } else |err| switch (err) {
......@@ -6099,7 +6059,6 @@ fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void {
60996059}
61006060
61016061fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {
6102 defer comp.link_task_queue.finishPrelinkItem(comp);
61036062 if (libtsan.buildTsan(comp, prog_node)) |_| {
61046063 comp.queued_jobs.libtsan = false;
61056064 } else |err| switch (err) {
......@@ -6109,7 +6068,6 @@ fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void {
61096068}
61106069
61116070fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void {
6112 defer comp.link_task_queue.finishPrelinkItem(comp);
61136071 comp.buildOutputFromZig(
61146072 "c.zig",
61156073 "zigc",
......@@ -6139,6 +6097,8 @@ fn reportRetryableWin32ResourceError(
61396097 win32_resource: *Win32Resource,
61406098 err: anyerror,
61416099) error{OutOfMemory}!void {
6100 const io = comp.io;
6101
61426102 win32_resource.status = .failure_retryable;
61436103
61446104 var bundle: ErrorBundle.Wip = undefined;
......@@ -6160,8 +6120,8 @@ fn reportRetryableWin32ResourceError(
61606120 });
61616121 const finished_bundle = try bundle.toOwnedBundle("");
61626122 {
6163 comp.mutex.lock();
6164 defer comp.mutex.unlock();
6123 comp.mutex.lockUncancelable(io);
6124 defer comp.mutex.unlock(io);
61656125 try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, finished_bundle);
61666126 }
61676127}
......@@ -6186,8 +6146,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
61866146
61876147 if (c_object.clearStatus(gpa)) {
61886148 // There was previous failure.
6189 comp.mutex.lock();
6190 defer comp.mutex.unlock();
6149 comp.mutex.lockUncancelable(io);
6150 defer comp.mutex.unlock(io);
61916151 // If the failure was OOM, there will not be an entry here, so we do
61926152 // not assert discard.
61936153 _ = comp.failed_c_objects.swapRemove(c_object);
......@@ -6457,8 +6417,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
64576417 switch (comp.cache_use) {
64586418 .whole => |whole| {
64596419 if (whole.cache_manifest) |whole_cache_manifest| {
6460 whole.cache_manifest_mutex.lock();
6461 defer whole.cache_manifest_mutex.unlock();
6420 try whole.cache_manifest_mutex.lock(io);
6421 defer whole.cache_manifest_mutex.unlock(io);
64626422 try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
64636423 }
64646424 },
......@@ -6503,7 +6463,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
65036463 },
65046464 };
65056465
6506 comp.queuePrelinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
6466 try comp.queuePrelinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
65076467}
65086468
65096469fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {
......@@ -6517,6 +6477,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
65176477 const tracy_trace = trace(@src());
65186478 defer tracy_trace.end();
65196479
6480 const io = comp.io;
6481
65206482 const src_path = switch (win32_resource.src) {
65216483 .rc => |rc_src| rc_src.src_path,
65226484 .manifest => |src_path| src_path,
......@@ -6531,8 +6493,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
65316493
65326494 if (win32_resource.clearStatus(comp.gpa)) {
65336495 // There was previous failure.
6534 comp.mutex.lock();
6535 defer comp.mutex.unlock();
6496 comp.mutex.lockUncancelable(io);
6497 defer comp.mutex.unlock(io);
65366498 // If the failure was OOM, there will not be an entry here, so we do
65376499 // not assert discard.
65386500 _ = comp.failed_win32_resources.swapRemove(win32_resource);
......@@ -6706,8 +6668,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
67066668 try man.addFilePost(dep_file_path);
67076669 switch (comp.cache_use) {
67086670 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
6709 whole.cache_manifest_mutex.lock();
6710 defer whole.cache_manifest_mutex.unlock();
6671 try whole.cache_manifest_mutex.lock(io);
6672 defer whole.cache_manifest_mutex.unlock(io);
67116673 try whole_cache_manifest.addFilePost(dep_file_path);
67126674 },
67136675 .incremental, .none => {},
......@@ -7428,8 +7390,9 @@ fn failCObjWithOwnedDiagBundle(
74287390 @branchHint(.cold);
74297391 assert(diag_bundle.diags.len > 0);
74307392 {
7431 comp.mutex.lock();
7432 defer comp.mutex.unlock();
7393 const io = comp.io;
7394 comp.mutex.lockUncancelable(io);
7395 defer comp.mutex.unlock(io);
74337396 {
74347397 errdefer diag_bundle.destroy(comp.gpa);
74357398 try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1);
......@@ -7470,8 +7433,9 @@ fn failWin32ResourceWithOwnedBundle(
74707433) error{ OutOfMemory, AnalysisFail } {
74717434 @branchHint(.cold);
74727435 {
7473 comp.mutex.lock();
7474 defer comp.mutex.unlock();
7436 const io = comp.io;
7437 comp.mutex.lockUncancelable(io);
7438 defer comp.mutex.unlock(io);
74757439 try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, err_bundle);
74767440 }
74777441 win32_resource.status = .failure;
......@@ -7795,9 +7759,9 @@ pub fn lockAndSetMiscFailure(
77957759 comptime format: []const u8,
77967760 args: anytype,
77977761) void {
7798 comp.mutex.lock();
7799 defer comp.mutex.unlock();
7800
7762 const io = comp.io;
7763 comp.mutex.lockUncancelable(io);
7764 defer comp.mutex.unlock(io);
78017765 return setMiscFailure(comp, tag, format, args);
78027766}
78037767
......@@ -7840,8 +7804,8 @@ pub fn updateSubCompilation(
78407804 defer errors.deinit(gpa);
78417805
78427806 if (errors.errorMessageCount() > 0) {
7843 parent_comp.mutex.lock();
7844 defer parent_comp.mutex.unlock();
7807 parent_comp.mutex.lockUncancelable(parent_comp.io);
7808 defer parent_comp.mutex.unlock(parent_comp.io);
78457809 try parent_comp.misc_failures.ensureUnusedCapacity(gpa, 1);
78467810 parent_comp.misc_failures.putAssumeCapacityNoClobber(misc_task, .{
78477811 .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {t} failed", .{misc_task}),
......@@ -7942,6 +7906,7 @@ fn buildOutputFromZig(
79427906
79437907 var sub_create_diag: CreateDiagnostic = undefined;
79447908 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{
7909 .thread_limit = comp.thread_limit,
79457910 .dirs = comp.dirs.withoutLocalCache(),
79467911 .cache_mode = .whole,
79477912 .parent_whole_cache = parent_whole_cache,
......@@ -7949,7 +7914,6 @@ fn buildOutputFromZig(
79497914 .config = config,
79507915 .root_mod = root_mod,
79517916 .root_name = root_name,
7952 .thread_pool = comp.thread_pool,
79537917 .libc_installation = comp.libc_installation,
79547918 .emit_bin = .yes_cache,
79557919 .function_sections = true,
......@@ -7980,7 +7944,7 @@ fn buildOutputFromZig(
79807944 assert(out.* == null);
79817945 out.* = crt_file;
79827946
7983 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
7947 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
79847948}
79857949
79867950pub const CrtFileOptions = struct {
......@@ -8079,13 +8043,13 @@ pub fn build_crt_file(
80798043
80808044 var sub_create_diag: CreateDiagnostic = undefined;
80818045 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{
8046 .thread_limit = comp.thread_limit,
80828047 .dirs = comp.dirs.withoutLocalCache(),
80838048 .self_exe_path = comp.self_exe_path,
80848049 .cache_mode = .whole,
80858050 .config = config,
80868051 .root_mod = root_mod,
80878052 .root_name = root_name,
8088 .thread_pool = comp.thread_pool,
80898053 .libc_installation = comp.libc_installation,
80908054 .emit_bin = .yes_cache,
80918055 .function_sections = options.function_sections orelse false,
......@@ -8114,18 +8078,18 @@ pub fn build_crt_file(
81148078 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
81158079
81168080 const crt_file = try sub_compilation.toCrtFile();
8117 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
8081 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
81188082
81198083 {
8120 comp.mutex.lock();
8121 defer comp.mutex.unlock();
8084 comp.mutex.lockUncancelable(io);
8085 defer comp.mutex.unlock(io);
81228086 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
81238087 comp.crt_files.putAssumeCapacityNoClobber(basename, crt_file);
81248088 }
81258089}
81268090
8127pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void {
8128 comp.queuePrelinkTasks(switch (config.output_mode) {
8091pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) Io.Cancelable!void {
8092 try comp.queuePrelinkTasks(switch (config.output_mode) {
81298093 .Exe => unreachable,
81308094 .Obj => &.{.{ .load_object = path }},
81318095 .Lib => &.{switch (config.link_mode) {
......@@ -8135,33 +8099,10 @@ pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const
81358099 });
81368100}
81378101
8138/// Only valid to call during `update`. Automatically handles queuing up a
8139/// linker worker task if there is not already one.
8140pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) void {
8102/// Only valid to call during `update`.
8103pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) Io.Cancelable!void {
81418104 comp.link_prog_node.increaseEstimatedTotalItems(tasks.len);
8142 comp.link_task_queue.enqueuePrelink(comp, tasks) catch |err| switch (err) {
8143 error.OutOfMemory => return comp.setAllocFailure(),
8144 };
8145}
8146
8147/// The reason for the double-queue here is that the first queue ensures any
8148/// resolve_type_fully tasks are complete before this dispatch function is called.
8149fn dispatchZcuLinkTask(comp: *Compilation, tid: usize, task: link.ZcuTask) void {
8150 if (!comp.separateCodegenThreadOk()) {
8151 assert(tid == 0);
8152 if (task == .link_func) {
8153 assert(task.link_func.mir.status.load(.monotonic) != .pending);
8154 }
8155 link.doZcuTask(comp, tid, task);
8156 task.deinit(comp.zcu.?);
8157 return;
8158 }
8159 comp.link_task_queue.enqueueZcu(comp, task) catch |err| switch (err) {
8160 error.OutOfMemory => {
8161 task.deinit(comp.zcu.?);
8162 comp.setAllocFailure();
8163 },
8164 };
8105 try comp.link_queue.enqueuePrelink(comp, tasks);
81658106}
81668107
81678108pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
......@@ -8251,3 +8192,17 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {
82518192pub fn compilerRtStrip(comp: Compilation) bool {
82528193 return comp.root_mod.strip;
82538194}
8195
8196/// This is a temporary workaround put in place to migrate from `std.Thread.Pool`
8197/// to `std.Io.Threaded` for asynchronous/concurrent work. The eventual solution
8198/// will likely involve significant changes to the `InternPool` implementation.
8199pub fn getTid() usize {
8200 if (my_tid == null) my_tid = next_tid.fetchAdd(1, .monotonic);
8201 return my_tid.?;
8202}
8203pub fn setMainThread() void {
8204 my_tid = 0;
8205}
8206/// TID 0 is reserved for the main thread.
8207var next_tid: std.atomic.Value(usize) = .init(1);
8208threadlocal var my_tid: ?usize = null;
src/IncrementalDebugServer.zig+109-39
......@@ -14,57 +14,122 @@ comptime {
1414}
1515
1616zcu: *Zcu,
17thread: ?std.Thread,
18running: std.atomic.Value(bool),
17future: ?Io.Future(void),
1918/// Held by our owner when an update is in-progress, and held by us when responding to a command.
2019/// So, essentially guards all access to `Compilation`, including `Zcu`.
21mutex: std.Thread.Mutex,
20mutex: std.Io.Mutex,
2221
2322pub fn init(zcu: *Zcu) IncrementalDebugServer {
2423 return .{
2524 .zcu = zcu,
26 .thread = null,
27 .running = .init(true),
28 .mutex = .{},
25 .future = null,
26 .mutex = .init,
2927 };
3028}
3129
3230pub fn deinit(ids: *IncrementalDebugServer) void {
33 if (ids.thread) |t| {
34 ids.running.store(false, .monotonic);
35 t.join();
36 }
31 const io = ids.zcu.comp.io;
32 if (ids.future) |*f| f.cancel(io);
3733}
3834
3935const port = 7623;
4036pub fn spawn(ids: *IncrementalDebugServer) void {
37 const io = ids.zcu.comp.io;
4138 std.debug.print("spawning incremental debug server on port {d}\n", .{port});
42 ids.thread = std.Thread.spawn(.{ .allocator = ids.zcu.comp.arena }, runThread, .{ids}) catch |err|
43 std.process.fatal("failed to spawn incremental debug server: {s}", .{@errorName(err)});
39 ids.future = io.concurrent(runServer, .{ids}) catch |err|
40 std.process.fatal("failed to start incremental debug server: {s}", .{@errorName(err)});
4441}
45fn runThread(ids: *IncrementalDebugServer) void {
46 const gpa = ids.zcu.gpa;
42fn runServer(ids: *IncrementalDebugServer) void {
4743 const io = ids.zcu.comp.io;
4844
49 var cmd_buf: [1024]u8 = undefined;
50 var text_out: std.ArrayList(u8) = .empty;
51 defer text_out.deinit(gpa);
52
53 const addr: std.Io.net.IpAddress = .{ .ip6 = .loopback(port) };
54 var server = addr.listen(io, .{}) catch @panic("IncrementalDebugServer: failed to listen");
45 const addr: Io.net.IpAddress = .{ .ip6 = .loopback(port) };
46 var server = addr.listen(io, .{}) catch |err| switch (err) {
47 error.Canceled => return,
48 else => |e| {
49 log.err("listen failed ({t}); closing server", .{e});
50 return;
51 },
52 };
5553 defer server.deinit(io);
56 var stream = server.accept(io) catch @panic("IncrementalDebugServer: failed to accept");
57 defer stream.close(io);
5854
59 var stream_reader = stream.reader(io, &cmd_buf);
60 var stream_writer = stream.writer(io, &.{});
55 while (true) {
56 var stream = server.accept(io) catch |err| switch (err) {
57 error.Canceled => return,
58 error.ConnectionAborted => {
59 log.warn("client disconnected during accept", .{});
60 continue;
61 },
62 else => |e| {
63 log.err("accept failed ({t})", .{e});
64 return;
65 },
66 };
67 defer stream.close(io);
68 log.info("client '{f}' connected", .{stream.socket.address});
69 var cmd_buf: [1024]u8 = undefined;
70 var reader = stream.reader(io, &cmd_buf);
71 var writer = stream.writer(io, &.{});
72 ids.serveStream(&reader.interface, &writer.interface) catch |orig_err| {
73 const actual_err = switch (orig_err) {
74 error.Canceled,
75 error.OutOfMemory,
76 error.EndOfStream,
77 error.StreamTooLong,
78 => |e| e,
79
80 error.ReadFailed => reader.err.?,
81 error.WriteFailed => writer.err.?,
82 };
83 switch (actual_err) {
84 error.Canceled => return,
85
86 error.OutOfMemory,
87 error.Unexpected,
88 error.SystemResources,
89 error.Timeout,
90 error.NetworkDown,
91 error.NetworkUnreachable,
92 error.HostUnreachable,
93 error.FastOpenAlreadyInProgress,
94 error.ConnectionRefused,
95 error.StreamTooLong,
96 => |e| log.err("failed to serve '{f}' ({t})", .{ stream.socket.address, e }),
97
98 error.EndOfStream,
99 error.ConnectionResetByPeer,
100 => log.info("client '{f}' disconnected", .{stream.socket.address}),
61101
62 while (ids.running.load(.monotonic)) {
63 stream_writer.interface.writeAll("zig> ") catch @panic("IncrementalDebugServer: failed to write");
64 const untrimmed = stream_reader.interface.takeSentinel('\n') catch |err| switch (err) {
65 error.EndOfStream => break,
66 else => @panic("IncrementalDebugServer: failed to read command"),
102 error.AddressFamilyUnsupported,
103 error.SocketUnconnected,
104 error.SocketNotBound,
105 error.AccessDenied,
106 => unreachable,
107 }
67108 };
109 }
110}
111
112fn serveStream(
113 ids: *IncrementalDebugServer,
114 stream_reader: *Io.Reader,
115 stream_writer: *Io.Writer,
116) error{
117 Canceled,
118 OutOfMemory,
119 EndOfStream,
120 StreamTooLong,
121 ReadFailed,
122 WriteFailed,
123}!noreturn {
124 const gpa = ids.zcu.gpa;
125 const io = ids.zcu.comp.io;
126
127 var text_out: std.ArrayList(u8) = .empty;
128 defer text_out.deinit(gpa);
129
130 while (true) {
131 try stream_writer.writeAll("zig> ");
132 const untrimmed = try stream_reader.takeSentinel('\n');
68133 const cmd_and_arg = std.mem.trim(u8, untrimmed, " \t\r\n");
69134 const cmd: []const u8, const arg: []const u8 = if (std.mem.indexOfScalar(u8, cmd_and_arg, ' ')) |i|
70135 .{ cmd_and_arg[0..i], cmd_and_arg[i + 1 ..] }
......@@ -74,18 +139,21 @@ fn runThread(ids: *IncrementalDebugServer) void {
74139 text_out.clearRetainingCapacity();
75140 {
76141 if (!ids.mutex.tryLock()) {
77 stream_writer.interface.writeAll("waiting for in-progress update to finish...\n") catch @panic("IncrementalDebugServer: failed to write");
78 ids.mutex.lock();
142 try stream_writer.writeAll("waiting for in-progress update to finish...\n");
143 try ids.mutex.lock(io);
79144 }
80 defer ids.mutex.unlock();
81 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &text_out);
145 defer ids.mutex.unlock(io);
146 var allocating: Io.Writer.Allocating = .fromArrayList(gpa, &text_out);
82147 defer text_out = allocating.toArrayList();
83 handleCommand(ids.zcu, &allocating.writer, cmd, arg) catch @panic("IncrementalDebugServer: out of memory");
148 handleCommand(ids.zcu, &allocating.writer, cmd, arg) catch |err| switch (err) {
149 error.OutOfMemory,
150 error.WriteFailed,
151 => return error.OutOfMemory,
152 };
84153 }
85 text_out.append(gpa, '\n') catch @panic("IncrementalDebugServer: out of memory");
86 stream_writer.interface.writeAll(text_out.items) catch @panic("IncrementalDebugServer: failed to write");
154 try text_out.append(gpa, '\n');
155 try stream_writer.writeAll(text_out.items);
87156 }
88 std.debug.print("closing incremental debug server\n", .{});
89157}
90158
91159const help_str: []const u8 =
......@@ -123,7 +191,7 @@ const help_str: []const u8 =
123191 \\
124192;
125193
126fn handleCommand(zcu: *Zcu, w: *std.Io.Writer, cmd_str: []const u8, arg_str: []const u8) error{ WriteFailed, OutOfMemory }!void {
194fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const u8) error{ WriteFailed, OutOfMemory }!void {
127195 const ip = &zcu.intern_pool;
128196 if (std.mem.eql(u8, cmd_str, "help")) {
129197 try w.writeAll(help_str);
......@@ -328,7 +396,8 @@ fn printAnalUnit(unit: AnalUnit, buf: *[32]u8) []const u8 {
328396 };
329397 return std.fmt.bufPrint(buf, "{s} {d}", .{ @tagName(unit.unwrap()), idx }) catch unreachable;
330398}
331fn printType(ty: Type, zcu: *const Zcu, w: anytype) !void {
399
400fn printType(ty: Type, zcu: *const Zcu, w: *Io.Writer) Io.Writer.Error!void {
332401 const ip = &zcu.intern_pool;
333402 switch (ip.indexToKey(ty.toIntern())) {
334403 .int_type => |int| try w.print("{c}{d}", .{
......@@ -377,6 +446,7 @@ fn printType(ty: Type, zcu: *const Zcu, w: anytype) !void {
377446const std = @import("std");
378447const Io = std.Io;
379448const Allocator = std.mem.Allocator;
449const log = std.log.scoped(.incremental_debug_server);
380450
381451const Compilation = @import("Compilation.zig");
382452const Zcu = @import("Zcu.zig");
src/InternPool.zig+441-331
......@@ -8,6 +8,7 @@ const assert = std.debug.assert;
88const BigIntConst = std.math.big.int.Const;
99const BigIntMutable = std.math.big.int.Mutable;
1010const Cache = std.Build.Cache;
11const Io = std.Io;
1112const Limb = std.math.big.Limb;
1213const Hash = std.hash.Wyhash;
1314
......@@ -214,6 +215,7 @@ pub const TrackedInst = extern struct {
214215pub fn trackZir(
215216 ip: *InternPool,
216217 gpa: Allocator,
218 io: Io,
217219 tid: Zcu.PerThread.Id,
218220 key: TrackedInst,
219221) Allocator.Error!TrackedInst.Index {
......@@ -235,8 +237,8 @@ pub fn trackZir(
235237 if (entry.hash != hash) continue;
236238 if (std.meta.eql(index.resolveFull(ip) orelse continue, key)) return index;
237239 }
238 shard.mutate.tracked_inst_map.mutex.lock();
239 defer shard.mutate.tracked_inst_map.mutex.unlock();
240 shard.mutate.tracked_inst_map.mutex.lock(io, tid);
241 defer shard.mutate.tracked_inst_map.mutex.unlock(io);
240242 if (map.entries != shard.shared.tracked_inst_map.entries) {
241243 map = shard.shared.tracked_inst_map;
242244 map_mask = map.header().mask();
......@@ -251,7 +253,7 @@ pub fn trackZir(
251253 }
252254 defer shard.mutate.tracked_inst_map.len += 1;
253255 const local = ip.getLocal(tid);
254 const list = local.getMutableTrackedInsts(gpa);
256 const list = local.getMutableTrackedInsts(gpa, io);
255257 try list.ensureUnusedCapacity(1);
256258 const map_header = map.header().*;
257259 if (shard.mutate.tracked_inst_map.len < map_header.capacity * 3 / 5) {
......@@ -317,6 +319,7 @@ pub fn trackZir(
317319pub fn rehashTrackedInsts(
318320 ip: *InternPool,
319321 gpa: Allocator,
322 io: Io,
320323 tid: Zcu.PerThread.Id,
321324) Allocator.Error!void {
322325 assert(tid == .main); // we shouldn't have any other threads active right now
......@@ -333,7 +336,7 @@ pub fn rehashTrackedInsts(
333336 for (ip.locals) |*local| {
334337 // `getMutableTrackedInsts` is okay only because no other thread is currently active.
335338 // We need the `mutate` for the len.
336 for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0")) |tracked_inst| {
339 for (local.getMutableTrackedInsts(gpa, io).viewAllowEmpty().items(.@"0")) |tracked_inst| {
337340 if (tracked_inst.inst == .lost) continue; // we can ignore this one!
338341 const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst));
339342 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
......@@ -379,7 +382,7 @@ pub fn rehashTrackedInsts(
379382 for (ip.locals, 0..) |*local, local_tid| {
380383 // `getMutableTrackedInsts` is okay only because no other thread is currently active.
381384 // We need the `mutate` for the len.
382 for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0"), 0..) |tracked_inst, local_inst_index| {
385 for (local.getMutableTrackedInsts(gpa, io).viewAllowEmpty().items(.@"0"), 0..) |tracked_inst, local_inst_index| {
383386 if (tracked_inst.inst == .lost) continue; // we can ignore this one!
384387 const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst));
385388 const hash: u32 = @truncate(full_hash >> 32);
......@@ -1113,11 +1116,11 @@ const Local = struct {
11131116 const Namespaces = List(struct { *[1 << namespaces_bucket_width]Zcu.Namespace });
11141117
11151118 const ListMutate = struct {
1116 mutex: std.Thread.Mutex,
1119 mutex: Io.Mutex,
11171120 len: u32,
11181121
11191122 const empty: ListMutate = .{
1120 .mutex = .{},
1123 .mutex = .init,
11211124 .len = 0,
11221125 };
11231126 };
......@@ -1144,6 +1147,7 @@ const Local = struct {
11441147 const ListSelf = @This();
11451148 const Mutable = struct {
11461149 gpa: Allocator,
1150 io: Io,
11471151 arena: *std.heap.ArenaAllocator.State,
11481152 mutate: *ListMutate,
11491153 list: *ListSelf,
......@@ -1296,6 +1300,7 @@ const Local = struct {
12961300 }
12971301
12981302 fn setCapacity(mutable: Mutable, capacity: u32) Allocator.Error!void {
1303 const io = mutable.io;
12991304 var arena = mutable.arena.promote(mutable.gpa);
13001305 defer mutable.arena.* = arena.state;
13011306 const buf = try arena.allocator().alignedAlloc(
......@@ -1313,8 +1318,8 @@ const Local = struct {
13131318 const new_slice = new_list.view().slice();
13141319 inline for (fields) |field| @memcpy(new_slice.items(field)[0..len], old_slice.items(field)[0..len]);
13151320 }
1316 mutable.mutate.mutex.lock();
1317 defer mutable.mutate.mutex.unlock();
1321 mutable.mutate.mutex.lockUncancelable(io);
1322 defer mutable.mutate.mutex.unlock(io);
13181323 mutable.list.release(new_list);
13191324 }
13201325
......@@ -1375,18 +1380,20 @@ const Local = struct {
13751380 };
13761381 }
13771382
1378 pub fn getMutableItems(local: *Local, gpa: Allocator) List(Item).Mutable {
1383 pub fn getMutableItems(local: *Local, gpa: Allocator, io: Io) List(Item).Mutable {
13791384 return .{
13801385 .gpa = gpa,
1386 .io = io,
13811387 .arena = &local.mutate.arena,
13821388 .mutate = &local.mutate.items,
13831389 .list = &local.shared.items,
13841390 };
13851391 }
13861392
1387 pub fn getMutableExtra(local: *Local, gpa: Allocator) Extra.Mutable {
1393 pub fn getMutableExtra(local: *Local, gpa: Allocator, io: Io) Extra.Mutable {
13881394 return .{
13891395 .gpa = gpa,
1396 .io = io,
13901397 .arena = &local.mutate.arena,
13911398 .mutate = &local.mutate.extra,
13921399 .list = &local.shared.extra,
......@@ -1397,11 +1404,12 @@ const Local = struct {
13971404 /// On 64-bit systems, this array is used for big integers and associated metadata.
13981405 /// Use the helper methods instead of accessing this directly in order to not
13991406 /// violate the above mechanism.
1400 pub fn getMutableLimbs(local: *Local, gpa: Allocator) Limbs.Mutable {
1407 pub fn getMutableLimbs(local: *Local, gpa: Allocator, io: Io) Limbs.Mutable {
14011408 return switch (@sizeOf(Limb)) {
1402 @sizeOf(u32) => local.getMutableExtra(gpa),
1409 @sizeOf(u32) => local.getMutableExtra(gpa, io),
14031410 @sizeOf(u64) => .{
14041411 .gpa = gpa,
1412 .io = io,
14051413 .arena = &local.mutate.arena,
14061414 .mutate = &local.mutate.limbs,
14071415 .list = &local.shared.limbs,
......@@ -1411,9 +1419,10 @@ const Local = struct {
14111419 }
14121420
14131421 /// A list of offsets into `string_bytes` for each string.
1414 pub fn getMutableStrings(local: *Local, gpa: Allocator) Strings.Mutable {
1422 pub fn getMutableStrings(local: *Local, gpa: Allocator, io: Io) Strings.Mutable {
14151423 return .{
14161424 .gpa = gpa,
1425 .io = io,
14171426 .arena = &local.mutate.arena,
14181427 .mutate = &local.mutate.strings,
14191428 .list = &local.shared.strings,
......@@ -1425,9 +1434,10 @@ const Local = struct {
14251434 /// is referencing the data here whether they want to store both index and length,
14261435 /// thus allowing null bytes, or store only index, and use null-termination. The
14271436 /// `strings_bytes` array is agnostic to either usage.
1428 pub fn getMutableStringBytes(local: *Local, gpa: Allocator) StringBytes.Mutable {
1437 pub fn getMutableStringBytes(local: *Local, gpa: Allocator, io: Io) StringBytes.Mutable {
14291438 return .{
14301439 .gpa = gpa,
1440 .io = io,
14311441 .arena = &local.mutate.arena,
14321442 .mutate = &local.mutate.string_bytes,
14331443 .list = &local.shared.string_bytes,
......@@ -1436,9 +1446,10 @@ const Local = struct {
14361446
14371447 /// An index into `tracked_insts` gives a reference to a single ZIR instruction which
14381448 /// persists across incremental updates.
1439 pub fn getMutableTrackedInsts(local: *Local, gpa: Allocator) TrackedInsts.Mutable {
1449 pub fn getMutableTrackedInsts(local: *Local, gpa: Allocator, io: Io) TrackedInsts.Mutable {
14401450 return .{
14411451 .gpa = gpa,
1452 .io = io,
14421453 .arena = &local.mutate.arena,
14431454 .mutate = &local.mutate.tracked_insts,
14441455 .list = &local.shared.tracked_insts,
......@@ -1452,9 +1463,10 @@ const Local = struct {
14521463 ///
14531464 /// Key is the hash of the path to this file, used to store
14541465 /// `InternPool.TrackedInst`.
1455 pub fn getMutableFiles(local: *Local, gpa: Allocator) List(File).Mutable {
1466 pub fn getMutableFiles(local: *Local, gpa: Allocator, io: Io) List(File).Mutable {
14561467 return .{
14571468 .gpa = gpa,
1469 .io = io,
14581470 .arena = &local.mutate.arena,
14591471 .mutate = &local.mutate.files,
14601472 .list = &local.shared.files,
......@@ -1466,27 +1478,30 @@ const Local = struct {
14661478 /// field names and values directly, relying on one of these maps, stored separately,
14671479 /// to provide lookup.
14681480 /// These are not serialized; it is computed upon deserialization.
1469 pub fn getMutableMaps(local: *Local, gpa: Allocator) Maps.Mutable {
1481 pub fn getMutableMaps(local: *Local, gpa: Allocator, io: Io) Maps.Mutable {
14701482 return .{
14711483 .gpa = gpa,
1484 .io = io,
14721485 .arena = &local.mutate.arena,
14731486 .mutate = &local.mutate.maps,
14741487 .list = &local.shared.maps,
14751488 };
14761489 }
14771490
1478 pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable {
1491 pub fn getMutableNavs(local: *Local, gpa: Allocator, io: Io) Navs.Mutable {
14791492 return .{
14801493 .gpa = gpa,
1494 .io = io,
14811495 .arena = &local.mutate.arena,
14821496 .mutate = &local.mutate.navs,
14831497 .list = &local.shared.navs,
14841498 };
14851499 }
14861500
1487 pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator) ComptimeUnits.Mutable {
1501 pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator, io: Io) ComptimeUnits.Mutable {
14881502 return .{
14891503 .gpa = gpa,
1504 .io = io,
14901505 .arena = &local.mutate.arena,
14911506 .mutate = &local.mutate.comptime_units,
14921507 .list = &local.shared.comptime_units,
......@@ -1503,9 +1518,10 @@ const Local = struct {
15031518 /// serialization trivial.
15041519 /// * It provides a unique integer to be used for anonymous symbol names, avoiding
15051520 /// multi-threaded contention on an atomic counter.
1506 pub fn getMutableNamespaces(local: *Local, gpa: Allocator) Namespaces.Mutable {
1521 pub fn getMutableNamespaces(local: *Local, gpa: Allocator, io: Io) Namespaces.Mutable {
15071522 return .{
15081523 .gpa = gpa,
1524 .io = io,
15091525 .arena = &local.mutate.arena,
15101526 .mutate = &local.mutate.namespaces.buckets_list,
15111527 .list = &local.shared.namespaces,
......@@ -1535,11 +1551,63 @@ const Shard = struct {
15351551 },
15361552
15371553 const Mutate = struct {
1538 mutex: std.Thread.Mutex.Recursive,
1554 /// This mutex needs to be recursive because `getFuncDeclIes` interns multiple things at
1555 /// once (the function, its IES, the corresponding error union, and the resulting function
1556 /// type), so calls `getOrPutKeyEnsuringAdditionalCapacity` multiple times. Each of these
1557 /// calls acquires a lock which will only be released when the whole operation is finalized,
1558 /// and these different items could be in the same shard, in which case that shard's lock
1559 /// will be acquired multiple times.
1560 mutex: RecursiveMutex,
15391561 len: u32,
15401562
1563 const RecursiveMutex = struct {
1564 const OptionalTid = if (single_threaded) enum(u8) {
1565 null,
1566 main,
1567 fn unwrap(ot: OptionalTid) ?Zcu.PerThread.Id {
1568 return switch (ot) {
1569 .null => null,
1570 .main => .main,
1571 };
1572 }
1573 fn wrap(tid: Zcu.PerThread.Id) OptionalTid {
1574 comptime assert(tid == .main);
1575 return .main;
1576 }
1577 } else packed struct(u8) {
1578 non_null: bool,
1579 value: Zcu.PerThread.Id,
1580 const @"null": OptionalTid = .{ .non_null = false, .value = .main };
1581 fn unwrap(ot: OptionalTid) ?Zcu.PerThread.Id {
1582 return if (ot.non_null) ot.value else null;
1583 }
1584 fn wrap(tid: Zcu.PerThread.Id) OptionalTid {
1585 return .{ .non_null = true, .value = tid };
1586 }
1587 };
1588 mutex: Io.Mutex,
1589 tid: std.atomic.Value(OptionalTid),
1590 lock_count: u32,
1591 const init: RecursiveMutex = .{ .mutex = .init, .tid = .init(.null), .lock_count = 0 };
1592 fn lock(r: *RecursiveMutex, io: Io, tid: Zcu.PerThread.Id) void {
1593 if (r.tid.load(.monotonic) != OptionalTid.wrap(tid)) {
1594 r.mutex.lockUncancelable(io);
1595 assert(r.lock_count == 0);
1596 r.tid.store(.wrap(tid), .monotonic);
1597 }
1598 r.lock_count += 1;
1599 }
1600 fn unlock(r: *RecursiveMutex, io: Io) void {
1601 r.lock_count -= 1;
1602 if (r.lock_count == 0) {
1603 r.tid.store(.null, .monotonic);
1604 r.mutex.unlock(io);
1605 }
1606 }
1607 };
1608
15411609 const empty: Mutate = .{
1542 .mutex = std.Thread.Mutex.Recursive.init,
1610 .mutex = .init,
15431611 .len = 0,
15441612 };
15451613 };
......@@ -1896,7 +1964,7 @@ pub const NullTerminatedString = enum(u32) {
18961964 ip: *const InternPool,
18971965 id: bool,
18981966 };
1899 fn format(data: FormatData, writer: *std.Io.Writer) std.Io.Writer.Error!void {
1967 fn format(data: FormatData, writer: *Io.Writer) Io.Writer.Error!void {
19001968 const slice = data.string.toSlice(data.ip);
19011969 if (!data.id) {
19021970 try writer.writeAll(slice);
......@@ -2323,10 +2391,10 @@ pub const Key = union(enum) {
23232391 return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered);
23242392 }
23252393
2326 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {
2394 pub fn setBranchHint(func: Func, ip: *InternPool, io: Io, hint: std.builtin.BranchHint) void {
23272395 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2328 extra_mutex.lock();
2329 defer extra_mutex.unlock();
2396 extra_mutex.lockUncancelable(io);
2397 defer extra_mutex.unlock(io);
23302398
23312399 const analysis_ptr = func.analysisPtr(ip);
23322400 var analysis = analysis_ptr.*;
......@@ -2334,10 +2402,10 @@ pub const Key = union(enum) {
23342402 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
23352403 }
23362404
2337 pub fn setAnalyzed(func: Func, ip: *InternPool) void {
2405 pub fn setAnalyzed(func: Func, ip: *InternPool, io: Io) void {
23382406 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2339 extra_mutex.lock();
2340 defer extra_mutex.unlock();
2407 extra_mutex.lockUncancelable(io);
2408 defer extra_mutex.unlock(io);
23412409
23422410 const analysis_ptr = func.analysisPtr(ip);
23432411 var analysis = analysis_ptr.*;
......@@ -2365,10 +2433,10 @@ pub const Key = union(enum) {
23652433 return @atomicLoad(u32, func.branchQuotaPtr(ip), .unordered);
23662434 }
23672435
2368 pub fn maxBranchQuota(func: Func, ip: *InternPool, new_branch_quota: u32) void {
2436 pub fn maxBranchQuota(func: Func, ip: *InternPool, io: Io, new_branch_quota: u32) void {
23692437 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2370 extra_mutex.lock();
2371 defer extra_mutex.unlock();
2438 extra_mutex.lockUncancelable(io);
2439 defer extra_mutex.unlock(io);
23722440
23732441 const branch_quota_ptr = func.branchQuotaPtr(ip);
23742442 @atomicStore(u32, branch_quota_ptr, @max(branch_quota_ptr.*, new_branch_quota), .release);
......@@ -2385,10 +2453,10 @@ pub const Key = union(enum) {
23852453 return @atomicLoad(Index, func.resolvedErrorSetPtr(ip), .unordered);
23862454 }
23872455
2388 pub fn setResolvedErrorSet(func: Func, ip: *InternPool, ies: Index) void {
2456 pub fn setResolvedErrorSet(func: Func, ip: *InternPool, io: Io, ies: Index) void {
23892457 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2390 extra_mutex.lock();
2391 defer extra_mutex.unlock();
2458 extra_mutex.lockUncancelable(io);
2459 defer extra_mutex.unlock(io);
23922460
23932461 @atomicStore(Index, func.resolvedErrorSetPtr(ip), ies, .release);
23942462 }
......@@ -3349,10 +3417,10 @@ pub const LoadedUnionType = struct {
33493417 return @atomicLoad(Index, u.tagTypePtr(ip), .unordered);
33503418 }
33513419
3352 pub fn setTagType(u: LoadedUnionType, ip: *InternPool, tag_type: Index) void {
3420 pub fn setTagType(u: LoadedUnionType, ip: *InternPool, io: Io, tag_type: Index) void {
33533421 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3354 extra_mutex.lock();
3355 defer extra_mutex.unlock();
3422 extra_mutex.lockUncancelable(io);
3423 defer extra_mutex.unlock(io);
33563424
33573425 @atomicStore(Index, u.tagTypePtr(ip), tag_type, .release);
33583426 }
......@@ -3368,10 +3436,10 @@ pub const LoadedUnionType = struct {
33683436 return @atomicLoad(Tag.TypeUnion.Flags, u.flagsPtr(ip), .unordered);
33693437 }
33703438
3371 pub fn setStatus(u: LoadedUnionType, ip: *InternPool, status: Status) void {
3439 pub fn setStatus(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
33723440 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3373 extra_mutex.lock();
3374 defer extra_mutex.unlock();
3441 extra_mutex.lockUncancelable(io);
3442 defer extra_mutex.unlock(io);
33753443
33763444 const flags_ptr = u.flagsPtr(ip);
33773445 var flags = flags_ptr.*;
......@@ -3379,10 +3447,10 @@ pub const LoadedUnionType = struct {
33793447 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
33803448 }
33813449
3382 pub fn setStatusIfLayoutWip(u: LoadedUnionType, ip: *InternPool, status: Status) void {
3450 pub fn setStatusIfLayoutWip(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
33833451 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3384 extra_mutex.lock();
3385 defer extra_mutex.unlock();
3452 extra_mutex.lockUncancelable(io);
3453 defer extra_mutex.unlock(io);
33863454
33873455 const flags_ptr = u.flagsPtr(ip);
33883456 var flags = flags_ptr.*;
......@@ -3390,10 +3458,10 @@ pub const LoadedUnionType = struct {
33903458 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
33913459 }
33923460
3393 pub fn setAlignment(u: LoadedUnionType, ip: *InternPool, alignment: Alignment) void {
3461 pub fn setAlignment(u: LoadedUnionType, ip: *InternPool, io: Io, alignment: Alignment) void {
33943462 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3395 extra_mutex.lock();
3396 defer extra_mutex.unlock();
3463 extra_mutex.lockUncancelable(io);
3464 defer extra_mutex.unlock(io);
33973465
33983466 const flags_ptr = u.flagsPtr(ip);
33993467 var flags = flags_ptr.*;
......@@ -3401,10 +3469,10 @@ pub const LoadedUnionType = struct {
34013469 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
34023470 }
34033471
3404 pub fn assumeRuntimeBitsIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool) bool {
3472 pub fn assumeRuntimeBitsIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io) bool {
34053473 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3406 extra_mutex.lock();
3407 defer extra_mutex.unlock();
3474 extra_mutex.lockUncancelable(io);
3475 defer extra_mutex.unlock(io);
34083476
34093477 const flags_ptr = u.flagsPtr(ip);
34103478 var flags = flags_ptr.*;
......@@ -3419,10 +3487,10 @@ pub const LoadedUnionType = struct {
34193487 return u.flagsUnordered(ip).requires_comptime;
34203488 }
34213489
3422 pub fn setRequiresComptimeWip(u: LoadedUnionType, ip: *InternPool) RequiresComptime {
3490 pub fn setRequiresComptimeWip(u: LoadedUnionType, ip: *InternPool, io: Io) RequiresComptime {
34233491 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3424 extra_mutex.lock();
3425 defer extra_mutex.unlock();
3492 extra_mutex.lockUncancelable(io);
3493 defer extra_mutex.unlock(io);
34263494
34273495 const flags_ptr = u.flagsPtr(ip);
34283496 var flags = flags_ptr.*;
......@@ -3433,12 +3501,12 @@ pub const LoadedUnionType = struct {
34333501 return flags.requires_comptime;
34343502 }
34353503
3436 pub fn setRequiresComptime(u: LoadedUnionType, ip: *InternPool, requires_comptime: RequiresComptime) void {
3504 pub fn setRequiresComptime(u: LoadedUnionType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {
34373505 assert(requires_comptime != .wip); // see setRequiresComptimeWip
34383506
34393507 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3440 extra_mutex.lock();
3441 defer extra_mutex.unlock();
3508 extra_mutex.lockUncancelable(io);
3509 defer extra_mutex.unlock(io);
34423510
34433511 const flags_ptr = u.flagsPtr(ip);
34443512 var flags = flags_ptr.*;
......@@ -3446,10 +3514,10 @@ pub const LoadedUnionType = struct {
34463514 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
34473515 }
34483516
3449 pub fn assumePointerAlignedIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, ptr_align: Alignment) bool {
3517 pub fn assumePointerAlignedIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
34503518 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3451 extra_mutex.lock();
3452 defer extra_mutex.unlock();
3519 extra_mutex.lockUncancelable(io);
3520 defer extra_mutex.unlock(io);
34533521
34543522 const flags_ptr = u.flagsPtr(ip);
34553523 var flags = flags_ptr.*;
......@@ -3495,10 +3563,10 @@ pub const LoadedUnionType = struct {
34953563 return self.flagsUnordered(ip).status.haveLayout();
34963564 }
34973565
3498 pub fn setHaveLayout(u: LoadedUnionType, ip: *InternPool, size: u32, padding: u32, alignment: Alignment) void {
3566 pub fn setHaveLayout(u: LoadedUnionType, ip: *InternPool, io: Io, size: u32, padding: u32, alignment: Alignment) void {
34993567 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3500 extra_mutex.lock();
3501 defer extra_mutex.unlock();
3568 extra_mutex.lockUncancelable(io);
3569 defer extra_mutex.unlock(io);
35023570
35033571 @atomicStore(u32, u.sizePtr(ip), size, .unordered);
35043572 @atomicStore(u32, u.paddingPtr(ip), padding, .unordered);
......@@ -3767,10 +3835,10 @@ pub const LoadedStructType = struct {
37673835 return s.flagsUnordered(ip).requires_comptime;
37683836 }
37693837
3770 pub fn setRequiresComptimeWip(s: LoadedStructType, ip: *InternPool) RequiresComptime {
3838 pub fn setRequiresComptimeWip(s: LoadedStructType, ip: *InternPool, io: Io) RequiresComptime {
37713839 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3772 extra_mutex.lock();
3773 defer extra_mutex.unlock();
3840 extra_mutex.lockUncancelable(io);
3841 defer extra_mutex.unlock(io);
37743842
37753843 const flags_ptr = s.flagsPtr(ip);
37763844 var flags = flags_ptr.*;
......@@ -3781,12 +3849,12 @@ pub const LoadedStructType = struct {
37813849 return flags.requires_comptime;
37823850 }
37833851
3784 pub fn setRequiresComptime(s: LoadedStructType, ip: *InternPool, requires_comptime: RequiresComptime) void {
3852 pub fn setRequiresComptime(s: LoadedStructType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {
37853853 assert(requires_comptime != .wip); // see setRequiresComptimeWip
37863854
37873855 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3788 extra_mutex.lock();
3789 defer extra_mutex.unlock();
3856 extra_mutex.lockUncancelable(io);
3857 defer extra_mutex.unlock(io);
37903858
37913859 const flags_ptr = s.flagsPtr(ip);
37923860 var flags = flags_ptr.*;
......@@ -3794,12 +3862,12 @@ pub const LoadedStructType = struct {
37943862 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
37953863 }
37963864
3797 pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool) bool {
3865 pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
37983866 if (s.layout == .@"packed") return false;
37993867
38003868 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3801 extra_mutex.lock();
3802 defer extra_mutex.unlock();
3869 extra_mutex.lockUncancelable(io);
3870 defer extra_mutex.unlock(io);
38033871
38043872 const flags_ptr = s.flagsPtr(ip);
38053873 var flags = flags_ptr.*;
......@@ -3810,12 +3878,12 @@ pub const LoadedStructType = struct {
38103878 return flags.field_types_wip;
38113879 }
38123880
3813 pub fn setFieldTypesWip(s: LoadedStructType, ip: *InternPool) bool {
3881 pub fn setFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
38143882 if (s.layout == .@"packed") return false;
38153883
38163884 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3817 extra_mutex.lock();
3818 defer extra_mutex.unlock();
3885 extra_mutex.lockUncancelable(io);
3886 defer extra_mutex.unlock(io);
38193887
38203888 const flags_ptr = s.flagsPtr(ip);
38213889 var flags = flags_ptr.*;
......@@ -3826,12 +3894,12 @@ pub const LoadedStructType = struct {
38263894 return flags.field_types_wip;
38273895 }
38283896
3829 pub fn clearFieldTypesWip(s: LoadedStructType, ip: *InternPool) void {
3897 pub fn clearFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
38303898 if (s.layout == .@"packed") return;
38313899
38323900 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3833 extra_mutex.lock();
3834 defer extra_mutex.unlock();
3901 extra_mutex.lockUncancelable(io);
3902 defer extra_mutex.unlock(io);
38353903
38363904 const flags_ptr = s.flagsPtr(ip);
38373905 var flags = flags_ptr.*;
......@@ -3839,12 +3907,12 @@ pub const LoadedStructType = struct {
38393907 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
38403908 }
38413909
3842 pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool) bool {
3910 pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
38433911 if (s.layout == .@"packed") return false;
38443912
38453913 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3846 extra_mutex.lock();
3847 defer extra_mutex.unlock();
3914 extra_mutex.lockUncancelable(io);
3915 defer extra_mutex.unlock(io);
38483916
38493917 const flags_ptr = s.flagsPtr(ip);
38503918 var flags = flags_ptr.*;
......@@ -3855,12 +3923,12 @@ pub const LoadedStructType = struct {
38553923 return flags.layout_wip;
38563924 }
38573925
3858 pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool) void {
3926 pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
38593927 if (s.layout == .@"packed") return;
38603928
38613929 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3862 extra_mutex.lock();
3863 defer extra_mutex.unlock();
3930 extra_mutex.lockUncancelable(io);
3931 defer extra_mutex.unlock(io);
38643932
38653933 const flags_ptr = s.flagsPtr(ip);
38663934 var flags = flags_ptr.*;
......@@ -3868,10 +3936,10 @@ pub const LoadedStructType = struct {
38683936 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
38693937 }
38703938
3871 pub fn setAlignment(s: LoadedStructType, ip: *InternPool, alignment: Alignment) void {
3939 pub fn setAlignment(s: LoadedStructType, ip: *InternPool, io: Io, alignment: Alignment) void {
38723940 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3873 extra_mutex.lock();
3874 defer extra_mutex.unlock();
3941 extra_mutex.lockUncancelable(io);
3942 defer extra_mutex.unlock(io);
38753943
38763944 const flags_ptr = s.flagsPtr(ip);
38773945 var flags = flags_ptr.*;
......@@ -3879,10 +3947,10 @@ pub const LoadedStructType = struct {
38793947 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
38803948 }
38813949
3882 pub fn assumePointerAlignedIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, ptr_align: Alignment) bool {
3950 pub fn assumePointerAlignedIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
38833951 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3884 extra_mutex.lock();
3885 defer extra_mutex.unlock();
3952 extra_mutex.lockUncancelable(io);
3953 defer extra_mutex.unlock(io);
38863954
38873955 const flags_ptr = s.flagsPtr(ip);
38883956 var flags = flags_ptr.*;
......@@ -3894,10 +3962,10 @@ pub const LoadedStructType = struct {
38943962 return flags.field_types_wip;
38953963 }
38963964
3897 pub fn assumePointerAlignedIfWip(s: LoadedStructType, ip: *InternPool, ptr_align: Alignment) bool {
3965 pub fn assumePointerAlignedIfWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
38983966 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3899 extra_mutex.lock();
3900 defer extra_mutex.unlock();
3967 extra_mutex.lockUncancelable(io);
3968 defer extra_mutex.unlock(io);
39013969
39023970 const flags_ptr = s.flagsPtr(ip);
39033971 var flags = flags_ptr.*;
......@@ -3911,12 +3979,12 @@ pub const LoadedStructType = struct {
39113979 return flags.alignment_wip;
39123980 }
39133981
3914 pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool) void {
3982 pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
39153983 if (s.layout == .@"packed") return;
39163984
39173985 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3918 extra_mutex.lock();
3919 defer extra_mutex.unlock();
3986 extra_mutex.lockUncancelable(io);
3987 defer extra_mutex.unlock(io);
39203988
39213989 const flags_ptr = s.flagsPtr(ip);
39223990 var flags = flags_ptr.*;
......@@ -3924,10 +3992,10 @@ pub const LoadedStructType = struct {
39243992 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
39253993 }
39263994
3927 pub fn setInitsWip(s: LoadedStructType, ip: *InternPool) bool {
3995 pub fn setInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
39283996 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3929 extra_mutex.lock();
3930 defer extra_mutex.unlock();
3997 extra_mutex.lockUncancelable(io);
3998 defer extra_mutex.unlock(io);
39313999
39324000 switch (s.layout) {
39334001 .@"packed" => {
......@@ -3951,10 +4019,10 @@ pub const LoadedStructType = struct {
39514019 }
39524020 }
39534021
3954 pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool) void {
4022 pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
39554023 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3956 extra_mutex.lock();
3957 defer extra_mutex.unlock();
4024 extra_mutex.lockUncancelable(io);
4025 defer extra_mutex.unlock(io);
39584026
39594027 switch (s.layout) {
39604028 .@"packed" => {
......@@ -3972,12 +4040,12 @@ pub const LoadedStructType = struct {
39724040 }
39734041 }
39744042
3975 pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool) bool {
4043 pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) bool {
39764044 if (s.layout == .@"packed") return true;
39774045
39784046 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3979 extra_mutex.lock();
3980 defer extra_mutex.unlock();
4047 extra_mutex.lockUncancelable(io);
4048 defer extra_mutex.unlock(io);
39814049
39824050 const flags_ptr = s.flagsPtr(ip);
39834051 var flags = flags_ptr.*;
......@@ -3988,10 +4056,10 @@ pub const LoadedStructType = struct {
39884056 return flags.fully_resolved;
39894057 }
39904058
3991 pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool) void {
4059 pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) void {
39924060 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3993 extra_mutex.lock();
3994 defer extra_mutex.unlock();
4061 extra_mutex.lockUncancelable(io);
4062 defer extra_mutex.unlock(io);
39954063
39964064 const flags_ptr = s.flagsPtr(ip);
39974065 var flags = flags_ptr.*;
......@@ -4027,10 +4095,10 @@ pub const LoadedStructType = struct {
40274095 return @atomicLoad(Index, s.backingIntTypePtr(ip), .unordered);
40284096 }
40294097
4030 pub fn setBackingIntType(s: LoadedStructType, ip: *InternPool, backing_int_ty: Index) void {
4098 pub fn setBackingIntType(s: LoadedStructType, ip: *InternPool, io: Io, backing_int_ty: Index) void {
40314099 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4032 extra_mutex.lock();
4033 defer extra_mutex.unlock();
4100 extra_mutex.lockUncancelable(io);
4101 defer extra_mutex.unlock(io);
40344102
40354103 @atomicStore(Index, s.backingIntTypePtr(ip), backing_int_ty, .release);
40364104 }
......@@ -4054,10 +4122,10 @@ pub const LoadedStructType = struct {
40544122 };
40554123 }
40564124
4057 pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool) void {
4125 pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool, io: Io) void {
40584126 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4059 extra_mutex.lock();
4060 defer extra_mutex.unlock();
4127 extra_mutex.lockUncancelable(io);
4128 defer extra_mutex.unlock(io);
40614129
40624130 switch (s.layout) {
40634131 .@"packed" => {
......@@ -4082,10 +4150,10 @@ pub const LoadedStructType = struct {
40824150 };
40834151 }
40844152
4085 pub fn setLayoutResolved(s: LoadedStructType, ip: *InternPool, size: u32, alignment: Alignment) void {
4153 pub fn setLayoutResolved(s: LoadedStructType, ip: *InternPool, io: Io, size: u32, alignment: Alignment) void {
40864154 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4087 extra_mutex.lock();
4088 defer extra_mutex.unlock();
4155 extra_mutex.lockUncancelable(io);
4156 defer extra_mutex.unlock(io);
40894157
40904158 @atomicStore(u32, s.sizePtr(ip), size, .unordered);
40914159 const flags_ptr = s.flagsPtr(ip);
......@@ -6826,8 +6894,8 @@ pub const MemoizedCall = struct {
68266894 branch_count: u32,
68276895};
68286896
6829pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
6830 errdefer ip.deinit(gpa);
6897pub fn init(ip: *InternPool, gpa: Allocator, io: Io, available_threads: usize) !void {
6898 errdefer ip.deinit(gpa, io);
68316899 assert(ip.locals.len == 0 and ip.shards.len == 0);
68326900 assert(available_threads > 0 and available_threads <= std.math.maxInt(u8));
68336901
......@@ -6865,7 +6933,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
68656933 .namespaces = .empty,
68666934 },
68676935 });
6868 for (ip.locals) |*local| try local.getMutableStrings(gpa).append(.{0});
6936 for (ip.locals) |*local| try local.getMutableStrings(gpa, io).append(.{0});
68696937
68706938 ip.tid_width = @intCast(std.math.log2_int_ceil(usize, used_threads));
68716939 ip.tid_shift_30 = if (single_threaded) 0 else 30 - ip.tid_width;
......@@ -6874,28 +6942,28 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
68746942 ip.shards = try gpa.alloc(Shard, @as(usize, 1) << ip.tid_width);
68756943 @memset(ip.shards, .{
68766944 .shared = .{
6877 .map = Shard.Map(Index).empty,
6878 .string_map = Shard.Map(OptionalNullTerminatedString).empty,
6879 .tracked_inst_map = Shard.Map(TrackedInst.Index.Optional).empty,
6945 .map = .empty,
6946 .string_map = .empty,
6947 .tracked_inst_map = .empty,
68806948 },
68816949 .mutate = .{
6882 .map = Shard.Mutate.empty,
6883 .string_map = Shard.Mutate.empty,
6884 .tracked_inst_map = Shard.Mutate.empty,
6950 .map = .empty,
6951 .string_map = .empty,
6952 .tracked_inst_map = .empty,
68856953 },
68866954 });
68876955
68886956 // Reserve string index 0 for an empty string.
6889 assert((try ip.getOrPutString(gpa, .main, "", .no_embedded_nulls)) == .empty);
6957 assert((try ip.getOrPutString(gpa, io, .main, "", .no_embedded_nulls)) == .empty);
68906958
68916959 // This inserts all the statically-known values into the intern pool in the
68926960 // order expected.
68936961 for (&static_keys, 0..) |key, key_index| switch (@as(Index, @enumFromInt(key_index))) {
6894 .empty_tuple_type => assert(try ip.getTupleType(gpa, .main, .{
6962 .empty_tuple_type => assert(try ip.getTupleType(gpa, io, .main, .{
68956963 .types = &.{},
68966964 .values = &.{},
68976965 }) == .empty_tuple_type),
6898 else => |expected_index| assert(try ip.get(gpa, .main, key) == expected_index),
6966 else => |expected_index| assert(try ip.get(gpa, io, .main, key) == expected_index),
68996967 };
69006968
69016969 if (std.debug.runtime_safety) {
......@@ -6905,7 +6973,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
69056973 }
69066974}
69076975
6908pub fn deinit(ip: *InternPool, gpa: Allocator) void {
6976pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {
69096977 if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null);
69106978
69116979 ip.src_hash_deps.deinit(gpa);
......@@ -6940,7 +7008,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
69407008 namespace.test_decls.deinit(gpa);
69417009 }
69427010 };
6943 const maps = local.getMutableMaps(gpa);
7011 const maps = local.getMutableMaps(gpa, io);
69447012 if (maps.mutate.len > 0) for (maps.view().items(.@"0")) |*map| map.deinit(gpa);
69457013 local.mutate.arena.promote(gpa).deinit();
69467014 }
......@@ -7645,6 +7713,7 @@ const GetOrPutKey = union(enum) {
76457713 new: struct {
76467714 ip: *InternPool,
76477715 tid: Zcu.PerThread.Id,
7716 io: Io,
76487717 shard: *Shard,
76497718 map_index: u32,
76507719 },
......@@ -7679,7 +7748,7 @@ const GetOrPutKey = union(enum) {
76797748 .new => |info| {
76807749 assert(info.shard.shared.map.entries[info.map_index].value == index);
76817750 info.shard.mutate.map.len += 1;
7682 info.shard.mutate.map.mutex.unlock();
7751 info.shard.mutate.map.mutex.unlock(info.io);
76837752 gop.* = .{ .existing = index };
76847753 },
76857754 }
......@@ -7688,7 +7757,7 @@ const GetOrPutKey = union(enum) {
76887757 fn cancel(gop: *GetOrPutKey) void {
76897758 switch (gop.*) {
76907759 .existing => {},
7691 .new => |info| info.shard.mutate.map.mutex.unlock(),
7760 .new => |info| info.shard.mutate.map.mutex.unlock(info.io),
76927761 }
76937762 gop.* = .{ .existing = undefined };
76947763 }
......@@ -7705,14 +7774,16 @@ const GetOrPutKey = union(enum) {
77057774fn getOrPutKey(
77067775 ip: *InternPool,
77077776 gpa: Allocator,
7777 io: Io,
77087778 tid: Zcu.PerThread.Id,
77097779 key: Key,
77107780) Allocator.Error!GetOrPutKey {
7711 return ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, key, 0);
7781 return ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, key, 0);
77127782}
77137783fn getOrPutKeyEnsuringAdditionalCapacity(
77147784 ip: *InternPool,
77157785 gpa: Allocator,
7786 io: Io,
77167787 tid: Zcu.PerThread.Id,
77177788 key: Key,
77187789 additional_capacity: u32,
......@@ -7733,8 +7804,8 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
77337804 if (index.unwrap(ip).getTag(ip) == .removed) continue;
77347805 if (ip.indexToKey(index).eql(key, ip)) return .{ .existing = index };
77357806 }
7736 shard.mutate.map.mutex.lock();
7737 errdefer shard.mutate.map.mutex.unlock();
7807 shard.mutate.map.mutex.lock(io, tid);
7808 errdefer shard.mutate.map.mutex.unlock(io);
77387809 if (map.entries != shard.shared.map.entries) {
77397810 map = shard.shared.map;
77407811 map_mask = map.header().mask();
......@@ -7747,7 +7818,7 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
77477818 if (index == .none) break;
77487819 if (entry.hash != hash) continue;
77497820 if (ip.indexToKey(index).eql(key, ip)) {
7750 defer shard.mutate.map.mutex.unlock();
7821 defer shard.mutate.map.mutex.unlock(io);
77517822 return .{ .existing = index };
77527823 }
77537824 }
......@@ -7801,6 +7872,7 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
78017872 return .{ .new = .{
78027873 .ip = ip,
78037874 .tid = tid,
7875 .io = io,
78047876 .shard = shard,
78057877 .map_index = map_index,
78067878 } };
......@@ -7815,14 +7887,15 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
78157887/// will be cleaned up when the `Zcu` undergoes garbage collection.
78167888fn putKeyReplace(
78177889 ip: *InternPool,
7890 io: Io,
78187891 tid: Zcu.PerThread.Id,
78197892 key: Key,
78207893) GetOrPutKey {
78217894 const full_hash = key.hash64(ip);
78227895 const hash: u32 = @truncate(full_hash >> 32);
78237896 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
7824 shard.mutate.map.mutex.lock();
7825 errdefer shard.mutate.map.mutex.unlock();
7897 shard.mutate.map.mutex.lock(io, tid);
7898 errdefer shard.mutate.map.mutex.unlock(io);
78267899 const map = shard.shared.map;
78277900 const map_mask = map.header().mask();
78287901 var map_index = hash;
......@@ -7838,18 +7911,19 @@ fn putKeyReplace(
78387911 return .{ .new = .{
78397912 .ip = ip,
78407913 .tid = tid,
7914 .io = io,
78417915 .shard = shard,
78427916 .map_index = map_index,
78437917 } };
78447918}
78457919
7846pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {
7847 var gop = try ip.getOrPutKey(gpa, tid, key);
7920pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {
7921 var gop = try ip.getOrPutKey(gpa, io, tid, key);
78487922 defer gop.deinit();
78497923 if (gop == .existing) return gop.existing;
78507924 const local = ip.getLocal(tid);
7851 const items = local.getMutableItems(gpa);
7852 const extra = local.getMutableExtra(gpa);
7925 const items = local.getMutableItems(gpa, io);
7926 const extra = local.getMutableExtra(gpa, io);
78537927 try items.ensureUnusedCapacity(1);
78547928 switch (key) {
78557929 .int_type => |int_type| {
......@@ -7870,8 +7944,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
78707944 gop.cancel();
78717945 var new_key = key;
78727946 new_key.ptr_type.flags.size = .many;
7873 const ptr_type_index = try ip.get(gpa, tid, new_key);
7874 gop = try ip.getOrPutKey(gpa, tid, key);
7947 const ptr_type_index = try ip.get(gpa, io, tid, new_key);
7948 gop = try ip.getOrPutKey(gpa, io, tid, key);
78757949
78767950 try items.ensureUnusedCapacity(1);
78777951 items.appendAssumeCapacity(.{
......@@ -7953,7 +8027,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
79538027 assert(error_set_type.names_map == .none);
79548028 assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan));
79558029 const names = error_set_type.names.get(ip);
7956 const names_map = try ip.addMap(gpa, tid, names.len);
8030 const names_map = try ip.addMap(gpa, io, tid, names.len);
79578031 ip.addStringsToMap(names_map, names);
79588032 const names_len = error_set_type.names.len;
79598033 try extra.ensureUnusedCapacity(@typeInfo(Tag.ErrorSet).@"struct".fields.len + names_len);
......@@ -8051,7 +8125,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
80518125 gop.cancel();
80528126 var new_key = key;
80538127 new_key.ptr.base_addr.uav.orig_ty = ptr.ty;
8054 gop = try ip.getOrPutKey(gpa, tid, new_key);
8128 gop = try ip.getOrPutKey(gpa, io, tid, new_key);
80558129 if (gop == .existing) return gop.existing;
80568130 }
80578131 break :item .{
......@@ -8123,11 +8197,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
81238197 else => unreachable,
81248198 }
81258199 gop.cancel();
8126 const index_index = try ip.get(gpa, tid, .{ .int = .{
8200 const index_index = try ip.get(gpa, io, tid, .{ .int = .{
81278201 .ty = .usize_type,
81288202 .storage = .{ .u64 = base_index.index },
81298203 } });
8130 gop = try ip.getOrPutKey(gpa, tid, key);
8204 gop = try ip.getOrPutKey(gpa, io, tid, key);
81318205 try items.ensureUnusedCapacity(1);
81328206 items.appendAssumeCapacity(.{
81338207 .tag = switch (ptr.base_addr) {
......@@ -8318,7 +8392,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
83188392 } else |_| {}
83198393
83208394 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
8321 try addInt(ip, gpa, tid, int.ty, tag, big_int.limbs);
8395 try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs);
83228396 },
83238397 inline .u64, .i64 => |x| {
83248398 if (std.math.cast(u32, x)) |casted| {
......@@ -8335,7 +8409,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
83358409 var buf: [2]Limb = undefined;
83368410 const big_int = BigIntMutable.init(&buf, x).toConst();
83378411 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
8338 try addInt(ip, gpa, tid, int.ty, tag, big_int.limbs);
8412 try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs);
83398413 },
83408414 .lazy_align, .lazy_size => unreachable,
83418415 }
......@@ -8546,11 +8620,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
85468620 const elem = switch (aggregate.storage) {
85478621 .bytes => |bytes| elem: {
85488622 gop.cancel();
8549 const elem = try ip.get(gpa, tid, .{ .int = .{
8623 const elem = try ip.get(gpa, io, tid, .{ .int = .{
85508624 .ty = .u8_type,
85518625 .storage = .{ .u64 = bytes.at(0, ip) },
85528626 } });
8553 gop = try ip.getOrPutKey(gpa, tid, key);
8627 gop = try ip.getOrPutKey(gpa, io, tid, key);
85548628 try items.ensureUnusedCapacity(1);
85558629 break :elem elem;
85568630 },
......@@ -8570,7 +8644,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
85708644 }
85718645
85728646 if (child == .u8_type) bytes: {
8573 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa);
8647 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa, io);
85748648 const start = string_bytes.mutate.len;
85758649 try string_bytes.ensureUnusedCapacity(@intCast(len_including_sentinel + 1));
85768650 try extra.ensureUnusedCapacity(@typeInfo(Bytes).@"struct".fields.len);
......@@ -8598,6 +8672,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
85988672 });
85998673 const string = try ip.getOrPutTrailingString(
86008674 gpa,
8675 io,
86018676 tid,
86028677 @intCast(len_including_sentinel),
86038678 .maybe_embedded_nulls,
......@@ -8647,15 +8722,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
86478722pub fn getUnion(
86488723 ip: *InternPool,
86498724 gpa: Allocator,
8725 io: Io,
86508726 tid: Zcu.PerThread.Id,
86518727 un: Key.Union,
86528728) Allocator.Error!Index {
8653 var gop = try ip.getOrPutKey(gpa, tid, .{ .un = un });
8729 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
86548730 defer gop.deinit();
86558731 if (gop == .existing) return gop.existing;
86568732 const local = ip.getLocal(tid);
8657 const items = local.getMutableItems(gpa);
8658 const extra = local.getMutableExtra(gpa);
8733 const items = local.getMutableItems(gpa, io);
8734 const extra = local.getMutableExtra(gpa, io);
86598735 try items.ensureUnusedCapacity(1);
86608736
86618737 assert(un.ty != .none);
......@@ -8706,6 +8782,7 @@ pub const UnionTypeInit = struct {
87068782pub fn getUnionType(
87078783 ip: *InternPool,
87088784 gpa: Allocator,
8785 io: Io,
87098786 tid: Zcu.PerThread.Id,
87108787 ini: UnionTypeInit,
87118788 /// If it is known that there is an existing type with this key which is outdated,
......@@ -8727,16 +8804,16 @@ pub fn getUnionType(
87278804 } },
87288805 } };
87298806 var gop = if (replace_existing)
8730 ip.putKeyReplace(tid, key)
8807 ip.putKeyReplace(io, tid, key)
87318808 else
8732 try ip.getOrPutKey(gpa, tid, key);
8809 try ip.getOrPutKey(gpa, io, tid, key);
87338810 defer gop.deinit();
87348811 if (gop == .existing) return .{ .existing = gop.existing };
87358812
87368813 const local = ip.getLocal(tid);
8737 const items = local.getMutableItems(gpa);
8814 const items = local.getMutableItems(gpa, io);
87388815 try items.ensureUnusedCapacity(1);
8739 const extra = local.getMutableExtra(gpa);
8816 const extra = local.getMutableExtra(gpa, io);
87408817
87418818 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
87428819 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
......@@ -8903,6 +8980,7 @@ pub const StructTypeInit = struct {
89038980pub fn getStructType(
89048981 ip: *InternPool,
89058982 gpa: Allocator,
8983 io: Io,
89068984 tid: Zcu.PerThread.Id,
89078985 ini: StructTypeInit,
89088986 /// If it is known that there is an existing type with this key which is outdated,
......@@ -8924,17 +9002,17 @@ pub fn getStructType(
89249002 } },
89259003 } };
89269004 var gop = if (replace_existing)
8927 ip.putKeyReplace(tid, key)
9005 ip.putKeyReplace(io, tid, key)
89289006 else
8929 try ip.getOrPutKey(gpa, tid, key);
9007 try ip.getOrPutKey(gpa, io, tid, key);
89309008 defer gop.deinit();
89319009 if (gop == .existing) return .{ .existing = gop.existing };
89329010
89339011 const local = ip.getLocal(tid);
8934 const items = local.getMutableItems(gpa);
8935 const extra = local.getMutableExtra(gpa);
9012 const items = local.getMutableItems(gpa, io);
9013 const extra = local.getMutableExtra(gpa, io);
89369014
8937 const names_map = try ip.addMap(gpa, tid, ini.fields_len);
9015 const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);
89389016 errdefer local.mutate.maps.len -= 1;
89399017
89409018 const zir_index = switch (ini.key) {
......@@ -9109,6 +9187,7 @@ pub const TupleTypeInit = struct {
91099187pub fn getTupleType(
91109188 ip: *InternPool,
91119189 gpa: Allocator,
9190 io: Io,
91129191 tid: Zcu.PerThread.Id,
91139192 ini: TupleTypeInit,
91149193) Allocator.Error!Index {
......@@ -9116,8 +9195,8 @@ pub fn getTupleType(
91169195 for (ini.types) |elem| assert(elem != .none);
91179196
91189197 const local = ip.getLocal(tid);
9119 const items = local.getMutableItems(gpa);
9120 const extra = local.getMutableExtra(gpa);
9198 const items = local.getMutableItems(gpa, io);
9199 const extra = local.getMutableExtra(gpa, io);
91219200
91229201 const prev_extra_len = extra.mutate.len;
91239202 const fields_len: u32 = @intCast(ini.types.len);
......@@ -9134,7 +9213,7 @@ pub fn getTupleType(
91349213 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)});
91359214 errdefer extra.mutate.len = prev_extra_len;
91369215
9137 var gop = try ip.getOrPutKey(gpa, tid, .{ .tuple_type = extraTypeTuple(tid, extra.list.*, extra_index) });
9216 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .tuple_type = extraTypeTuple(tid, extra.list.*, extra_index) });
91389217 defer gop.deinit();
91399218 if (gop == .existing) {
91409219 extra.mutate.len = prev_extra_len;
......@@ -9166,6 +9245,7 @@ pub const GetFuncTypeKey = struct {
91669245pub fn getFuncType(
91679246 ip: *InternPool,
91689247 gpa: Allocator,
9248 io: Io,
91699249 tid: Zcu.PerThread.Id,
91709250 key: GetFuncTypeKey,
91719251) Allocator.Error!Index {
......@@ -9174,9 +9254,9 @@ pub fn getFuncType(
91749254 for (key.param_types) |param_type| assert(param_type != .none);
91759255
91769256 const local = ip.getLocal(tid);
9177 const items = local.getMutableItems(gpa);
9257 const items = local.getMutableItems(gpa, io);
91789258 try items.ensureUnusedCapacity(1);
9179 const extra = local.getMutableExtra(gpa);
9259 const extra = local.getMutableExtra(gpa, io);
91809260
91819261 // The strategy here is to add the function type unconditionally, then to
91829262 // ask if it already exists, and if so, revert the lengths of the mutated
......@@ -9207,7 +9287,7 @@ pub fn getFuncType(
92079287 extra.appendSliceAssumeCapacity(.{@ptrCast(key.param_types)});
92089288 errdefer extra.mutate.len = prev_extra_len;
92099289
9210 var gop = try ip.getOrPutKey(gpa, tid, .{
9290 var gop = try ip.getOrPutKey(gpa, io, tid, .{
92119291 .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index),
92129292 });
92139293 defer gop.deinit();
......@@ -9228,6 +9308,7 @@ pub fn getFuncType(
92289308pub fn getExtern(
92299309 ip: *InternPool,
92309310 gpa: Allocator,
9311 io: Io,
92319312 tid: Zcu.PerThread.Id,
92329313 /// `key.owner_nav` is ignored.
92339314 key: Key.Extern,
......@@ -9236,7 +9317,7 @@ pub fn getExtern(
92369317 /// Only set if the `Nav` was newly created.
92379318 new_nav: Nav.Index.Optional,
92389319} {
9239 var gop = try ip.getOrPutKey(gpa, tid, .{ .@"extern" = key });
9320 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .@"extern" = key });
92409321 defer gop.deinit();
92419322 if (gop == .existing) return .{
92429323 .index = gop.existing,
......@@ -9244,18 +9325,18 @@ pub fn getExtern(
92449325 };
92459326
92469327 const local = ip.getLocal(tid);
9247 const items = local.getMutableItems(gpa);
9248 const extra = local.getMutableExtra(gpa);
9328 const items = local.getMutableItems(gpa, io);
9329 const extra = local.getMutableExtra(gpa, io);
92499330 try items.ensureUnusedCapacity(1);
92509331 try extra.ensureUnusedCapacity(@typeInfo(Tag.Extern).@"struct".fields.len);
9251 try local.getMutableNavs(gpa).ensureUnusedCapacity(1);
9332 try local.getMutableNavs(gpa, io).ensureUnusedCapacity(1);
92529333
92539334 // Predict the index the `@"extern" will live at, so we can construct the owner `Nav` before releasing the shard's mutex.
92549335 const extern_index = Index.Unwrapped.wrap(.{
92559336 .tid = tid,
92569337 .index = items.mutate.len,
92579338 }, ip);
9258 const owner_nav = ip.createNav(gpa, tid, .{
9339 const owner_nav = ip.createNav(gpa, io, tid, .{
92599340 .name = key.name,
92609341 .fqn = key.name,
92619342 .val = extern_index,
......@@ -9305,13 +9386,14 @@ pub const GetFuncDeclKey = struct {
93059386pub fn getFuncDecl(
93069387 ip: *InternPool,
93079388 gpa: Allocator,
9389 io: Io,
93089390 tid: Zcu.PerThread.Id,
93099391 key: GetFuncDeclKey,
93109392) Allocator.Error!Index {
93119393 const local = ip.getLocal(tid);
9312 const items = local.getMutableItems(gpa);
9394 const items = local.getMutableItems(gpa, io);
93139395 try items.ensureUnusedCapacity(1);
9314 const extra = local.getMutableExtra(gpa);
9396 const extra = local.getMutableExtra(gpa, io);
93159397
93169398 // The strategy here is to add the function type unconditionally, then to
93179399 // ask if it already exists, and if so, revert the lengths of the mutated
......@@ -9340,7 +9422,7 @@ pub fn getFuncDecl(
93409422 });
93419423 errdefer extra.mutate.len = prev_extra_len;
93429424
9343 var gop = try ip.getOrPutKey(gpa, tid, .{
9425 var gop = try ip.getOrPutKey(gpa, io, tid, .{
93449426 .func = extraFuncDecl(tid, extra.list.*, func_decl_extra_index),
93459427 });
93469428 defer gop.deinit();
......@@ -9387,6 +9469,7 @@ pub const GetFuncDeclIesKey = struct {
93879469pub fn getFuncDeclIes(
93889470 ip: *InternPool,
93899471 gpa: Allocator,
9472 io: Io,
93909473 tid: Zcu.PerThread.Id,
93919474 key: GetFuncDeclIesKey,
93929475) Allocator.Error!Index {
......@@ -9395,9 +9478,9 @@ pub fn getFuncDeclIes(
93959478 for (key.param_types) |param_type| assert(param_type != .none);
93969479
93979480 const local = ip.getLocal(tid);
9398 const items = local.getMutableItems(gpa);
9481 const items = local.getMutableItems(gpa, io);
93999482 try items.ensureUnusedCapacity(4);
9400 const extra = local.getMutableExtra(gpa);
9483 const extra = local.getMutableExtra(gpa, io);
94019484
94029485 // The strategy here is to add the function decl unconditionally, then to
94039486 // ask if it already exists, and if so, revert the lengths of the mutated
......@@ -9488,7 +9571,7 @@ pub fn getFuncDeclIes(
94889571 extra.mutate.len = prev_extra_len;
94899572 }
94909573
9491 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{
9574 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
94929575 .func = extraFuncDecl(tid, extra.list.*, func_decl_extra_index),
94939576 }, 3);
94949577 defer func_gop.deinit();
......@@ -9509,18 +9592,18 @@ pub fn getFuncDeclIes(
95099592 return func_gop.existing;
95109593 }
95119594 func_gop.putTentative(func_index);
9512 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{ .error_union_type = .{
9595 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{
95139596 .error_set_type = error_set_type,
95149597 .payload_type = key.bare_return_type,
95159598 } }, 2);
95169599 defer error_union_type_gop.deinit();
95179600 error_union_type_gop.putTentative(error_union_type);
9518 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{
9601 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
95199602 .inferred_error_set_type = func_index,
95209603 }, 1);
95219604 defer error_set_type_gop.deinit();
95229605 error_set_type_gop.putTentative(error_set_type);
9523 var func_ty_gop = try ip.getOrPutKey(gpa, tid, .{
9606 var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{
95249607 .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index),
95259608 });
95269609 defer func_ty_gop.deinit();
......@@ -9536,17 +9619,18 @@ pub fn getFuncDeclIes(
95369619pub fn getErrorSetType(
95379620 ip: *InternPool,
95389621 gpa: Allocator,
9622 io: Io,
95399623 tid: Zcu.PerThread.Id,
95409624 names: []const NullTerminatedString,
95419625) Allocator.Error!Index {
95429626 assert(std.sort.isSorted(NullTerminatedString, names, {}, NullTerminatedString.indexLessThan));
95439627
95449628 const local = ip.getLocal(tid);
9545 const items = local.getMutableItems(gpa);
9546 const extra = local.getMutableExtra(gpa);
9629 const items = local.getMutableItems(gpa, io);
9630 const extra = local.getMutableExtra(gpa, io);
95479631 try extra.ensureUnusedCapacity(@typeInfo(Tag.ErrorSet).@"struct".fields.len + names.len);
95489632
9549 const names_map = try ip.addMap(gpa, tid, names.len);
9633 const names_map = try ip.addMap(gpa, io, tid, names.len);
95509634 errdefer local.mutate.maps.len -= 1;
95519635
95529636 // The strategy here is to add the type unconditionally, then to ask if it
......@@ -9562,7 +9646,7 @@ pub fn getErrorSetType(
95629646 extra.appendSliceAssumeCapacity(.{@ptrCast(names)});
95639647 errdefer extra.mutate.len = prev_extra_len;
95649648
9565 var gop = try ip.getOrPutKey(gpa, tid, .{
9649 var gop = try ip.getOrPutKey(gpa, io, tid, .{
95669650 .error_set_type = extraErrorSet(tid, extra.list.*, error_set_extra_index),
95679651 });
95689652 defer gop.deinit();
......@@ -9599,16 +9683,17 @@ pub const GetFuncInstanceKey = struct {
95999683pub fn getFuncInstance(
96009684 ip: *InternPool,
96019685 gpa: Allocator,
9686 io: Io,
96029687 tid: Zcu.PerThread.Id,
96039688 arg: GetFuncInstanceKey,
96049689) Allocator.Error!Index {
96059690 if (arg.inferred_error_set)
9606 return getFuncInstanceIes(ip, gpa, tid, arg);
9691 return getFuncInstanceIes(ip, gpa, io, tid, arg);
96079692
96089693 const generic_owner = unwrapCoercedFunc(ip, arg.generic_owner);
96099694 const generic_owner_ty = ip.indexToKey(ip.funcDeclInfo(generic_owner).ty).func_type;
96109695
9611 const func_ty = try ip.getFuncType(gpa, tid, .{
9696 const func_ty = try ip.getFuncType(gpa, io, tid, .{
96129697 .param_types = arg.param_types,
96139698 .return_type = arg.bare_return_type,
96149699 .noalias_bits = arg.noalias_bits,
......@@ -9617,8 +9702,8 @@ pub fn getFuncInstance(
96179702 });
96189703
96199704 const local = ip.getLocal(tid);
9620 const items = local.getMutableItems(gpa);
9621 const extra = local.getMutableExtra(gpa);
9705 const items = local.getMutableItems(gpa, io);
9706 const extra = local.getMutableExtra(gpa, io);
96229707 try extra.ensureUnusedCapacity(@typeInfo(Tag.FuncInstance).@"struct".fields.len +
96239708 arg.comptime_args.len);
96249709
......@@ -9646,7 +9731,7 @@ pub fn getFuncInstance(
96469731 });
96479732 extra.appendSliceAssumeCapacity(.{@ptrCast(arg.comptime_args)});
96489733
9649 var gop = try ip.getOrPutKey(gpa, tid, .{
9734 var gop = try ip.getOrPutKey(gpa, io, tid, .{
96509735 .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index),
96519736 });
96529737 defer gop.deinit();
......@@ -9664,6 +9749,7 @@ pub fn getFuncInstance(
96649749 try finishFuncInstance(
96659750 ip,
96669751 gpa,
9752 io,
96679753 tid,
96689754 extra,
96699755 generic_owner,
......@@ -9676,9 +9762,10 @@ pub fn getFuncInstance(
96769762/// This function exists separately than `getFuncInstance` because it needs to
96779763/// create 4 new items in the InternPool atomically before it can look for an
96789764/// existing item in the map.
9679pub fn getFuncInstanceIes(
9765fn getFuncInstanceIes(
96809766 ip: *InternPool,
96819767 gpa: Allocator,
9768 io: Io,
96829769 tid: Zcu.PerThread.Id,
96839770 arg: GetFuncInstanceKey,
96849771) Allocator.Error!Index {
......@@ -9688,8 +9775,8 @@ pub fn getFuncInstanceIes(
96889775 for (arg.param_types) |param_type| assert(param_type != .none);
96899776
96909777 const local = ip.getLocal(tid);
9691 const items = local.getMutableItems(gpa);
9692 const extra = local.getMutableExtra(gpa);
9778 const items = local.getMutableItems(gpa, io);
9779 const extra = local.getMutableExtra(gpa, io);
96939780 try items.ensureUnusedCapacity(4);
96949781
96959782 const generic_owner = unwrapCoercedFunc(ip, arg.generic_owner);
......@@ -9784,7 +9871,7 @@ pub fn getFuncInstanceIes(
97849871 extra.mutate.len = prev_extra_len;
97859872 }
97869873
9787 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{
9874 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
97889875 .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index),
97899876 }, 3);
97909877 defer func_gop.deinit();
......@@ -9795,18 +9882,18 @@ pub fn getFuncInstanceIes(
97959882 return func_gop.existing;
97969883 }
97979884 func_gop.putTentative(func_index);
9798 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{ .error_union_type = .{
9885 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{
97999886 .error_set_type = error_set_type,
98009887 .payload_type = arg.bare_return_type,
98019888 } }, 2);
98029889 defer error_union_type_gop.deinit();
98039890 error_union_type_gop.putTentative(error_union_type);
9804 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, .{
9891 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
98059892 .inferred_error_set_type = func_index,
98069893 }, 1);
98079894 defer error_set_type_gop.deinit();
98089895 error_set_type_gop.putTentative(error_set_type);
9809 var func_ty_gop = try ip.getOrPutKey(gpa, tid, .{
9896 var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{
98109897 .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index),
98119898 });
98129899 defer func_ty_gop.deinit();
......@@ -9814,6 +9901,7 @@ pub fn getFuncInstanceIes(
98149901 try finishFuncInstance(
98159902 ip,
98169903 gpa,
9904 io,
98179905 tid,
98189906 extra,
98199907 generic_owner,
......@@ -9831,6 +9919,7 @@ pub fn getFuncInstanceIes(
98319919fn finishFuncInstance(
98329920 ip: *InternPool,
98339921 gpa: Allocator,
9922 io: Io,
98349923 tid: Zcu.PerThread.Id,
98359924 extra: Local.Extra.Mutable,
98369925 generic_owner: Index,
......@@ -9841,12 +9930,12 @@ fn finishFuncInstance(
98419930 const fn_namespace = fn_owner_nav.analysis.?.namespace;
98429931
98439932 // TODO: improve this name
9844 const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{f}__anon_{d}", .{
9933 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{
98459934 fn_owner_nav.name.fmt(ip), @intFromEnum(func_index),
98469935 }, .no_embedded_nulls);
9847 const nav_index = try ip.createNav(gpa, tid, .{
9936 const nav_index = try ip.createNav(gpa, io, tid, .{
98489937 .name = nav_name,
9849 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
9938 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name),
98509939 .val = func_index,
98519940 .is_const = fn_owner_nav.status.fully_resolved.is_const,
98529941 .alignment = fn_owner_nav.status.fully_resolved.alignment,
......@@ -9967,6 +10056,7 @@ pub const WipEnumType = struct {
996710056pub fn getEnumType(
996810057 ip: *InternPool,
996910058 gpa: Allocator,
10059 io: Io,
997010060 tid: Zcu.PerThread.Id,
997110061 ini: EnumTypeInit,
997210062 /// If it is known that there is an existing type with this key which is outdated,
......@@ -9988,18 +10078,18 @@ pub fn getEnumType(
998810078 } },
998910079 } };
999010080 var gop = if (replace_existing)
9991 ip.putKeyReplace(tid, key)
10081 ip.putKeyReplace(io, tid, key)
999210082 else
9993 try ip.getOrPutKey(gpa, tid, key);
10083 try ip.getOrPutKey(gpa, io, tid, key);
999410084 defer gop.deinit();
999510085 if (gop == .existing) return .{ .existing = gop.existing };
999610086
999710087 const local = ip.getLocal(tid);
9998 const items = local.getMutableItems(gpa);
10088 const items = local.getMutableItems(gpa, io);
999910089 try items.ensureUnusedCapacity(1);
10000 const extra = local.getMutableExtra(gpa);
10090 const extra = local.getMutableExtra(gpa, io);
1000110091
10002 const names_map = try ip.addMap(gpa, tid, ini.fields_len);
10092 const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);
1000310093 errdefer local.mutate.maps.len -= 1;
1000410094
1000510095 switch (ini.tag_mode) {
......@@ -10056,7 +10146,7 @@ pub fn getEnumType(
1005610146 },
1005710147 .explicit, .nonexhaustive => {
1005810148 const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: {
10059 const values_map = try ip.addMap(gpa, tid, ini.fields_len);
10149 const values_map = try ip.addMap(gpa, io, tid, ini.fields_len);
1006010150 break :m values_map.toOptional();
1006110151 };
1006210152 errdefer if (ini.has_values) {
......@@ -10141,6 +10231,7 @@ const GeneratedTagEnumTypeInit = struct {
1014110231pub fn getGeneratedTagEnumType(
1014210232 ip: *InternPool,
1014310233 gpa: Allocator,
10234 io: Io,
1014410235 tid: Zcu.PerThread.Id,
1014510236 ini: GeneratedTagEnumTypeInit,
1014610237) Allocator.Error!Index {
......@@ -10149,11 +10240,11 @@ pub fn getGeneratedTagEnumType(
1014910240 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
1015010241
1015110242 const local = ip.getLocal(tid);
10152 const items = local.getMutableItems(gpa);
10243 const items = local.getMutableItems(gpa, io);
1015310244 try items.ensureUnusedCapacity(1);
10154 const extra = local.getMutableExtra(gpa);
10245 const extra = local.getMutableExtra(gpa, io);
1015510246
10156 const names_map = try ip.addMap(gpa, tid, ini.names.len);
10247 const names_map = try ip.addMap(gpa, io, tid, ini.names.len);
1015710248 errdefer local.mutate.maps.len -= 1;
1015810249 ip.addStringsToMap(names_map, ini.names);
1015910250
......@@ -10165,7 +10256,7 @@ pub fn getGeneratedTagEnumType(
1016510256 .index = items.mutate.len,
1016610257 }, ip);
1016710258 const parent_namespace = ip.namespacePtr(ini.parent_namespace);
10168 const namespace = try ip.createNamespace(gpa, tid, .{
10259 const namespace = try ip.createNamespace(gpa, io, tid, .{
1016910260 .parent = ini.parent_namespace.toOptional(),
1017010261 .owner_type = enum_index,
1017110262 .file_scope = parent_namespace.file_scope,
......@@ -10202,7 +10293,7 @@ pub fn getGeneratedTagEnumType(
1020210293 ini.values.len); // field values
1020310294
1020410295 const values_map: OptionalMapIndex = if (ini.values.len != 0) m: {
10205 const map = try ip.addMap(gpa, tid, ini.values.len);
10296 const map = try ip.addMap(gpa, io, tid, ini.values.len);
1020610297 ip.addIndexesToMap(map, ini.values);
1020710298 break :m map.toOptional();
1020810299 } else .none;
......@@ -10240,7 +10331,7 @@ pub fn getGeneratedTagEnumType(
1024010331 },
1024110332 };
1024210333
10243 var gop = try ip.getOrPutKey(gpa, tid, .{ .enum_type = .{
10334 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{
1024410335 .generated_tag = .{ .union_type = ini.owner_union_ty },
1024510336 } });
1024610337 defer gop.deinit();
......@@ -10256,10 +10347,11 @@ pub const OpaqueTypeInit = struct {
1025610347pub fn getOpaqueType(
1025710348 ip: *InternPool,
1025810349 gpa: Allocator,
10350 io: Io,
1025910351 tid: Zcu.PerThread.Id,
1026010352 ini: OpaqueTypeInit,
1026110353) Allocator.Error!WipNamespaceType.Result {
10262 var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = .{ .declared = .{
10354 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
1026310355 .zir_index = ini.zir_index,
1026410356 .captures = .{ .external = ini.captures },
1026510357 } } });
......@@ -10267,8 +10359,8 @@ pub fn getOpaqueType(
1026710359 if (gop == .existing) return .{ .existing = gop.existing };
1026810360
1026910361 const local = ip.getLocal(tid);
10270 const items = local.getMutableItems(gpa);
10271 const extra = local.getMutableExtra(gpa);
10362 const items = local.getMutableItems(gpa, io);
10363 const extra = local.getMutableExtra(gpa, io);
1027210364 try items.ensureUnusedCapacity(1);
1027310365
1027410366 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
......@@ -10338,8 +10430,8 @@ fn addIndexesToMap(
1033810430 }
1033910431}
1034010432
10341fn addMap(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {
10342 const maps = ip.getLocal(tid).getMutableMaps(gpa);
10433fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {
10434 const maps = ip.getLocal(tid).getMutableMaps(gpa, io);
1034310435 const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len };
1034410436 const ptr = try maps.addOne();
1034510437 errdefer maps.mutate.len = unwrapped.index;
......@@ -10373,14 +10465,15 @@ pub fn remove(ip: *InternPool, tid: Zcu.PerThread.Id, index: Index) void {
1037310465fn addInt(
1037410466 ip: *InternPool,
1037510467 gpa: Allocator,
10468 io: Io,
1037610469 tid: Zcu.PerThread.Id,
1037710470 ty: Index,
1037810471 tag: Tag,
1037910472 limbs: []const Limb,
1038010473) !void {
1038110474 const local = ip.getLocal(tid);
10382 const items_list = local.getMutableItems(gpa);
10383 const limbs_list = local.getMutableLimbs(gpa);
10475 const items_list = local.getMutableItems(gpa, io);
10476 const limbs_list = local.getMutableLimbs(gpa, io);
1038410477 const limbs_len: u32 = @intCast(limbs.len);
1038510478 try limbs_list.ensureUnusedCapacity(Int.limbs_items_len + limbs_len);
1038610479 items_list.appendAssumeCapacity(.{
......@@ -10510,28 +10603,29 @@ fn extraData(extra: Local.Extra, comptime T: type, index: u32) T {
1051010603
1051110604test "basic usage" {
1051210605 const gpa = std.testing.allocator;
10606 const io = std.testing.io;
1051310607
1051410608 var ip: InternPool = .empty;
10515 try ip.init(gpa, 1);
10516 defer ip.deinit(gpa);
10609 try ip.init(gpa, io, 1);
10610 defer ip.deinit(gpa, io);
1051710611
10518 const i32_type = try ip.get(gpa, .main, .{ .int_type = .{
10612 const i32_type = try ip.get(gpa, io, .main, .{ .int_type = .{
1051910613 .signedness = .signed,
1052010614 .bits = 32,
1052110615 } });
10522 const array_i32 = try ip.get(gpa, .main, .{ .array_type = .{
10616 const array_i32 = try ip.get(gpa, io, .main, .{ .array_type = .{
1052310617 .len = 10,
1052410618 .child = i32_type,
1052510619 .sentinel = .none,
1052610620 } });
1052710621
10528 const another_i32_type = try ip.get(gpa, .main, .{ .int_type = .{
10622 const another_i32_type = try ip.get(gpa, io, .main, .{ .int_type = .{
1052910623 .signedness = .signed,
1053010624 .bits = 32,
1053110625 } });
1053210626 try std.testing.expect(another_i32_type == i32_type);
1053310627
10534 const another_array_i32 = try ip.get(gpa, .main, .{ .array_type = .{
10628 const another_array_i32 = try ip.get(gpa, io, .main, .{ .array_type = .{
1053510629 .len = 10,
1053610630 .child = i32_type,
1053710631 .sentinel = .none,
......@@ -10608,6 +10702,7 @@ pub fn sliceLen(ip: *const InternPool, index: Index) Index {
1060810702pub fn getCoerced(
1060910703 ip: *InternPool,
1061010704 gpa: Allocator,
10705 io: Io,
1061110706 tid: Zcu.PerThread.Id,
1061210707 val: Index,
1061310708 new_ty: Index,
......@@ -10616,22 +10711,22 @@ pub fn getCoerced(
1061610711 if (old_ty == new_ty) return val;
1061710712
1061810713 switch (val) {
10619 .undef => return ip.get(gpa, tid, .{ .undef = new_ty }),
10714 .undef => return ip.get(gpa, io, tid, .{ .undef = new_ty }),
1062010715 .null_value => {
10621 if (ip.isOptionalType(new_ty)) return ip.get(gpa, tid, .{ .opt = .{
10716 if (ip.isOptionalType(new_ty)) return ip.get(gpa, io, tid, .{ .opt = .{
1062210717 .ty = new_ty,
1062310718 .val = .none,
1062410719 } });
1062510720
1062610721 if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
10627 .one, .many, .c => return ip.get(gpa, tid, .{ .ptr = .{
10722 .one, .many, .c => return ip.get(gpa, io, tid, .{ .ptr = .{
1062810723 .ty = new_ty,
1062910724 .base_addr = .int,
1063010725 .byte_offset = 0,
1063110726 } }),
10632 .slice => return ip.get(gpa, tid, .{ .slice = .{
10727 .slice => return ip.get(gpa, io, tid, .{ .slice = .{
1063310728 .ty = new_ty,
10634 .ptr = try ip.get(gpa, tid, .{ .ptr = .{
10729 .ptr = try ip.get(gpa, io, tid, .{ .ptr = .{
1063510730 .ty = ip.slicePtrType(new_ty),
1063610731 .base_addr = .int,
1063710732 .byte_offset = 0,
......@@ -10644,15 +10739,15 @@ pub fn getCoerced(
1064410739 const unwrapped_val = val.unwrap(ip);
1064510740 const val_item = unwrapped_val.getItem(ip);
1064610741 switch (val_item.tag) {
10647 .func_decl => return getCoercedFuncDecl(ip, gpa, tid, val, new_ty),
10648 .func_instance => return getCoercedFuncInstance(ip, gpa, tid, val, new_ty),
10742 .func_decl => return getCoercedFuncDecl(ip, gpa, io, tid, val, new_ty),
10743 .func_instance => return getCoercedFuncInstance(ip, gpa, io, tid, val, new_ty),
1064910744 .func_coerced => {
1065010745 const func: Index = @enumFromInt(unwrapped_val.getExtra(ip).view().items(.@"0")[
1065110746 val_item.data + std.meta.fieldIndex(Tag.FuncCoerced, "func").?
1065210747 ]);
1065310748 switch (func.unwrap(ip).getTag(ip)) {
10654 .func_decl => return getCoercedFuncDecl(ip, gpa, tid, val, new_ty),
10655 .func_instance => return getCoercedFuncInstance(ip, gpa, tid, val, new_ty),
10749 .func_decl => return getCoercedFuncDecl(ip, gpa, io, tid, val, new_ty),
10750 .func_instance => return getCoercedFuncInstance(ip, gpa, io, tid, val, new_ty),
1065610751 else => unreachable,
1065710752 }
1065810753 },
......@@ -10662,16 +10757,16 @@ pub fn getCoerced(
1066210757 }
1066310758
1066410759 switch (ip.indexToKey(val)) {
10665 .undef => return ip.get(gpa, tid, .{ .undef = new_ty }),
10760 .undef => return ip.get(gpa, io, tid, .{ .undef = new_ty }),
1066610761 .func => unreachable,
1066710762
1066810763 .int => |int| switch (ip.indexToKey(new_ty)) {
10669 .enum_type => return ip.get(gpa, tid, .{ .enum_tag = .{
10764 .enum_type => return ip.get(gpa, io, tid, .{ .enum_tag = .{
1067010765 .ty = new_ty,
10671 .int = try ip.getCoerced(gpa, tid, val, ip.loadEnumType(new_ty).tag_ty),
10766 .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).tag_ty),
1067210767 } }),
1067310768 .ptr_type => switch (int.storage) {
10674 inline .u64, .i64 => |int_val| return ip.get(gpa, tid, .{ .ptr = .{
10769 inline .u64, .i64 => |int_val| return ip.get(gpa, io, tid, .{ .ptr = .{
1067510770 .ty = new_ty,
1067610771 .base_addr = .int,
1067710772 .byte_offset = @intCast(int_val),
......@@ -10680,7 +10775,7 @@ pub fn getCoerced(
1068010775 .lazy_align, .lazy_size => {},
1068110776 },
1068210777 else => if (ip.isIntegerType(new_ty))
10683 return ip.getCoercedInts(gpa, tid, int, new_ty),
10778 return ip.getCoercedInts(gpa, io, tid, int, new_ty),
1068410779 },
1068510780 .float => |float| switch (ip.indexToKey(new_ty)) {
1068610781 .simple_type => |simple| switch (simple) {
......@@ -10691,7 +10786,7 @@ pub fn getCoerced(
1069110786 .f128,
1069210787 .c_longdouble,
1069310788 .comptime_float,
10694 => return ip.get(gpa, tid, .{ .float = .{
10789 => return ip.get(gpa, io, tid, .{ .float = .{
1069510790 .ty = new_ty,
1069610791 .storage = float.storage,
1069710792 } }),
......@@ -10700,17 +10795,17 @@ pub fn getCoerced(
1070010795 else => {},
1070110796 },
1070210797 .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
10703 return ip.getCoercedInts(gpa, tid, ip.indexToKey(enum_tag.int).int, new_ty),
10798 return ip.getCoercedInts(gpa, io, tid, ip.indexToKey(enum_tag.int).int, new_ty),
1070410799 .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
1070510800 .enum_type => {
1070610801 const enum_type = ip.loadEnumType(new_ty);
1070710802 const index = enum_type.nameIndex(ip, enum_literal).?;
10708 return ip.get(gpa, tid, .{ .enum_tag = .{
10803 return ip.get(gpa, io, tid, .{ .enum_tag = .{
1070910804 .ty = new_ty,
1071010805 .int = if (enum_type.values.len != 0)
1071110806 enum_type.values.get(ip)[index]
1071210807 else
10713 try ip.get(gpa, tid, .{ .int = .{
10808 try ip.get(gpa, io, tid, .{ .int = .{
1071410809 .ty = enum_type.tag_ty,
1071510810 .storage = .{ .u64 = index },
1071610811 } }),
......@@ -10719,22 +10814,22 @@ pub fn getCoerced(
1071910814 else => {},
1072010815 },
1072110816 .slice => |slice| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size == .slice)
10722 return ip.get(gpa, tid, .{ .slice = .{
10817 return ip.get(gpa, io, tid, .{ .slice = .{
1072310818 .ty = new_ty,
10724 .ptr = try ip.getCoerced(gpa, tid, slice.ptr, ip.slicePtrType(new_ty)),
10819 .ptr = try ip.getCoerced(gpa, io, tid, slice.ptr, ip.slicePtrType(new_ty)),
1072510820 .len = slice.len,
1072610821 } })
1072710822 else if (ip.isIntegerType(new_ty))
10728 return ip.getCoerced(gpa, tid, slice.ptr, new_ty),
10823 return ip.getCoerced(gpa, io, tid, slice.ptr, new_ty),
1072910824 .ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .slice)
10730 return ip.get(gpa, tid, .{ .ptr = .{
10825 return ip.get(gpa, io, tid, .{ .ptr = .{
1073110826 .ty = new_ty,
1073210827 .base_addr = ptr.base_addr,
1073310828 .byte_offset = ptr.byte_offset,
1073410829 } })
1073510830 else if (ip.isIntegerType(new_ty))
1073610831 switch (ptr.base_addr) {
10737 .int => return ip.get(gpa, tid, .{ .int = .{
10832 .int => return ip.get(gpa, io, tid, .{ .int = .{
1073810833 .ty = .usize_type,
1073910834 .storage = .{ .u64 = @intCast(ptr.byte_offset) },
1074010835 } }),
......@@ -10743,14 +10838,14 @@ pub fn getCoerced(
1074310838 .opt => |opt| switch (ip.indexToKey(new_ty)) {
1074410839 .ptr_type => |ptr_type| return switch (opt.val) {
1074510840 .none => switch (ptr_type.flags.size) {
10746 .one, .many, .c => try ip.get(gpa, tid, .{ .ptr = .{
10841 .one, .many, .c => try ip.get(gpa, io, tid, .{ .ptr = .{
1074710842 .ty = new_ty,
1074810843 .base_addr = .int,
1074910844 .byte_offset = 0,
1075010845 } }),
10751 .slice => try ip.get(gpa, tid, .{ .slice = .{
10846 .slice => try ip.get(gpa, io, tid, .{ .slice = .{
1075210847 .ty = new_ty,
10753 .ptr = try ip.get(gpa, tid, .{ .ptr = .{
10848 .ptr = try ip.get(gpa, io, tid, .{ .ptr = .{
1075410849 .ty = ip.slicePtrType(new_ty),
1075510850 .base_addr = .int,
1075610851 .byte_offset = 0,
......@@ -10758,29 +10853,29 @@ pub fn getCoerced(
1075810853 .len = .undef_usize,
1075910854 } }),
1076010855 },
10761 else => |payload| try ip.getCoerced(gpa, tid, payload, new_ty),
10856 else => |payload| try ip.getCoerced(gpa, io, tid, payload, new_ty),
1076210857 },
10763 .opt_type => |child_type| return try ip.get(gpa, tid, .{ .opt = .{
10858 .opt_type => |child_type| return try ip.get(gpa, io, tid, .{ .opt = .{
1076410859 .ty = new_ty,
1076510860 .val = switch (opt.val) {
1076610861 .none => .none,
10767 else => try ip.getCoerced(gpa, tid, opt.val, child_type),
10862 else => try ip.getCoerced(gpa, io, tid, opt.val, child_type),
1076810863 },
1076910864 } }),
1077010865 else => {},
1077110866 },
1077210867 .err => |err| if (ip.isErrorSetType(new_ty))
10773 return ip.get(gpa, tid, .{ .err = .{
10868 return ip.get(gpa, io, tid, .{ .err = .{
1077410869 .ty = new_ty,
1077510870 .name = err.name,
1077610871 } })
1077710872 else if (ip.isErrorUnionType(new_ty))
10778 return ip.get(gpa, tid, .{ .error_union = .{
10873 return ip.get(gpa, io, tid, .{ .error_union = .{
1077910874 .ty = new_ty,
1078010875 .val = .{ .err_name = err.name },
1078110876 } }),
1078210877 .error_union => |error_union| if (ip.isErrorUnionType(new_ty))
10783 return ip.get(gpa, tid, .{ .error_union = .{
10878 return ip.get(gpa, io, tid, .{ .error_union = .{
1078410879 .ty = new_ty,
1078510880 .val = error_union.val,
1078610881 } }),
......@@ -10799,20 +10894,20 @@ pub fn getCoerced(
1079910894 };
1080010895 if (old_ty_child != new_ty_child) break :direct;
1080110896 switch (aggregate.storage) {
10802 .bytes => |bytes| return ip.get(gpa, tid, .{ .aggregate = .{
10897 .bytes => |bytes| return ip.get(gpa, io, tid, .{ .aggregate = .{
1080310898 .ty = new_ty,
1080410899 .storage = .{ .bytes = bytes },
1080510900 } }),
1080610901 .elems => |elems| {
1080710902 const elems_copy = try gpa.dupe(Index, elems[0..new_len]);
1080810903 defer gpa.free(elems_copy);
10809 return ip.get(gpa, tid, .{ .aggregate = .{
10904 return ip.get(gpa, io, tid, .{ .aggregate = .{
1081010905 .ty = new_ty,
1081110906 .storage = .{ .elems = elems_copy },
1081210907 } });
1081310908 },
1081410909 .repeated_elem => |elem| {
10815 return ip.get(gpa, tid, .{ .aggregate = .{
10910 return ip.get(gpa, io, tid, .{ .aggregate = .{
1081610911 .ty = new_ty,
1081710912 .storage = .{ .repeated_elem = elem },
1081810913 } });
......@@ -10830,7 +10925,7 @@ pub fn getCoerced(
1083010925 // We have to intern each value here, so unfortunately we can't easily avoid
1083110926 // the repeated indexToKey calls.
1083210927 for (agg_elems, 0..) |*elem, index| {
10833 elem.* = try ip.get(gpa, tid, .{ .int = .{
10928 elem.* = try ip.get(gpa, io, tid, .{ .int = .{
1083410929 .ty = .u8_type,
1083510930 .storage = .{ .u64 = bytes.at(index, ip) },
1083610931 } });
......@@ -10847,27 +10942,27 @@ pub fn getCoerced(
1084710942 .struct_type => ip.loadStructType(new_ty).field_types.get(ip)[i],
1084810943 else => unreachable,
1084910944 };
10850 elem.* = try ip.getCoerced(gpa, tid, elem.*, new_elem_ty);
10945 elem.* = try ip.getCoerced(gpa, io, tid, elem.*, new_elem_ty);
1085110946 }
10852 return ip.get(gpa, tid, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });
10947 return ip.get(gpa, io, tid, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });
1085310948 },
1085410949 else => {},
1085510950 }
1085610951
1085710952 switch (ip.indexToKey(new_ty)) {
1085810953 .opt_type => |child_type| switch (val) {
10859 .null_value => return ip.get(gpa, tid, .{ .opt = .{
10954 .null_value => return ip.get(gpa, io, tid, .{ .opt = .{
1086010955 .ty = new_ty,
1086110956 .val = .none,
1086210957 } }),
10863 else => return ip.get(gpa, tid, .{ .opt = .{
10958 else => return ip.get(gpa, io, tid, .{ .opt = .{
1086410959 .ty = new_ty,
10865 .val = try ip.getCoerced(gpa, tid, val, child_type),
10960 .val = try ip.getCoerced(gpa, io, tid, val, child_type),
1086610961 } }),
1086710962 },
10868 .error_union_type => |error_union_type| return ip.get(gpa, tid, .{ .error_union = .{
10963 .error_union_type => |error_union_type| return ip.get(gpa, io, tid, .{ .error_union = .{
1086910964 .ty = new_ty,
10870 .val = .{ .payload = try ip.getCoerced(gpa, tid, val, error_union_type.payload_type) },
10965 .val = .{ .payload = try ip.getCoerced(gpa, io, tid, val, error_union_type.payload_type) },
1087110966 } }),
1087210967 else => {},
1087310968 }
......@@ -10884,6 +10979,7 @@ pub fn getCoerced(
1088410979fn getCoercedFuncDecl(
1088510980 ip: *InternPool,
1088610981 gpa: Allocator,
10982 io: Io,
1088710983 tid: Zcu.PerThread.Id,
1088810984 val: Index,
1088910985 new_ty: Index,
......@@ -10893,12 +10989,13 @@ fn getCoercedFuncDecl(
1089310989 unwrapped_val.getData(ip) + std.meta.fieldIndex(Tag.FuncDecl, "ty").?
1089410990 ]);
1089510991 if (new_ty == prev_ty) return val;
10896 return getCoercedFunc(ip, gpa, tid, val, new_ty);
10992 return getCoercedFunc(ip, gpa, io, tid, val, new_ty);
1089710993}
1089810994
1089910995fn getCoercedFuncInstance(
1090010996 ip: *InternPool,
1090110997 gpa: Allocator,
10998 io: Io,
1090210999 tid: Zcu.PerThread.Id,
1090311000 val: Index,
1090411001 new_ty: Index,
......@@ -10908,20 +11005,21 @@ fn getCoercedFuncInstance(
1090811005 unwrapped_val.getData(ip) + std.meta.fieldIndex(Tag.FuncInstance, "ty").?
1090911006 ]);
1091011007 if (new_ty == prev_ty) return val;
10911 return getCoercedFunc(ip, gpa, tid, val, new_ty);
11008 return getCoercedFunc(ip, gpa, io, tid, val, new_ty);
1091211009}
1091311010
1091411011fn getCoercedFunc(
1091511012 ip: *InternPool,
1091611013 gpa: Allocator,
11014 io: Io,
1091711015 tid: Zcu.PerThread.Id,
1091811016 func: Index,
1091911017 ty: Index,
1092011018) Allocator.Error!Index {
1092111019 const local = ip.getLocal(tid);
10922 const items = local.getMutableItems(gpa);
11020 const items = local.getMutableItems(gpa, io);
1092311021 try items.ensureUnusedCapacity(1);
10924 const extra = local.getMutableExtra(gpa);
11022 const extra = local.getMutableExtra(gpa, io);
1092511023
1092611024 const prev_extra_len = extra.mutate.len;
1092711025 try extra.ensureUnusedCapacity(@typeInfo(Tag.FuncCoerced).@"struct".fields.len);
......@@ -10932,7 +11030,7 @@ fn getCoercedFunc(
1093211030 });
1093311031 errdefer extra.mutate.len = prev_extra_len;
1093411032
10935 var gop = try ip.getOrPutKey(gpa, tid, .{
11033 var gop = try ip.getOrPutKey(gpa, io, tid, .{
1093611034 .func = ip.extraFuncCoerced(extra.list.*, extra_index),
1093711035 });
1093811036 defer gop.deinit();
......@@ -10950,8 +11048,15 @@ fn getCoercedFunc(
1095011048
1095111049/// Asserts `val` has an integer type.
1095211050/// Assumes `new_ty` is an integer type.
10953pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, int: Key.Int, new_ty: Index) Allocator.Error!Index {
10954 return ip.get(gpa, tid, .{ .int = .{
11051pub fn getCoercedInts(
11052 ip: *InternPool,
11053 gpa: Allocator,
11054 io: Io,
11055 tid: Zcu.PerThread.Id,
11056 int: Key.Int,
11057 new_ty: Index,
11058) Allocator.Error!Index {
11059 return ip.get(gpa, io, tid, .{ .int = .{
1095511060 .ty = new_ty,
1095611061 .storage = int.storage,
1095711062 } });
......@@ -11047,12 +11152,12 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
1104711152}
1104811153
1104911154/// The is only legal because the initializer is not part of the hash.
11050pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void {
11155pub fn mutateVarInit(ip: *InternPool, io: Io, index: Index, init_index: Index) void {
1105111156 const unwrapped_index = index.unwrap(ip);
1105211157
1105311158 const local = ip.getLocal(unwrapped_index.tid);
11054 local.mutate.extra.mutex.lock();
11055 defer local.mutate.extra.mutex.unlock();
11159 local.mutate.extra.mutex.lockUncancelable(io);
11160 defer local.mutate.extra.mutex.unlock(io);
1105611161
1105711162 const extra_items = local.shared.extra.view().items(.@"0");
1105811163 const item = unwrapped_index.getItem(ip);
......@@ -11508,11 +11613,12 @@ pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Names
1150811613pub fn createComptimeUnit(
1150911614 ip: *InternPool,
1151011615 gpa: Allocator,
11616 io: Io,
1151111617 tid: Zcu.PerThread.Id,
1151211618 zir_index: TrackedInst.Index,
1151311619 namespace: NamespaceIndex,
1151411620) Allocator.Error!ComptimeUnit.Id {
11515 const comptime_units = ip.getLocal(tid).getMutableComptimeUnits(gpa);
11621 const comptime_units = ip.getLocal(tid).getMutableComptimeUnits(gpa, io);
1151611622 const id_unwrapped: ComptimeUnit.Id.Unwrapped = .{
1151711623 .tid = tid,
1151811624 .index = comptime_units.mutate.len,
......@@ -11532,9 +11638,10 @@ pub fn getComptimeUnit(ip: *const InternPool, id: ComptimeUnit.Id) ComptimeUnit
1153211638
1153311639/// Create a `Nav` which does not undergo semantic analysis.
1153411640/// Since it is never analyzed, the `Nav`'s value must be known at creation time.
11535pub fn createNav(
11641fn createNav(
1153611642 ip: *InternPool,
1153711643 gpa: Allocator,
11644 io: Io,
1153811645 tid: Zcu.PerThread.Id,
1153911646 opts: struct {
1154011647 name: NullTerminatedString,
......@@ -11546,7 +11653,7 @@ pub fn createNav(
1154611653 @"addrspace": std.builtin.AddressSpace,
1154711654 },
1154811655) Allocator.Error!Nav.Index {
11549 const navs = ip.getLocal(tid).getMutableNavs(gpa);
11656 const navs = ip.getLocal(tid).getMutableNavs(gpa, io);
1155011657 const index_unwrapped: Nav.Index.Unwrapped = .{
1155111658 .tid = tid,
1155211659 .index = navs.mutate.len,
......@@ -11571,13 +11678,14 @@ pub fn createNav(
1157111678pub fn createDeclNav(
1157211679 ip: *InternPool,
1157311680 gpa: Allocator,
11681 io: Io,
1157411682 tid: Zcu.PerThread.Id,
1157511683 name: NullTerminatedString,
1157611684 fqn: NullTerminatedString,
1157711685 zir_index: TrackedInst.Index,
1157811686 namespace: NamespaceIndex,
1157911687) Allocator.Error!Nav.Index {
11580 const navs = ip.getLocal(tid).getMutableNavs(gpa);
11688 const navs = ip.getLocal(tid).getMutableNavs(gpa, io);
1158111689
1158211690 try navs.ensureUnusedCapacity(1);
1158311691
......@@ -11603,6 +11711,7 @@ pub fn createDeclNav(
1160311711/// If its status is already `resolved`, the old value is discarded.
1160411712pub fn resolveNavType(
1160511713 ip: *InternPool,
11714 io: Io,
1160611715 nav: Nav.Index,
1160711716 resolved: struct {
1160811717 type: InternPool.Index,
......@@ -11617,8 +11726,8 @@ pub fn resolveNavType(
1161711726 const unwrapped = nav.unwrap(ip);
1161811727
1161911728 const local = ip.getLocal(unwrapped.tid);
11620 local.mutate.extra.mutex.lock();
11621 defer local.mutate.extra.mutex.unlock();
11729 local.mutate.extra.mutex.lockUncancelable(io);
11730 defer local.mutate.extra.mutex.unlock(io);
1162211731
1162311732 const navs = local.shared.navs.view();
1162411733
......@@ -11647,6 +11756,7 @@ pub fn resolveNavType(
1164711756/// If its status is already `resolved`, the old value is discarded.
1164811757pub fn resolveNavValue(
1164911758 ip: *InternPool,
11759 io: Io,
1165011760 nav: Nav.Index,
1165111761 resolved: struct {
1165211762 val: InternPool.Index,
......@@ -11659,8 +11769,8 @@ pub fn resolveNavValue(
1165911769 const unwrapped = nav.unwrap(ip);
1166011770
1166111771 const local = ip.getLocal(unwrapped.tid);
11662 local.mutate.extra.mutex.lock();
11663 defer local.mutate.extra.mutex.unlock();
11772 local.mutate.extra.mutex.lockUncancelable(io);
11773 defer local.mutate.extra.mutex.unlock(io);
1166411774
1166511775 const navs = local.shared.navs.view();
1166611776
......@@ -11687,6 +11797,7 @@ pub fn resolveNavValue(
1168711797pub fn createNamespace(
1168811798 ip: *InternPool,
1168911799 gpa: Allocator,
11800 io: Io,
1169011801 tid: Zcu.PerThread.Id,
1169111802 initialization: Zcu.Namespace,
1169211803) Allocator.Error!NamespaceIndex {
......@@ -11700,7 +11811,7 @@ pub fn createNamespace(
1170011811 reused_namespace.* = initialization;
1170111812 return reused_namespace_index;
1170211813 }
11703 const namespaces = local.getMutableNamespaces(gpa);
11814 const namespaces = local.getMutableNamespaces(gpa, io);
1170411815 const last_bucket_len = local.mutate.namespaces.last_bucket_len & Local.namespaces_bucket_mask;
1170511816 if (last_bucket_len == 0) {
1170611817 try namespaces.ensureUnusedCapacity(1);
......@@ -11748,10 +11859,11 @@ pub fn filePtr(ip: *const InternPool, file_index: FileIndex) *Zcu.File {
1174811859pub fn createFile(
1174911860 ip: *InternPool,
1175011861 gpa: Allocator,
11862 io: Io,
1175111863 tid: Zcu.PerThread.Id,
1175211864 file: File,
1175311865) Allocator.Error!FileIndex {
11754 const files = ip.getLocal(tid).getMutableFiles(gpa);
11866 const files = ip.getLocal(tid).getMutableFiles(gpa, io);
1175511867 const file_index_unwrapped: FileIndex.Unwrapped = .{
1175611868 .tid = tid,
1175711869 .index = files.mutate.len,
......@@ -11782,20 +11894,22 @@ const EmbeddedNulls = enum {
1178211894pub fn getOrPutString(
1178311895 ip: *InternPool,
1178411896 gpa: Allocator,
11897 io: Io,
1178511898 tid: Zcu.PerThread.Id,
1178611899 slice: []const u8,
1178711900 comptime embedded_nulls: EmbeddedNulls,
1178811901) Allocator.Error!embedded_nulls.StringType() {
11789 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa);
11902 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa, io);
1179011903 try string_bytes.ensureUnusedCapacity(slice.len + 1);
1179111904 string_bytes.appendSliceAssumeCapacity(.{slice});
1179211905 string_bytes.appendAssumeCapacity(.{0});
11793 return ip.getOrPutTrailingString(gpa, tid, @intCast(slice.len + 1), embedded_nulls);
11906 return ip.getOrPutTrailingString(gpa, io, tid, @intCast(slice.len + 1), embedded_nulls);
1179411907}
1179511908
1179611909pub fn getOrPutStringFmt(
1179711910 ip: *InternPool,
1179811911 gpa: Allocator,
11912 io: Io,
1179911913 tid: Zcu.PerThread.Id,
1180011914 comptime format: []const u8,
1180111915 args: anytype,
......@@ -11804,20 +11918,21 @@ pub fn getOrPutStringFmt(
1180411918 // ensure that references to strings in args do not get invalidated
1180511919 const format_z = format ++ .{0};
1180611920 const len: u32 = @intCast(std.fmt.count(format_z, args));
11807 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa);
11921 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa, io);
1180811922 const slice = try string_bytes.addManyAsSlice(len);
1180911923 assert((std.fmt.bufPrint(slice[0], format_z, args) catch unreachable).len == len);
11810 return ip.getOrPutTrailingString(gpa, tid, len, embedded_nulls);
11924 return ip.getOrPutTrailingString(gpa, io, tid, len, embedded_nulls);
1181111925}
1181211926
1181311927pub fn getOrPutStringOpt(
1181411928 ip: *InternPool,
1181511929 gpa: Allocator,
11930 io: Io,
1181611931 tid: Zcu.PerThread.Id,
1181711932 slice: ?[]const u8,
1181811933 comptime embedded_nulls: EmbeddedNulls,
1181911934) Allocator.Error!embedded_nulls.OptionalStringType() {
11820 const string = try getOrPutString(ip, gpa, tid, slice orelse return .none, embedded_nulls);
11935 const string = try getOrPutString(ip, gpa, io, tid, slice orelse return .none, embedded_nulls);
1182111936 return string.toOptional();
1182211937}
1182311938
......@@ -11825,14 +11940,15 @@ pub fn getOrPutStringOpt(
1182511940pub fn getOrPutTrailingString(
1182611941 ip: *InternPool,
1182711942 gpa: Allocator,
11943 io: Io,
1182811944 tid: Zcu.PerThread.Id,
1182911945 len: u32,
1183011946 comptime embedded_nulls: EmbeddedNulls,
1183111947) Allocator.Error!embedded_nulls.StringType() {
1183211948 const local = ip.getLocal(tid);
11833 const strings = local.getMutableStrings(gpa);
11949 const strings = local.getMutableStrings(gpa, io);
1183411950 try strings.ensureUnusedCapacity(1);
11835 const string_bytes = local.getMutableStringBytes(gpa);
11951 const string_bytes = local.getMutableStringBytes(gpa, io);
1183611952 const start: u32 = @intCast(string_bytes.mutate.len - len);
1183711953 if (len > 0 and string_bytes.view().items(.@"0")[string_bytes.mutate.len - 1] == 0) {
1183811954 string_bytes.mutate.len -= 1;
......@@ -11870,8 +11986,8 @@ pub fn getOrPutTrailingString(
1187011986 string_bytes.shrinkRetainingCapacity(start);
1187111987 return @enumFromInt(@intFromEnum(index));
1187211988 }
11873 shard.mutate.string_map.mutex.lock();
11874 defer shard.mutate.string_map.mutex.unlock();
11989 shard.mutate.string_map.mutex.lock(io, tid);
11990 defer shard.mutate.string_map.mutex.unlock(io);
1187511991 if (map.entries != shard.shared.string_map.entries) {
1187611992 map = shard.shared.string_map;
1187711993 map_mask = map.header().mask();
......@@ -12590,11 +12706,11 @@ pub fn funcAnalysisUnordered(ip: *const InternPool, func: Index) FuncAnalysis {
1259012706 return @atomicLoad(FuncAnalysis, ip.funcAnalysisPtr(func), .unordered);
1259112707}
1259212708
12593pub fn funcSetHasErrorTrace(ip: *InternPool, func: Index, has_error_trace: bool) void {
12709pub fn funcSetHasErrorTrace(ip: *InternPool, io: Io, func: Index, has_error_trace: bool) void {
1259412710 const unwrapped_func = func.unwrap(ip);
1259512711 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
12596 extra_mutex.lock();
12597 defer extra_mutex.unlock();
12712 extra_mutex.lockUncancelable(io);
12713 defer extra_mutex.unlock(io);
1259812714
1259912715 const analysis_ptr = ip.funcAnalysisPtr(func);
1260012716 var analysis = analysis_ptr.*;
......@@ -12602,11 +12718,11 @@ pub fn funcSetHasErrorTrace(ip: *InternPool, func: Index, has_error_trace: bool)
1260212718 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
1260312719}
1260412720
12605pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void {
12721pub fn funcSetDisableInstrumentation(ip: *InternPool, io: Io, func: Index) void {
1260612722 const unwrapped_func = func.unwrap(ip);
1260712723 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
12608 extra_mutex.lock();
12609 defer extra_mutex.unlock();
12724 extra_mutex.lockUncancelable(io);
12725 defer extra_mutex.unlock(io);
1261012726
1261112727 const analysis_ptr = ip.funcAnalysisPtr(func);
1261212728 var analysis = analysis_ptr.*;
......@@ -12614,11 +12730,11 @@ pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void {
1261412730 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
1261512731}
1261612732
12617pub fn funcSetDisableIntrinsics(ip: *InternPool, func: Index) void {
12733pub fn funcSetDisableIntrinsics(ip: *InternPool, io: Io, func: Index) void {
1261812734 const unwrapped_func = func.unwrap(ip);
1261912735 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
12620 extra_mutex.lock();
12621 defer extra_mutex.unlock();
12736 extra_mutex.lockUncancelable(io);
12737 defer extra_mutex.unlock(io);
1262212738
1262312739 const analysis_ptr = ip.funcAnalysisPtr(func);
1262412740 var analysis = analysis_ptr.*;
......@@ -12663,15 +12779,6 @@ pub fn iesFuncIndex(ip: *const InternPool, ies_index: Index) Index {
1266312779 return func_index;
1266412780}
1266512781
12666/// Returns a mutable pointer to the resolved error set type of an inferred
12667/// error set function. The returned pointer is invalidated when anything is
12668/// added to `ip`.
12669fn iesResolvedPtr(ip: *InternPool, ies_index: Index) *Index {
12670 const ies_item = ies_index.getItem(ip);
12671 assert(ies_item.tag == .type_inferred_error_set);
12672 return ip.funcIesResolvedPtr(ies_item.data);
12673}
12674
1267512782/// Returns a mutable pointer to the resolved error set type of an inferred
1267612783/// error set function. The returned pointer is invalidated when anything is
1267712784/// added to `ip`.
......@@ -12706,11 +12813,11 @@ pub fn funcIesResolvedUnordered(ip: *const InternPool, index: Index) Index {
1270612813 return @atomicLoad(Index, ip.funcIesResolvedPtr(index), .unordered);
1270712814}
1270812815
12709pub fn funcSetIesResolved(ip: *InternPool, index: Index, ies: Index) void {
12816pub fn funcSetIesResolved(ip: *InternPool, io: Io, index: Index, ies: Index) void {
1271012817 const unwrapped_func = index.unwrap(ip);
1271112818 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
12712 extra_mutex.lock();
12713 defer extra_mutex.unlock();
12819 extra_mutex.lockUncancelable(io);
12820 defer extra_mutex.unlock(io);
1271412821
1271512822 @atomicStore(Index, ip.funcIesResolvedPtr(index), ies, .release);
1271612823}
......@@ -12777,19 +12884,19 @@ const GlobalErrorSet = struct {
1277712884 } align(std.atomic.cache_line),
1277812885 mutate: struct {
1277912886 names: Local.ListMutate,
12780 map: struct { mutex: std.Thread.Mutex },
12887 map: struct { mutex: Io.Mutex },
1278112888 } align(std.atomic.cache_line),
1278212889
1278312890 const Names = Local.List(struct { NullTerminatedString });
1278412891
1278512892 const empty: GlobalErrorSet = .{
1278612893 .shared = .{
12787 .names = Names.empty,
12788 .map = Shard.Map(GlobalErrorSet.Index).empty,
12894 .names = .empty,
12895 .map = .empty,
1278912896 },
1279012897 .mutate = .{
12791 .names = Local.ListMutate.empty,
12792 .map = .{ .mutex = .{} },
12898 .names = .empty,
12899 .map = .{ .mutex = .init },
1279312900 },
1279412901 };
1279512902
......@@ -12807,6 +12914,7 @@ const GlobalErrorSet = struct {
1280712914 fn getErrorValue(
1280812915 ges: *GlobalErrorSet,
1280912916 gpa: Allocator,
12917 io: Io,
1281012918 arena_state: *std.heap.ArenaAllocator.State,
1281112919 name: NullTerminatedString,
1281212920 ) Allocator.Error!GlobalErrorSet.Index {
......@@ -12825,8 +12933,8 @@ const GlobalErrorSet = struct {
1282512933 if (entry.hash != hash) continue;
1282612934 if (names.view().items(.@"0")[@intFromEnum(index) - 1] == name) return index;
1282712935 }
12828 ges.mutate.map.mutex.lock();
12829 defer ges.mutate.map.mutex.unlock();
12936 ges.mutate.map.mutex.lockUncancelable(io);
12937 defer ges.mutate.map.mutex.unlock(io);
1283012938 if (map.entries != ges.shared.map.entries) {
1283112939 map = ges.shared.map;
1283212940 map_mask = map.header().mask();
......@@ -12842,6 +12950,7 @@ const GlobalErrorSet = struct {
1284212950 }
1284312951 const mutable_names: Names.Mutable = .{
1284412952 .gpa = gpa,
12953 .io = io,
1284512954 .arena = arena_state,
1284612955 .mutate = &ges.mutate.names,
1284712956 .list = &ges.shared.names,
......@@ -12923,10 +13032,11 @@ const GlobalErrorSet = struct {
1292313032pub fn getErrorValue(
1292413033 ip: *InternPool,
1292513034 gpa: Allocator,
13035 io: Io,
1292613036 tid: Zcu.PerThread.Id,
1292713037 name: NullTerminatedString,
1292813038) Allocator.Error!Zcu.ErrorInt {
12929 return @intFromEnum(try ip.global_error_set.getErrorValue(gpa, &ip.getLocal(tid).mutate.arena, name));
13039 return @intFromEnum(try ip.global_error_set.getErrorValue(gpa, io, &ip.getLocal(tid).mutate.arena, name));
1293013040}
1293113041
1293213042pub fn getErrorValueIfExists(ip: *const InternPool, name: NullTerminatedString) ?Zcu.ErrorInt {
src/Sema.zig+466-207
......@@ -853,8 +853,9 @@ pub const Block = struct {
853853
854854 fn trackZir(block: *Block, inst: Zir.Inst.Index) Allocator.Error!InternPool.TrackedInst.Index {
855855 const pt = block.sema.pt;
856 const comp = pt.zcu.comp;
856857 block.sema.code.assertTrackable(inst);
857 return pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
858 return pt.zcu.intern_pool.trackZir(comp.gpa, comp.io, pt.tid, .{
858859 .file = block.getFileScopeIndex(pt.zcu),
859860 .inst = inst,
860861 });
......@@ -1061,7 +1062,7 @@ fn analyzeInlineBody(
10611062 /// The index which a break instruction can target to break from this body.
10621063 break_target: Zir.Inst.Index,
10631064) CompileError!?Air.Inst.Ref {
1064 if (sema.analyzeBodyInner(block, body)) |_| {
1065 if (sema.analyzeBodyInner(block, body)) {
10651066 return null;
10661067 } else |err| switch (err) {
10671068 error.ComptimeBreak => {},
......@@ -1808,7 +1809,7 @@ fn analyzeBodyInner(
18081809 child_block.instructions = block.instructions;
18091810 defer block.instructions = child_block.instructions;
18101811
1811 const break_result: ?BreakResult = if (sema.analyzeBodyInner(&child_block, inline_body)) |_| r: {
1812 const break_result: ?BreakResult = if (sema.analyzeBodyInner(&child_block, inline_body)) r: {
18121813 break :r null;
18131814 } else |err| switch (err) {
18141815 error.ComptimeBreak => brk_res: {
......@@ -1956,7 +1957,7 @@ fn analyzeBodyInner(
19561957 .@"defer" => blk: {
19571958 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"defer";
19581959 const defer_body = sema.code.bodySlice(inst_data.index, inst_data.len);
1959 if (sema.analyzeBodyInner(block, defer_body)) |_| {
1960 if (sema.analyzeBodyInner(block, defer_body)) {
19601961 // The defer terminated noreturn - no more analysis needed.
19611962 break;
19621963 } else |err| switch (err) {
......@@ -1975,7 +1976,7 @@ fn analyzeBodyInner(
19751976 const err_code = try sema.resolveInst(inst_data.err_code);
19761977 try map.ensureSpaceForInstructions(sema.gpa, defer_body);
19771978 map.putAssumeCapacity(extra.remapped_err_code, err_code);
1978 if (sema.analyzeBodyInner(block, defer_body)) |_| {
1979 if (sema.analyzeBodyInner(block, defer_body)) {
19791980 // The defer terminated noreturn - no more analysis needed.
19801981 break;
19811982 } else |err| switch (err) {
......@@ -2205,10 +2206,11 @@ fn analyzeAsType(
22052206
22062207pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
22072208 const pt = sema.pt;
2208 const zcu = pt.zcu;
2209 const comp = zcu.comp;
2210 const gpa = sema.gpa;
2211 const ip = &zcu.intern_pool;
2209 const comp = pt.zcu.comp;
2210 const gpa = comp.gpa;
2211 const io = comp.io;
2212 const ip = &pt.zcu.intern_pool;
2213
22122214 if (!comp.config.any_error_tracing) return;
22132215
22142216 assert(!block.isComptime());
......@@ -2231,12 +2233,12 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
22312233 const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty));
22322234
22332235 // st.instruction_addresses = &addrs;
2234 const instruction_addresses_field_name = try ip.getOrPutString(gpa, pt.tid, "instruction_addresses", .no_embedded_nulls);
2236 const instruction_addresses_field_name = try ip.getOrPutString(gpa, io, pt.tid, "instruction_addresses", .no_embedded_nulls);
22352237 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, instruction_addresses_field_name, src, true);
22362238 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
22372239
22382240 // st.index = 0;
2239 const index_field_name = try ip.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls);
2241 const index_field_name = try ip.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
22402242 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, index_field_name, src, true);
22412243 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
22422244
......@@ -2828,9 +2830,12 @@ fn zirTupleDecl(
28282830 block: *Block,
28292831 extended: Zir.Inst.Extended.InstData,
28302832) CompileError!Air.Inst.Ref {
2831 const gpa = sema.gpa;
28322833 const pt = sema.pt;
28332834 const zcu = pt.zcu;
2835 const comp = zcu.comp;
2836 const gpa = comp.gpa;
2837 const io = comp.io;
2838
28342839 const fields_len = extended.small;
28352840 const extra = sema.code.extraData(Zir.Inst.TupleDecl, extended.operand);
28362841 var extra_index = extra.end;
......@@ -2863,7 +2868,7 @@ fn zirTupleDecl(
28632868 const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);
28642869 const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });
28652870 if (field_init_val.canMutateComptimeVarState(zcu)) {
2866 const field_name = try zcu.intern_pool.getOrPutStringFmt(gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
2871 const field_name = try zcu.intern_pool.getOrPutStringFmt(gpa, io, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
28672872 return sema.failWithContainsReferenceToComptimeVar(block, init_src, field_name, "field default value", field_init_val);
28682873 }
28692874 break :init field_init_val.toIntern();
......@@ -2872,7 +2877,7 @@ fn zirTupleDecl(
28722877 };
28732878 }
28742879
2875 return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{
2880 return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, io, pt.tid, .{
28762881 .types = types,
28772882 .values = inits,
28782883 }));
......@@ -2911,7 +2916,11 @@ fn validateTupleFieldType(
29112916fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
29122917 const pt = sema.pt;
29132918 const zcu = pt.zcu;
2919 const comp = zcu.comp;
2920 const gpa = comp.gpa;
2921 const io = comp.io;
29142922 const ip = &zcu.intern_pool;
2923
29152924 const parent_ty: Type = .fromInterned(zcu.namespacePtr(block.namespace).owner_type);
29162925 const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu);
29172926
......@@ -2934,7 +2943,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
29342943 };
29352944 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
29362945 if (loaded_val.canMutateComptimeVarState(zcu)) {
2937 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2946 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
29382947 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);
29392948 }
29402949 break :capture .{ .@"comptime" = loaded_val.toIntern() };
......@@ -2943,7 +2952,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
29432952 const air_ref = try sema.resolveInst(inst.toRef());
29442953 if (try sema.resolveValueResolveLazy(air_ref)) |val| {
29452954 if (val.canMutateComptimeVarState(zcu)) {
2946 const field_name = try ip.getOrPutString(zcu.gpa, pt.tid, zir_name_slice, .no_embedded_nulls);
2955 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
29472956 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);
29482957 }
29492958 break :capture .{ .@"comptime" = val.toIntern() };
......@@ -2952,7 +2961,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
29522961 }),
29532962 .decl_val => |str| capture: {
29542963 const decl_name = try ip.getOrPutString(
2955 sema.gpa,
2964 gpa,
2965 io,
29562966 pt.tid,
29572967 sema.code.nullTerminatedString(str),
29582968 .no_embedded_nulls,
......@@ -2962,7 +2972,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
29622972 },
29632973 .decl_ref => |str| capture: {
29642974 const decl_name = try ip.getOrPutString(
2965 sema.gpa,
2975 gpa,
2976 io,
29662977 pt.tid,
29672978 sema.code.nullTerminatedString(str),
29682979 .no_embedded_nulls,
......@@ -2984,8 +2995,11 @@ fn zirStructDecl(
29842995) CompileError!Air.Inst.Ref {
29852996 const pt = sema.pt;
29862997 const zcu = pt.zcu;
2987 const gpa = sema.gpa;
2998 const comp = zcu.comp;
2999 const gpa = comp.gpa;
3000 const io = comp.io;
29883001 const ip = &zcu.intern_pool;
3002
29893003 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
29903004 const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
29913005
......@@ -3040,7 +3054,7 @@ fn zirStructDecl(
30403054 .captures = captures,
30413055 } },
30423056 };
3043 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) {
3057 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, struct_init, false)) {
30443058 .existing => |ty| {
30453059 const new_ty = try pt.ensureTypeUpToDate(ty);
30463060
......@@ -3108,7 +3122,9 @@ pub fn createTypeName(
31083122} {
31093123 const pt = sema.pt;
31103124 const zcu = pt.zcu;
3111 const gpa = zcu.gpa;
3125 const comp = zcu.comp;
3126 const gpa = comp.gpa;
3127 const io = comp.io;
31123128 const ip = &zcu.intern_pool;
31133129
31143130 switch (name_strategy) {
......@@ -3158,7 +3174,7 @@ pub fn createTypeName(
31583174
31593175 w.writeByte(')') catch return error.OutOfMemory;
31603176 return .{
3161 .name = try ip.getOrPutString(gpa, pt.tid, aw.written(), .no_embedded_nulls),
3177 .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),
31623178 .nav = .none,
31633179 };
31643180 },
......@@ -3170,7 +3186,7 @@ pub fn createTypeName(
31703186 for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) {
31713187 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
31723188 return .{
3173 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.{s}", .{
3189 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
31743190 block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
31753191 }, .no_embedded_nulls),
31763192 .nav = .none,
......@@ -3193,7 +3209,7 @@ pub fn createTypeName(
31933209 // that builtin from the language, we can consider this.
31943210
31953211 return .{
3196 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}__{s}_{d}", .{
3212 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}__{s}_{d}", .{
31973213 block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index),
31983214 }, .no_embedded_nulls),
31993215 .nav = .none,
......@@ -3211,8 +3227,11 @@ fn zirEnumDecl(
32113227
32123228 const pt = sema.pt;
32133229 const zcu = pt.zcu;
3214 const gpa = sema.gpa;
3230 const comp = zcu.comp;
3231 const gpa = comp.gpa;
3232 const io = comp.io;
32153233 const ip = &zcu.intern_pool;
3234
32163235 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
32173236 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
32183237 var extra_index: usize = extra.end;
......@@ -3281,7 +3300,7 @@ fn zirEnumDecl(
32813300 .captures = captures,
32823301 } },
32833302 };
3284 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) {
3303 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, enum_init, false)) {
32853304 .existing => |ty| {
32863305 const new_ty = try pt.ensureTypeUpToDate(ty);
32873306
......@@ -3380,8 +3399,11 @@ fn zirUnionDecl(
33803399
33813400 const pt = sema.pt;
33823401 const zcu = pt.zcu;
3383 const gpa = sema.gpa;
3402 const comp = zcu.comp;
3403 const gpa = comp.gpa;
3404 const io = comp.io;
33843405 const ip = &zcu.intern_pool;
3406
33853407 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
33863408 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
33873409 var extra_index: usize = extra.end;
......@@ -3438,7 +3460,7 @@ fn zirUnionDecl(
34383460 .captures = captures,
34393461 } },
34403462 };
3441 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) {
3463 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, union_init, false)) {
34423464 .existing => |ty| {
34433465 const new_ty = try pt.ensureTypeUpToDate(ty);
34443466
......@@ -3503,7 +3525,9 @@ fn zirOpaqueDecl(
35033525
35043526 const pt = sema.pt;
35053527 const zcu = pt.zcu;
3506 const gpa = sema.gpa;
3528 const comp = zcu.comp;
3529 const gpa = comp.gpa;
3530 const io = comp.io;
35073531 const ip = &zcu.intern_pool;
35083532
35093533 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
......@@ -3532,7 +3556,7 @@ fn zirOpaqueDecl(
35323556 .zir_index = tracked_inst,
35333557 .captures = captures,
35343558 };
3535 const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) {
3559 const wip_ty = switch (try ip.getOpaqueType(gpa, io, pt.tid, opaque_init)) {
35363560 .existing => |ty| {
35373561 // Make sure we update the namespace if the declaration is re-analyzed, to pick
35383562 // up on e.g. changed comptime decls.
......@@ -3587,7 +3611,10 @@ fn zirErrorSetDecl(
35873611
35883612 const pt = sema.pt;
35893613 const zcu = pt.zcu;
3590 const gpa = sema.gpa;
3614 const comp = zcu.comp;
3615 const gpa = comp.gpa;
3616 const io = comp.io;
3617
35913618 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
35923619 const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
35933620
......@@ -3599,7 +3626,7 @@ fn zirErrorSetDecl(
35993626 while (extra_index < extra_index_end) : (extra_index += 1) {
36003627 const name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
36013628 const name = sema.code.nullTerminatedString(name_index);
3602 const name_ip = try zcu.intern_pool.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
3629 const name_ip = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
36033630 _ = try pt.getErrorValue(name_ip);
36043631 const result = names.getOrPutAssumeCapacity(name_ip);
36053632 assert(!result.found_existing); // verified in AstGen
......@@ -3761,11 +3788,14 @@ fn indexablePtrLen(
37613788) CompileError!Air.Inst.Ref {
37623789 const pt = sema.pt;
37633790 const zcu = pt.zcu;
3791 const comp = zcu.comp;
3792 const gpa = comp.gpa;
3793 const io = comp.io;
37643794 const object_ty = sema.typeOf(object);
37653795 const is_pointer_to = object_ty.isSinglePointer(zcu);
37663796 const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty;
37673797 try sema.checkIndexable(block, src, indexable_ty);
3768 const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls);
3798 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls);
37693799 return sema.fieldVal(block, src, object, field_name, src);
37703800}
37713801
......@@ -3777,13 +3807,16 @@ fn indexablePtrLenOrNone(
37773807) CompileError!Air.Inst.Ref {
37783808 const pt = sema.pt;
37793809 const zcu = pt.zcu;
3810 const comp = zcu.comp;
3811 const gpa = comp.gpa;
3812 const io = comp.io;
37803813 const operand_ty = sema.typeOf(operand);
37813814 try checkMemOperand(sema, block, src, operand_ty);
37823815 switch (operand_ty.ptrSize(zcu)) {
37833816 .many, .c => return .none,
37843817 .one, .slice => {},
37853818 }
3786 const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls);
3819 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls);
37873820 return sema.fieldVal(block, src, operand, field_name, src);
37883821}
37893822
......@@ -3961,6 +3994,9 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
39613994fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index {
39623995 const pt = sema.pt;
39633996 const zcu = pt.zcu;
3997 const comp = zcu.comp;
3998 const gpa = comp.gpa;
3999 const io = comp.io;
39644000
39654001 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
39664002 const ptr_info = alloc_ty.ptrInfo(zcu);
......@@ -4108,7 +4144,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
41084144 };
41094145 const new_ptr_ty = tmp_air.typeOfIndex(air_ptr, &zcu.intern_pool).toIntern();
41104146 const new_ptr = switch (method) {
4111 .same_addr => try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, decl_parent_ptr, new_ptr_ty),
4147 .same_addr => try zcu.intern_pool.getCoerced(gpa, io, pt.tid, decl_parent_ptr, new_ptr_ty),
41124148 .opt_payload => ptr: {
41134149 // Set the optional to non-null at comptime.
41144150 // If the payload is OPV, we must use that value instead of undef.
......@@ -4523,8 +4559,11 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
45234559fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
45244560 const pt = sema.pt;
45254561 const zcu = pt.zcu;
4526 const gpa = sema.gpa;
4562 const comp = zcu.comp;
4563 const gpa = comp.gpa;
4564 const io = comp.io;
45274565 const ip = &zcu.intern_pool;
4566
45284567 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
45294568 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
45304569 const all_args = sema.code.refSlice(extra.end, extra.data.operands_len);
......@@ -4570,7 +4609,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
45704609 return sema.failWithOwnedErrorMsg(block, msg);
45714610 }
45724611 if (!object_ty.indexableHasLen(zcu)) continue;
4573 break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls), arg_src);
4612 break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), arg_src);
45744613 } else l: {
45754614 // This argument is a range.
45764615 const range_start = try sema.resolveInst(zir_arg_pair[0]);
......@@ -4733,6 +4772,10 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
47334772fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
47344773 const pt = sema.pt;
47354774 const zcu = pt.zcu;
4775 const comp = zcu.comp;
4776 const gpa = comp.gpa;
4777 const io = comp.io;
4778
47364779 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
47374780 const src = block.nodeOffset(un_node.src_node);
47384781
......@@ -4758,7 +4801,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo
47584801 // This function cannot return an error.
47594802 // `try` is still valid if the error case is impossible, i.e. no error is returned.
47604803 // So, the result type has an error set of `error{}`.
4761 break :err_set .fromInterned(try zcu.intern_pool.getErrorSetType(zcu.gpa, pt.tid, &.{}));
4804 break :err_set .fromInterned(try zcu.intern_pool.getErrorSetType(gpa, io, pt.tid, &.{}));
47624805 },
47634806 }
47644807 }
......@@ -5003,7 +5046,9 @@ fn validateStructInit(
50035046) CompileError!void {
50045047 const pt = sema.pt;
50055048 const zcu = pt.zcu;
5006 const gpa = sema.gpa;
5049 const comp = zcu.comp;
5050 const gpa = comp.gpa;
5051 const io = comp.io;
50075052 const ip = &zcu.intern_pool;
50085053
50095054 // Tracks whether each field was explicitly initialized.
......@@ -5017,6 +5062,7 @@ fn validateStructInit(
50175062 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
50185063 const field_name = try ip.getOrPutString(
50195064 gpa,
5065 io,
50205066 pt.tid,
50215067 sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
50225068 .no_embedded_nulls,
......@@ -5461,9 +5507,15 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
54615507}
54625508
54635509fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5510 const pt = sema.pt;
5511 const zcu = pt.zcu;
5512 const comp = zcu.comp;
5513 const gpa = comp.gpa;
5514 const io = comp.io;
5515 const ip = &zcu.intern_pool;
54645516 const bytes = sema.code.instructions.items(.data)[@intFromEnum(inst)].str.get(sema.code);
54655517 return sema.addStrLit(
5466 try sema.pt.zcu.intern_pool.getOrPutString(sema.gpa, sema.pt.tid, bytes, .maybe_embedded_nulls),
5518 try ip.getOrPutString(gpa, io, pt.tid, bytes, .maybe_embedded_nulls),
54675519 bytes.len,
54685520 );
54695521}
......@@ -5555,7 +5607,9 @@ fn zirCompileLog(
55555607) CompileError!Air.Inst.Ref {
55565608 const pt = sema.pt;
55575609 const zcu = pt.zcu;
5558 const gpa = zcu.gpa;
5610 const comp = zcu.comp;
5611 const gpa = comp.gpa;
5612 const io = comp.io;
55595613
55605614 var aw: std.Io.Writer.Allocating = .init(gpa);
55615615 defer aw.deinit();
......@@ -5579,7 +5633,7 @@ fn zirCompileLog(
55795633 }
55805634 }
55815635
5582 const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, aw.written(), .no_embedded_nulls);
5636 const line_data = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
55835637
55845638 const line_idx: Zcu.CompileLogLine.Index = if (zcu.free_compile_log_lines.pop()) |idx| idx: {
55855639 zcu.compile_log_lines.items[@intFromEnum(idx)] = .{
......@@ -5757,7 +5811,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
57575811 const pt = sema.pt;
57585812 const zcu = pt.zcu;
57595813 const comp = zcu.comp;
5760 const gpa = sema.gpa;
5814 const gpa = comp.gpa;
5815 const io = comp.io;
5816
57615817 const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
57625818 const src = parent_block.nodeOffset(pl_node.src_node);
57635819 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
......@@ -5846,7 +5902,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
58465902 errdefer c_import_file_path.deinit(gpa);
58475903 const c_import_file = try gpa.create(Zcu.File);
58485904 errdefer gpa.destroy(c_import_file);
5849 const c_import_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
5905 const c_import_file_index = try zcu.intern_pool.createFile(gpa, io, pt.tid, .{
58505906 .bin_digest = c_import_file_path.digest(),
58515907 .file = c_import_file,
58525908 .root_type = .none,
......@@ -5959,7 +6015,7 @@ fn resolveBlockBody(
59596015 assert(sema.air_instructions.items(.tag)[@intFromEnum(merges.block_inst)] == .block);
59606016 var need_debug_scope = false;
59616017 child_block.need_debug_scope = &need_debug_scope;
5962 if (sema.analyzeBodyInner(child_block, body)) |_| {
6018 if (sema.analyzeBodyInner(child_block, body)) {
59636019 return sema.resolveAnalyzedBlock(parent_block, src, child_block, merges, need_debug_scope);
59646020 } else |err| switch (err) {
59656021 error.ComptimeBreak => {
......@@ -6350,6 +6406,7 @@ pub fn analyzeExport(
63506406fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
63516407 const pt = sema.pt;
63526408 const zcu = pt.zcu;
6409 const io = zcu.comp.io;
63536410 const ip = &zcu.intern_pool;
63546411 const func = switch (sema.owner.unwrap()) {
63556412 .func => |func| func,
......@@ -6360,13 +6417,14 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
63606417 .memoized_state,
63616418 => return, // does nothing outside a function
63626419 };
6363 ip.funcSetDisableInstrumentation(func);
6420 ip.funcSetDisableInstrumentation(io, func);
63646421 sema.allow_memoize = false;
63656422}
63666423
63676424fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
63686425 const pt = sema.pt;
63696426 const zcu = pt.zcu;
6427 const io = zcu.comp.io;
63706428 const ip = &zcu.intern_pool;
63716429 const func = switch (sema.owner.unwrap()) {
63726430 .func => |func| func,
......@@ -6377,7 +6435,7 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
63776435 .memoized_state,
63786436 => return, // does nothing outside a function
63796437 };
6380 ip.funcSetDisableIntrinsics(func);
6438 ip.funcSetDisableIntrinsics(io, func);
63816439 sema.allow_memoize = false;
63826440}
63836441
......@@ -6576,10 +6634,15 @@ pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!Air.NullTer
65766634fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
65776635 const pt = sema.pt;
65786636 const zcu = pt.zcu;
6637 const comp = zcu.comp;
6638 const gpa = comp.gpa;
6639 const io = comp.io;
6640
65796641 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
65806642 const src = block.tokenOffset(inst_data.src_tok);
65816643 const decl_name = try zcu.intern_pool.getOrPutString(
6582 sema.gpa,
6644 gpa,
6645 io,
65836646 pt.tid,
65846647 inst_data.get(sema.code),
65856648 .no_embedded_nulls,
......@@ -6591,10 +6654,15 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
65916654fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
65926655 const pt = sema.pt;
65936656 const zcu = pt.zcu;
6657 const comp = zcu.comp;
6658 const gpa = comp.gpa;
6659 const io = comp.io;
6660
65946661 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
65956662 const src = block.tokenOffset(inst_data.src_tok);
65966663 const decl_name = try zcu.intern_pool.getOrPutString(
6597 sema.gpa,
6664 gpa,
6665 io,
65986666 pt.tid,
65996667 inst_data.get(sema.code),
66006668 .no_embedded_nulls,
......@@ -6683,7 +6751,9 @@ fn funcDeclSrcInst(sema: *Sema, func_inst: Air.Inst.Ref) !?InternPool.TrackedIns
66836751pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
66846752 const pt = sema.pt;
66856753 const zcu = pt.zcu;
6686 const gpa = sema.gpa;
6754 const comp = zcu.comp;
6755 const gpa = comp.gpa;
6756 const io = comp.io;
66876757
66886758 if (block.isComptime() or block.is_typeof) {
66896759 const index_val = try pt.intValue_u64(.usize, sema.comptime_err_ret_trace.items.len);
......@@ -6694,7 +6764,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
66946764
66956765 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
66966766 try stack_trace_ty.resolveFields(pt);
6697 const field_name = try zcu.intern_pool.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls);
6767 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
66986768 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
66996769 error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"),
67006770 error.ComptimeReturn, error.ComptimeBreak => unreachable,
......@@ -6721,7 +6791,9 @@ fn popErrorReturnTrace(
67216791) CompileError!void {
67226792 const pt = sema.pt;
67236793 const zcu = pt.zcu;
6724 const gpa = sema.gpa;
6794 const comp = zcu.comp;
6795 const gpa = comp.gpa;
6796 const io = comp.io;
67256797 var is_non_error: ?bool = null;
67266798 var is_non_error_inst: Air.Inst.Ref = undefined;
67276799 if (operand != .none) {
......@@ -6738,7 +6810,7 @@ fn popErrorReturnTrace(
67386810 try stack_trace_ty.resolveFields(pt);
67396811 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
67406812 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
6741 const field_name = try zcu.intern_pool.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls);
6813 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
67426814 const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true);
67436815 try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store);
67446816 } else if (is_non_error == null) {
......@@ -6764,7 +6836,7 @@ fn popErrorReturnTrace(
67646836 try stack_trace_ty.resolveFields(pt);
67656837 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
67666838 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
6767 const field_name = try zcu.intern_pool.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls);
6839 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
67686840 const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true);
67696841 try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store);
67706842 _ = try then_block.addBr(cond_block_inst, .void_value);
......@@ -6818,6 +6890,10 @@ fn zirCall(
68186890
68196891 const pt = sema.pt;
68206892 const zcu = pt.zcu;
6893 const comp = zcu.comp;
6894 const gpa = comp.gpa;
6895 const io = comp.io;
6896
68216897 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
68226898 const callee_src = block.src(.{ .node_offset_call_func = inst_data.src_node });
68236899 const call_src = block.nodeOffset(inst_data.src_node);
......@@ -6837,7 +6913,8 @@ fn zirCall(
68376913 .field => blk: {
68386914 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
68396915 const field_name = try zcu.intern_pool.getOrPutString(
6840 sema.gpa,
6916 gpa,
6917 io,
68416918 pt.tid,
68426919 sema.code.nullTerminatedString(extra.data.field_name_start),
68436920 .no_embedded_nulls,
......@@ -6897,7 +6974,7 @@ fn zirCall(
68976974 if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) {
68986975 const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace);
68996976 try stack_trace_ty.resolveFields(pt);
6900 const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "index", .no_embedded_nulls);
6977 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
69016978 const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
69026979
69036980 // Insert a save instruction before the arg resolution + call instructions we just generated
......@@ -7232,7 +7309,9 @@ fn analyzeCall(
72327309) CompileError!Air.Inst.Ref {
72337310 const pt = sema.pt;
72347311 const zcu = pt.zcu;
7235 const gpa = zcu.gpa;
7312 const comp = zcu.comp;
7313 const gpa = comp.gpa;
7314 const io = comp.io;
72367315 const ip = &zcu.intern_pool;
72377316 const arena = sema.arena;
72387317
......@@ -7544,7 +7623,7 @@ fn analyzeCall(
75447623 if (func_ty_info.cc == .auto) {
75457624 switch (sema.owner.unwrap()) {
75467625 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
7547 .func => |owner_func| ip.funcSetHasErrorTrace(owner_func, true),
7626 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),
75487627 }
75497628 }
75507629 for (args, 0..) |arg, arg_idx| {
......@@ -7596,7 +7675,7 @@ fn analyzeCall(
75967675 } else resolved_ret_ty;
75977676
75987677 // We now need to actually create the function instance.
7599 const func_instance = try ip.getFuncInstance(gpa, pt.tid, .{
7678 const func_instance = try ip.getFuncInstance(gpa, io, pt.tid, .{
76007679 .param_types = runtime_param_tys.items,
76017680 .noalias_bits = noalias_bits,
76027681 .bare_return_type = bare_ret_ty.toIntern(),
......@@ -7614,7 +7693,7 @@ fn analyzeCall(
76147693 // This call is problematic as it breaks guarantees about order-independency of semantic analysis.
76157694 // These guarantees are necessary for incremental compilation and parallel semantic analysis.
76167695 // See: #22410
7617 zcu.funcInfo(func_instance).maxBranchQuota(ip, sema.branch_quota);
7696 zcu.funcInfo(func_instance).maxBranchQuota(ip, io, sema.branch_quota);
76187697
76197698 break :func .{ Air.internedToRef(func_instance), runtime_args.items };
76207699 };
......@@ -8102,6 +8181,9 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
81028181
81038182 const pt = sema.pt;
81048183 const zcu = pt.zcu;
8184 const comp = zcu.comp;
8185 const gpa = comp.gpa;
8186 const io = comp.io;
81058187 const ip = &zcu.intern_pool;
81068188
81078189 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
......@@ -8116,7 +8198,7 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
81168198 const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
81178199 const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel });
81188200 if (sentinel_val.canMutateComptimeVarState(zcu)) {
8119 const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls);
8201 const sentinel_name = try ip.getOrPutString(gpa, io, pt.tid, "sentinel", .no_embedded_nulls);
81208202 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel_val);
81218203 }
81228204 const array_ty = try pt.arrayType(.{
......@@ -8194,10 +8276,17 @@ fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, p
81948276
81958277fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
81968278 _ = block;
8279
81978280 const pt = sema.pt;
8281 const zcu = pt.zcu;
8282 const comp = zcu.comp;
8283 const gpa = comp.gpa;
8284 const io = comp.io;
8285
81988286 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
81998287 const name = try pt.zcu.intern_pool.getOrPutString(
8200 sema.gpa,
8288 gpa,
8289 io,
82018290 pt.tid,
82028291 inst_data.get(sema.code),
82038292 .no_embedded_nulls,
......@@ -8259,7 +8348,9 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
82598348
82608349 const pt = sema.pt;
82618350 const zcu = pt.zcu;
8351 const io = zcu.comp.io;
82628352 const ip = &zcu.intern_pool;
8353
82638354 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
82648355 const src = block.nodeOffset(extra.node);
82658356 const operand_src = block.builtinCallArgSrc(extra.node, 0);
......@@ -8271,8 +8362,8 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
82718362 const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(pt));
82728363 if (int > len: {
82738364 const mutate = &ip.global_error_set.mutate;
8274 mutate.map.mutex.lock();
8275 defer mutate.map.mutex.unlock();
8365 mutate.map.mutex.lockUncancelable(io);
8366 defer mutate.map.mutex.unlock(io);
82768367 break :len mutate.names.len;
82778368 } or int == 0)
82788369 return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
......@@ -8361,10 +8452,14 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
83618452
83628453 const pt = sema.pt;
83638454 const zcu = pt.zcu;
8455 const comp = zcu.comp;
8456 const gpa = comp.gpa;
8457 const io = comp.io;
8458
83648459 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
83658460 const name = inst_data.get(sema.code);
83668461 return Air.internedToRef((try pt.intern(.{
8367 .enum_literal = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, name, .no_embedded_nulls),
8462 .enum_literal = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls),
83688463 })));
83698464}
83708465
......@@ -8374,11 +8469,16 @@ fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: b
83748469
83758470 const pt = sema.pt;
83768471 const zcu = pt.zcu;
8472 const comp = zcu.comp;
8473 const gpa = comp.gpa;
8474 const io = comp.io;
8475
83778476 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
83788477 const src = block.nodeOffset(inst_data.src_node);
83798478 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
83808479 const name = try zcu.intern_pool.getOrPutString(
8381 sema.gpa,
8480 gpa,
8481 io,
83828482 pt.tid,
83838483 sema.code.nullTerminatedString(extra.field_name_start),
83848484 .no_embedded_nulls,
......@@ -8915,7 +9015,11 @@ fn zirFunc(
89159015) CompileError!Air.Inst.Ref {
89169016 const pt = sema.pt;
89179017 const zcu = pt.zcu;
9018 const comp = zcu.comp;
9019 const gpa = comp.gpa;
9020 const io = comp.io;
89189021 const ip = &zcu.intern_pool;
9022
89199023 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
89209024 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
89219025 const target = zcu.getTarget();
......@@ -8970,7 +9074,7 @@ fn zirFunc(
89709074 block,
89719075 LazySrcLoc.unneeded,
89729076 cc_type.getNamespaceIndex(zcu),
8973 try ip.getOrPutString(sema.gpa, pt.tid, "c", .no_embedded_nulls),
9077 try ip.getOrPutString(gpa, io, pt.tid, "c", .no_embedded_nulls),
89749078 );
89759079 // The above should have errored.
89769080 @panic("std.builtin is corrupt");
......@@ -9443,8 +9547,11 @@ fn funcCommon(
94439547) CompileError!Air.Inst.Ref {
94449548 const pt = sema.pt;
94459549 const zcu = pt.zcu;
9446 const gpa = sema.gpa;
9550 const comp = zcu.comp;
9551 const gpa = comp.gpa;
9552 const io = comp.io;
94479553 const ip = &zcu.intern_pool;
9554
94489555 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
94499556 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
94509557 const func_src = block.nodeOffset(src_node_offset);
......@@ -9563,7 +9670,7 @@ fn funcCommon(
95639670
95649671 if (inferred_error_set) {
95659672 assert(has_body);
9566 return .fromIntern(try ip.getFuncDeclIes(gpa, pt.tid, .{
9673 return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
95679674 .owner_nav = sema.owner.unwrap().nav_val,
95689675
95699676 .param_types = param_types,
......@@ -9583,7 +9690,7 @@ fn funcCommon(
95839690 }));
95849691 }
95859692
9586 const func_ty = try ip.getFuncType(gpa, pt.tid, .{
9693 const func_ty = try ip.getFuncType(gpa, io, pt.tid, .{
95879694 .param_types = param_types,
95889695 .noalias_bits = noalias_bits,
95899696 .comptime_bits = comptime_bits,
......@@ -9595,7 +9702,7 @@ fn funcCommon(
95959702 });
95969703
95979704 if (has_body) {
9598 return .fromIntern(try ip.getFuncDecl(gpa, pt.tid, .{
9705 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
95999706 .owner_nav = sema.owner.unwrap().nav_val,
96009707 .ty = func_ty,
96019708 .cc = cc,
......@@ -9778,12 +9885,17 @@ fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
97789885
97799886 const pt = sema.pt;
97809887 const zcu = pt.zcu;
9888 const comp = zcu.comp;
9889 const gpa = comp.gpa;
9890 const io = comp.io;
9891
97819892 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
97829893 const src = block.nodeOffset(inst_data.src_node);
97839894 const field_name_src = block.src(.{ .node_offset_field_name = inst_data.src_node });
97849895 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
97859896 const field_name = try zcu.intern_pool.getOrPutString(
9786 sema.gpa,
9897 gpa,
9898 io,
97879899 pt.tid,
97889900 sema.code.nullTerminatedString(extra.field_name_start),
97899901 .no_embedded_nulls,
......@@ -9798,12 +9910,17 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
97989910
97999911 const pt = sema.pt;
98009912 const zcu = pt.zcu;
9913 const comp = zcu.comp;
9914 const gpa = comp.gpa;
9915 const io = comp.io;
9916
98019917 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
98029918 const src = block.nodeOffset(inst_data.src_node);
98039919 const field_name_src = block.src(.{ .node_offset_field_name = inst_data.src_node });
98049920 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
98059921 const field_name = try zcu.intern_pool.getOrPutString(
9806 sema.gpa,
9922 gpa,
9923 io,
98079924 pt.tid,
98089925 sema.code.nullTerminatedString(extra.field_name_start),
98099926 .no_embedded_nulls,
......@@ -9818,12 +9935,17 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
98189935
98199936 const pt = sema.pt;
98209937 const zcu = pt.zcu;
9938 const comp = zcu.comp;
9939 const gpa = comp.gpa;
9940 const io = comp.io;
9941
98219942 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
98229943 const src = block.nodeOffset(inst_data.src_node);
98239944 const field_name_src = block.src(.{ .node_offset_field_name_init = inst_data.src_node });
98249945 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
98259946 const field_name = try zcu.intern_pool.getOrPutString(
9826 sema.gpa,
9947 gpa,
9948 io,
98279949 pt.tid,
98289950 sema.code.nullTerminatedString(extra.field_name_start),
98299951 .no_embedded_nulls,
......@@ -13941,9 +14063,14 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1394114063fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1394214064 const pt = sema.pt;
1394314065 const zcu = pt.zcu;
14066 const comp = zcu.comp;
14067 const gpa = comp.gpa;
14068 const io = comp.io;
14069
1394414070 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
1394514071 const name = try zcu.intern_pool.getOrPutString(
13946 sema.gpa,
14072 gpa,
14073 io,
1394714074 pt.tid,
1394814075 inst_data.get(sema.code),
1394914076 .no_embedded_nulls,
......@@ -14379,6 +14506,10 @@ fn analyzeTupleCat(
1437914506) CompileError!Air.Inst.Ref {
1438014507 const pt = sema.pt;
1438114508 const zcu = pt.zcu;
14509 const comp = zcu.comp;
14510 const gpa = comp.gpa;
14511 const io = comp.io;
14512
1438214513 const lhs_ty = sema.typeOf(lhs);
1438314514 const rhs_ty = sema.typeOf(rhs);
1438414515 const src = block.nodeOffset(src_node);
......@@ -14434,7 +14565,7 @@ fn analyzeTupleCat(
1443414565 break :rs runtime_src;
1443514566 };
1443614567
14437 const tuple_ty: Type = .fromInterned(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{
14568 const tuple_ty: Type = .fromInterned(try zcu.intern_pool.getTupleType(gpa, io, pt.tid, .{
1443814569 .types = types,
1443914570 .values = values,
1444014571 }));
......@@ -14821,6 +14952,10 @@ fn analyzeTupleMul(
1482114952) CompileError!Air.Inst.Ref {
1482214953 const pt = sema.pt;
1482314954 const zcu = pt.zcu;
14955 const comp = zcu.comp;
14956 const gpa = comp.gpa;
14957 const io = comp.io;
14958
1482414959 const operand_ty = sema.typeOf(operand);
1482514960 const src = block.nodeOffset(src_node);
1482614961 const len_src = block.src(.{ .node_offset_bin_rhs = src_node });
......@@ -14856,7 +14991,7 @@ fn analyzeTupleMul(
1485614991 break :rs runtime_src;
1485714992 };
1485814993
14859 const tuple_ty: Type = .fromInterned(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{
14994 const tuple_ty: Type = .fromInterned(try zcu.intern_pool.getTupleType(gpa, io, pt.tid, .{
1486014995 .types = types,
1486114996 .values = values,
1486214997 }));
......@@ -16388,7 +16523,11 @@ fn zirAsm(
1638816523
1638916524 const pt = sema.pt;
1639016525 const zcu = pt.zcu;
16526 const comp = zcu.comp;
16527 const gpa = comp.gpa;
16528 const io = comp.io;
1639116529 const ip = &zcu.intern_pool;
16530
1639216531 const extra = sema.code.extraData(Zir.Inst.Asm, extended.operand);
1639316532 const src = block.nodeOffset(extra.data.src_node);
1639416533 const ret_ty_src = block.src(.{ .node_offset_asm_ret_ty = extra.data.src_node });
......@@ -16445,7 +16584,7 @@ fn zirAsm(
1644516584 } else {
1644616585 const inst = try sema.resolveInst(output.data.operand);
1644716586 if (!sema.checkRuntimeValue(inst)) {
16448 const output_name = try ip.getOrPutString(sema.gpa, pt.tid, name, .no_embedded_nulls);
16587 const output_name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
1644916588 return sema.failWithContainsReferenceToComptimeVar(block, output_src, output_name, "assembly output", .fromInterned(inst.toInterned().?));
1645016589 }
1645116590 arg.* = inst;
......@@ -16476,7 +16615,7 @@ fn zirAsm(
1647616615 const uncasted_arg = try sema.resolveInst(input.data.operand);
1647716616 const name = sema.code.nullTerminatedString(input.data.name);
1647816617 if (!sema.checkRuntimeValue(uncasted_arg)) {
16479 const input_name = try ip.getOrPutString(sema.gpa, pt.tid, name, .no_embedded_nulls);
16618 const input_name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
1648016619 return sema.failWithContainsReferenceToComptimeVar(block, input_src, input_name, "assembly input", .fromInterned(uncasted_arg.toInterned().?));
1648116620 }
1648216621 const uncasted_arg_ty = sema.typeOf(uncasted_arg);
......@@ -16500,7 +16639,6 @@ fn zirAsm(
1650016639 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
1650116640 needed_capacity += asm_source.len / 4 + 1;
1650216641
16503 const gpa = sema.gpa;
1650416642 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
1650516643 const asm_air = try block.addInst(.{
1650616644 .tag = .assembly,
......@@ -17060,10 +17198,13 @@ fn zirBuiltinSrc(
1706017198
1706117199 const pt = sema.pt;
1706217200 const zcu = pt.zcu;
17201 const comp = zcu.comp;
17202 const gpa = comp.gpa;
17203 const io = comp.io;
1706317204 const ip = &zcu.intern_pool;
17205
1706417206 const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data;
1706517207 const fn_name = ip.getNav(zcu.funcInfo(sema.func_index).owner_nav).name;
17066 const gpa = sema.gpa;
1706717208 const file_scope = block.getFileScope(zcu);
1706817209
1706917210 const func_name_val = v: {
......@@ -17106,7 +17247,7 @@ fn zirBuiltinSrc(
1710617247 .val = try pt.intern(.{ .aggregate = .{
1710717248 .ty = array_ty,
1710817249 .storage = .{
17109 .bytes = try ip.getOrPutString(gpa, pt.tid, module_name, .maybe_embedded_nulls),
17250 .bytes = try ip.getOrPutString(gpa, io, pt.tid, module_name, .maybe_embedded_nulls),
1711017251 },
1711117252 } }),
1711217253 } },
......@@ -17132,7 +17273,7 @@ fn zirBuiltinSrc(
1713217273 .val = try pt.intern(.{ .aggregate = .{
1713317274 .ty = array_ty,
1713417275 .storage = .{
17135 .bytes = try ip.getOrPutString(gpa, pt.tid, file_name, .maybe_embedded_nulls),
17276 .bytes = try ip.getOrPutString(gpa, io, pt.tid, file_name, .maybe_embedded_nulls),
1713617277 },
1713717278 } }),
1713817279 } },
......@@ -17161,8 +17302,11 @@ fn zirBuiltinSrc(
1716117302fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1716217303 const pt = sema.pt;
1716317304 const zcu = pt.zcu;
17164 const gpa = sema.gpa;
17305 const comp = zcu.comp;
17306 const gpa = comp.gpa;
17307 const io = comp.io;
1716517308 const ip = &zcu.intern_pool;
17309
1716617310 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1716717311 const src = block.nodeOffset(inst_data.src_node);
1716817312 const ty = try sema.resolveType(block, src, inst_data.operand);
......@@ -17511,7 +17655,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1751117655 const enum_type = ip.loadEnumType(ty.toIntern());
1751217656 const value_val = if (enum_type.values.len > 0)
1751317657 try ip.getCoercedInts(
17514 zcu.gpa,
17658 gpa,
17659 io,
1751517660 pt.tid,
1751617661 ip.indexToKey(enum_type.values.get(ip)[tag_index]).int,
1751717662 .comptime_int_type,
......@@ -17729,7 +17874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1772917874 const field_ty = tuple_type.types.get(ip)[field_index];
1773017875 const field_val = tuple_type.values.get(ip)[field_index];
1773117876 const name_val = v: {
17732 const field_name = try ip.getOrPutStringFmt(gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
17877 const field_name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
1773317878 const field_name_len = field_name.length(ip);
1773417879 const new_decl_ty = try pt.arrayType(.{
1773517880 .len = field_name_len,
......@@ -18752,10 +18897,15 @@ fn zirRetErrValue(
1875218897) CompileError!void {
1875318898 const pt = sema.pt;
1875418899 const zcu = pt.zcu;
18900 const comp = zcu.comp;
18901 const gpa = comp.gpa;
18902 const io = comp.io;
18903
1875518904 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
1875618905 const src = block.tokenOffset(inst_data.src_tok);
1875718906 const err_name = try zcu.intern_pool.getOrPutString(
18758 sema.gpa,
18907 gpa,
18908 io,
1875918909 pt.tid,
1876018910 inst_data.get(sema.code),
1876118911 .no_embedded_nulls,
......@@ -19121,6 +19271,9 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1912119271
1912219272 const pt = sema.pt;
1912319273 const zcu = pt.zcu;
19274 const comp = zcu.comp;
19275 const gpa = comp.gpa;
19276 const io = comp.io;
1912419277 const ip = &zcu.intern_pool;
1912519278
1912619279 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type;
......@@ -19158,7 +19311,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1915819311 const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ .simple = .pointer_sentinel });
1915919312 try checkSentinelType(sema, block, sentinel_src, elem_ty);
1916019313 if (val.canMutateComptimeVarState(zcu)) {
19161 const sentinel_name = try ip.getOrPutString(sema.gpa, pt.tid, "sentinel", .no_embedded_nulls);
19314 const sentinel_name = try ip.getOrPutString(gpa, io, pt.tid, "sentinel", .no_embedded_nulls);
1916219315 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", val);
1916319316 }
1916419317 break :blk val.toIntern();
......@@ -19463,15 +19616,18 @@ fn zirStructInit(
1946319616 inst: Zir.Inst.Index,
1946419617 is_ref: bool,
1946519618) CompileError!Air.Inst.Ref {
19466 const gpa = sema.gpa;
19619 const pt = sema.pt;
19620 const zcu = pt.zcu;
19621 const comp = zcu.comp;
19622 const gpa = comp.gpa;
19623 const io = comp.io;
19624 const ip = &zcu.intern_pool;
19625
1946719626 const zir_datas = sema.code.instructions.items(.data);
1946819627 const inst_data = zir_datas[@intFromEnum(inst)].pl_node;
1946919628 const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
1947019629 const src = block.nodeOffset(inst_data.src_node);
1947119630
19472 const pt = sema.pt;
19473 const zcu = pt.zcu;
19474 const ip = &zcu.intern_pool;
1947519631 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
1947619632 const first_field_type_data = zir_datas[@intFromEnum(first_item.field_type)].pl_node;
1947719633 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
......@@ -19513,6 +19669,7 @@ fn zirStructInit(
1951319669 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1951419670 const field_name = try ip.getOrPutString(
1951519671 gpa,
19672 io,
1951619673 pt.tid,
1951719674 sema.code.nullTerminatedString(field_type_extra.name_start),
1951819675 .no_embedded_nulls,
......@@ -19554,6 +19711,7 @@ fn zirStructInit(
1955419711 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1955519712 const field_name = try ip.getOrPutString(
1955619713 gpa,
19714 io,
1955719715 pt.tid,
1955819716 sema.code.nullTerminatedString(field_type_extra.name_start),
1955919717 .no_embedded_nulls,
......@@ -19797,8 +19955,11 @@ fn structInitAnon(
1979719955) CompileError!Air.Inst.Ref {
1979819956 const pt = sema.pt;
1979919957 const zcu = pt.zcu;
19800 const gpa = sema.gpa;
19958 const comp = zcu.comp;
19959 const gpa = comp.gpa;
19960 const io = comp.io;
1980119961 const ip = &zcu.intern_pool;
19962
1980219963 const zir_datas = sema.code.instructions.items(.data);
1980319964
1980419965 const types = try sema.arena.alloc(InternPool.Index, extra_data.fields_len);
......@@ -19828,7 +19989,7 @@ fn structInitAnon(
1982819989 },
1982919990 };
1983019991
19831 field_name.* = try zcu.intern_pool.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
19992 field_name.* = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
1983219993
1983319994 const init = try sema.resolveInst(item.data.init);
1983419995 field_ty.* = sema.typeOf(init).toIntern();
......@@ -19871,7 +20032,7 @@ fn structInitAnon(
1987120032 break :hash hasher.final();
1987220033 };
1987320034 const tracked_inst = try block.trackZir(inst);
19874 const struct_ty = switch (try ip.getStructType(gpa, pt.tid, .{
20035 const struct_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
1987520036 .layout = .auto,
1987620037 .fields_len = extra_data.fields_len,
1987720038 .known_non_opv = false,
......@@ -20131,7 +20292,9 @@ fn arrayInitAnon(
2013120292) CompileError!Air.Inst.Ref {
2013220293 const pt = sema.pt;
2013320294 const zcu = pt.zcu;
20134 const gpa = sema.gpa;
20295 const comp = zcu.comp;
20296 const gpa = comp.gpa;
20297 const io = comp.io;
2013520298 const ip = &zcu.intern_pool;
2013620299
2013720300 const types = try sema.arena.alloc(InternPool.Index, operands.len);
......@@ -20180,7 +20343,7 @@ fn arrayInitAnon(
2018020343 break :blk new_values;
2018120344 };
2018220345
20183 const tuple_ty: Type = .fromInterned(try ip.getTupleType(gpa, pt.tid, .{
20346 const tuple_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
2018420347 .types = types,
2018520348 .values = values_no_comptime,
2018620349 }));
......@@ -20247,7 +20410,11 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2024720410fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2024820411 const pt = sema.pt;
2024920412 const zcu = pt.zcu;
20413 const comp = zcu.comp;
20414 const gpa = comp.gpa;
20415 const io = comp.io;
2025020416 const ip = &zcu.intern_pool;
20417
2025120418 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2025220419 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
2025320420 const ty_src = block.nodeOffset(inst_data.src_node);
......@@ -20255,7 +20422,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
2025520422 const wrapped_aggregate_ty = try sema.resolveTypeOrPoison(block, ty_src, extra.container_type) orelse return .generic_poison_type;
2025620423 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);
2025720424 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
20258 const field_name = try ip.getOrPutString(sema.gpa, pt.tid, zir_field_name, .no_embedded_nulls);
20425 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);
2025920426 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
2026020427}
2026120428
......@@ -20669,6 +20836,9 @@ fn zirReifyTuple(
2066920836) CompileError!Air.Inst.Ref {
2067020837 const pt = sema.pt;
2067120838 const zcu = pt.zcu;
20839 const comp = zcu.comp;
20840 const gpa = comp.gpa;
20841 const io = comp.io;
2067220842
2067320843 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
2067420844 const operand_src = block.builtinCallArgSrc(extra.node, 0);
......@@ -20691,7 +20861,7 @@ fn zirReifyTuple(
2069120861 const field_values = try sema.arena.alloc(InternPool.Index, fields_len);
2069220862 @memset(field_values, .none);
2069320863
20694 return .fromIntern(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{
20864 return .fromIntern(try zcu.intern_pool.getTupleType(gpa, io, pt.tid, .{
2069520865 .types = field_types,
2069620866 .values = field_values,
2069720867 }));
......@@ -20704,7 +20874,9 @@ fn zirReifyPointer(
2070420874) CompileError!Air.Inst.Ref {
2070520875 const pt = sema.pt;
2070620876 const zcu = pt.zcu;
20707 const gpa = zcu.gpa;
20877 const comp = zcu.comp;
20878 const gpa = comp.gpa;
20879 const io = comp.io;
2070820880 const ip = &zcu.intern_pool;
2070920881
2071020882 const extra = sema.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
......@@ -20772,7 +20944,7 @@ fn zirReifyPointer(
2077220944 }
2077320945 try checkSentinelType(sema, block, sentinel_src, elem_ty);
2077420946 if (sentinel.canMutateComptimeVarState(zcu)) {
20775 const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel", .no_embedded_nulls);
20947 const sentinel_name = try ip.getOrPutString(gpa, io, pt.tid, "sentinel", .no_embedded_nulls);
2077620948 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel);
2077720949 }
2077820950 }
......@@ -20801,7 +20973,9 @@ fn zirReifyFn(
2080120973) CompileError!Air.Inst.Ref {
2080220974 const pt = sema.pt;
2080320975 const zcu = pt.zcu;
20804 const gpa = zcu.gpa;
20976 const comp = zcu.comp;
20977 const gpa = comp.gpa;
20978 const io = comp.io;
2080520979 const ip = &zcu.intern_pool;
2080620980
2080720981 const extra = sema.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
......@@ -20884,7 +21058,7 @@ fn zirReifyFn(
2088421058 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
2088521059 }
2088621060
20887 return .fromIntern(try ip.getFuncType(gpa, pt.tid, .{
21061 return .fromIntern(try ip.getFuncType(gpa, io, pt.tid, .{
2088821062 .param_types = param_types_ip,
2088921063 .noalias_bits = noalias_bits,
2089021064 .comptime_bits = 0,
......@@ -20904,7 +21078,9 @@ fn zirReifyStruct(
2090421078) CompileError!Air.Inst.Ref {
2090521079 const pt = sema.pt;
2090621080 const zcu = pt.zcu;
20907 const gpa = sema.gpa;
21081 const comp = zcu.comp;
21082 const gpa = comp.gpa;
21083 const io = comp.io;
2090821084 const ip = &zcu.intern_pool;
2090921085
2091021086 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
......@@ -21079,7 +21255,7 @@ fn zirReifyStruct(
2107921255 return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
2108021256 }
2108121257
21082 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
21258 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
2108321259 .layout = layout,
2108421260 .fields_len = @intCast(fields_len),
2108521261 .known_non_opv = false,
......@@ -21223,10 +21399,10 @@ fn zirReifyStruct(
2122321399 }
2122421400 if (backing_int_ty) |ty| {
2122521401 try sema.checkBackingIntType(block, src, ty, fields_bit_sum);
21226 wip_struct_type.setBackingIntType(ip, ty.toIntern());
21402 wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
2122721403 } else {
2122821404 const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
21229 wip_struct_type.setBackingIntType(ip, ty.toIntern());
21405 wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
2123021406 }
2123121407 }
2123221408
......@@ -21259,7 +21435,9 @@ fn zirReifyUnion(
2125921435) CompileError!Air.Inst.Ref {
2126021436 const pt = sema.pt;
2126121437 const zcu = pt.zcu;
21262 const gpa = sema.gpa;
21438 const comp = zcu.comp;
21439 const gpa = comp.gpa;
21440 const io = comp.io;
2126321441 const ip = &zcu.intern_pool;
2126421442
2126521443 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
......@@ -21400,7 +21578,7 @@ fn zirReifyUnion(
2140021578 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
2140121579 }
2140221580
21403 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{
21581 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
2140421582 .flags = .{
2140521583 .layout = layout,
2140621584 .status = .none,
......@@ -21558,8 +21736,8 @@ fn zirReifyUnion(
2155821736 }
2155921737 }
2156021738
21561 loaded_union.setTagType(ip, enum_tag_ty);
21562 loaded_union.setStatus(ip, .have_field_types);
21739 loaded_union.setTagType(ip, io, enum_tag_ty);
21740 loaded_union.setStatus(ip, io, .have_field_types);
2156321741
2156421742 const new_namespace_index = try pt.createNamespace(.{
2156521743 .parent = block.namespace.toOptional(),
......@@ -21590,7 +21768,9 @@ fn zirReifyEnum(
2159021768) CompileError!Air.Inst.Ref {
2159121769 const pt = sema.pt;
2159221770 const zcu = pt.zcu;
21593 const gpa = sema.gpa;
21771 const comp = zcu.comp;
21772 const gpa = comp.gpa;
21773 const io = comp.io;
2159421774 const ip = &zcu.intern_pool;
2159521775
2159621776 const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
......@@ -21688,7 +21868,7 @@ fn zirReifyEnum(
2168821868 std.hash.autoHash(&hasher, field_name);
2168921869 }
2169021870
21691 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
21871 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
2169221872 .has_values = true,
2169321873 .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit,
2169421874 .fields_len = @intCast(fields_len),
......@@ -21844,13 +22024,16 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
2184422024fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2184522025 const pt = sema.pt;
2184622026 const zcu = pt.zcu;
22027 const comp = zcu.comp;
22028 const gpa = comp.gpa;
22029 const io = comp.io;
2184722030 const ip = &zcu.intern_pool;
2184822031
2184922032 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
2185022033 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
2185122034 const ty = try sema.resolveType(block, ty_src, inst_data.operand);
2185222035
21853 const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{f}", .{ty.fmt(pt)}, .no_embedded_nulls);
22036 const type_name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}", .{ty.fmt(pt)}, .no_embedded_nulls);
2185422037 return sema.addNullTerminatedStrLit(type_name);
2185522038}
2185622039
......@@ -22281,6 +22464,10 @@ fn ptrCastFull(
2228122464) CompileError!Air.Inst.Ref {
2228222465 const pt = sema.pt;
2228322466 const zcu = pt.zcu;
22467 const comp = zcu.comp;
22468 const gpa = comp.gpa;
22469 const io = comp.io;
22470
2228422471 const operand_ty = sema.typeOf(operand);
2228522472
2228622473 try sema.checkPtrType(block, src, dest_ty, true);
......@@ -22452,14 +22639,14 @@ fn ptrCastFull(
2245222639 if (dest_info.sentinel == .none) break :check_sent;
2245322640 if (src_info.flags.size == .c) break :check_sent;
2245422641 if (src_info.sentinel != .none) {
22455 const coerced_sent = try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, src_info.sentinel, dest_info.child);
22642 const coerced_sent = try zcu.intern_pool.getCoerced(gpa, io, pt.tid, src_info.sentinel, dest_info.child);
2245622643 if (dest_info.sentinel == coerced_sent) break :check_sent;
2245722644 }
2245822645 if (is_array_ptr_to_slice) {
2245922646 // [*]nT -> []T
2246022647 const arr_ty: Type = .fromInterned(src_info.child);
2246122648 if (arr_ty.sentinel(zcu)) |src_sentinel| {
22462 const coerced_sent = try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, src_sentinel.toIntern(), dest_info.child);
22649 const coerced_sent = try zcu.intern_pool.getCoerced(gpa, io, pt.tid, src_sentinel.toIntern(), dest_info.child);
2246322650 if (dest_info.sentinel == coerced_sent) break :check_sent;
2246422651 }
2246522652 }
......@@ -23577,8 +23764,11 @@ fn resolveExportOptions(
2357723764) CompileError!Zcu.Export.Options {
2357823765 const pt = sema.pt;
2357923766 const zcu = pt.zcu;
23580 const gpa = sema.gpa;
23767 const comp = zcu.comp;
23768 const gpa = comp.gpa;
23769 const io = comp.io;
2358123770 const ip = &zcu.intern_pool;
23771
2358223772 const export_options_ty = try sema.getBuiltinType(src, .ExportOptions);
2358323773 const air_ref = try sema.resolveInst(zir_ref);
2358423774 const options = try sema.coerce(block, export_options_ty, air_ref, src);
......@@ -23588,21 +23778,21 @@ fn resolveExportOptions(
2358823778 const section_src = block.src(.{ .init_field_section = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2358923779 const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2359023780
23591 const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
23781 const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "name", .no_embedded_nulls), name_src);
2359223782 const name = try sema.toConstString(block, name_src, name_operand, .{ .simple = .export_options });
2359323783
23594 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
23784 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
2359523785 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ .simple = .export_options });
2359623786 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2359723787
23598 const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "section", .no_embedded_nulls), section_src);
23788 const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "section", .no_embedded_nulls), section_src);
2359923789 const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .simple = .export_options });
2360023790 const section = if (section_opt_val.optionalValue(zcu)) |section_val|
2360123791 try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{ .simple = .export_options })
2360223792 else
2360323793 null;
2360423794
23605 const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
23795 const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
2360623796 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ .simple = .export_options });
2360723797 const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
2360823798
......@@ -23617,9 +23807,9 @@ fn resolveExportOptions(
2361723807 }
2361823808
2361923809 return .{
23620 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
23810 .name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls),
2362123811 .linkage = linkage,
23622 .section = try ip.getOrPutStringOpt(gpa, pt.tid, section, .no_embedded_nulls),
23812 .section = try ip.getOrPutStringOpt(gpa, io, pt.tid, section, .no_embedded_nulls),
2362323813 .visibility = visibility,
2362423814 };
2362523815}
......@@ -25345,8 +25535,11 @@ fn zirMemcpy(
2534525535fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2534625536 const pt = sema.pt;
2534725537 const zcu = pt.zcu;
25348 const gpa = sema.gpa;
25538 const comp = zcu.comp;
25539 const gpa = comp.gpa;
25540 const io = comp.io;
2534925541 const ip = &zcu.intern_pool;
25542
2535025543 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2535125544 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
2535225545 const src = block.nodeOffset(inst_data.src_node);
......@@ -25385,7 +25578,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2538525578 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
2538625579
2538725580 const runtime_src = rs: {
25388 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls), dest_src);
25581 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), dest_src);
2538925582 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;
2539025583 const len_u64 = try len_val.toUnsignedIntSema(pt);
2539125584 const len = try sema.usizeCast(block, dest_src, len_u64);
......@@ -25438,7 +25631,11 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2543825631
2543925632 const pt = sema.pt;
2544025633 const zcu = pt.zcu;
25634 const comp = zcu.comp;
25635 const gpa = comp.gpa;
25636 const io = comp.io;
2544125637 const ip = &zcu.intern_pool;
25638
2544225639 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2544325640 const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
2544425641 const target = zcu.getTarget();
......@@ -25482,7 +25679,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2548225679 block,
2548325680 LazySrcLoc.unneeded,
2548425681 cc_type.getNamespaceIndex(zcu),
25485 try ip.getOrPutString(sema.gpa, pt.tid, "c", .no_embedded_nulls),
25682 try ip.getOrPutString(gpa, io, pt.tid, "c", .no_embedded_nulls),
2548625683 );
2548725684 // The above should have errored.
2548825685 @panic("std.builtin is corrupt");
......@@ -25648,8 +25845,11 @@ fn resolvePrefetchOptions(
2564825845) CompileError!std.builtin.PrefetchOptions {
2564925846 const pt = sema.pt;
2565025847 const zcu = pt.zcu;
25651 const gpa = sema.gpa;
25848 const comp = zcu.comp;
25849 const gpa = comp.gpa;
25850 const io = comp.io;
2565225851 const ip = &zcu.intern_pool;
25852
2565325853 const options_ty = try sema.getBuiltinType(src, .PrefetchOptions);
2565425854 const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
2565525855
......@@ -25657,13 +25857,13 @@ fn resolvePrefetchOptions(
2565725857 const locality_src = block.src(.{ .init_field_locality = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2565825858 const cache_src = block.src(.{ .init_field_cache = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2565925859
25660 const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "rw", .no_embedded_nulls), rw_src);
25860 const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "rw", .no_embedded_nulls), rw_src);
2566125861 const rw_val = try sema.resolveConstDefinedValue(block, rw_src, rw, .{ .simple = .prefetch_options });
2566225862
25663 const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "locality", .no_embedded_nulls), locality_src);
25863 const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "locality", .no_embedded_nulls), locality_src);
2566425864 const locality_val = try sema.resolveConstDefinedValue(block, locality_src, locality, .{ .simple = .prefetch_options });
2566525865
25666 const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "cache", .no_embedded_nulls), cache_src);
25866 const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "cache", .no_embedded_nulls), cache_src);
2566725867 const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ .simple = .prefetch_options });
2566825868
2566925869 return std.builtin.PrefetchOptions{
......@@ -25717,8 +25917,11 @@ fn resolveExternOptions(
2571725917} {
2571825918 const pt = sema.pt;
2571925919 const zcu = pt.zcu;
25720 const gpa = sema.gpa;
25920 const comp = zcu.comp;
25921 const gpa = comp.gpa;
25922 const io = comp.io;
2572125923 const ip = &zcu.intern_pool;
25924
2572225925 const options_inst = try sema.resolveInst(zir_ref);
2572325926 const extern_options_ty = try sema.getBuiltinType(src, .ExternOptions);
2572425927 const options = try sema.coerce(block, extern_options_ty, options_inst, src);
......@@ -25731,21 +25934,21 @@ fn resolveExternOptions(
2573125934 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2573225935 const relocation_src = block.src(.{ .init_field_relocation = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2573325936
25734 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
25937 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "name", .no_embedded_nulls), name_src);
2573525938 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
2573625939
25737 const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "library_name", .no_embedded_nulls), library_src);
25940 const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "library_name", .no_embedded_nulls), library_src);
2573825941 const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ .simple = .extern_options });
2573925942
25740 const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
25943 const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "linkage", .no_embedded_nulls), linkage_src);
2574125944 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
2574225945 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2574325946
25744 const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
25947 const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
2574525948 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_ref, .{ .simple = .extern_options });
2574625949 const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
2574725950
25748 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);
25951 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);
2574925952 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
2575025953
2575125954 const library_name = if (library_name_val.optionalValue(zcu)) |library_name_payload| library_name: {
......@@ -25757,10 +25960,10 @@ fn resolveExternOptions(
2575725960 break :library_name library_name;
2575825961 } else null;
2575925962
25760 const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src);
25963 const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src);
2576125964 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });
2576225965
25763 const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "relocation", .no_embedded_nulls), relocation_src);
25966 const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, io, pt.tid, "relocation", .no_embedded_nulls), relocation_src);
2576425967 const relocation_val = try sema.resolveConstDefinedValue(block, relocation_src, relocation_ref, .{ .simple = .extern_options });
2576525968 const relocation = try sema.interpretBuiltinType(block, relocation_src, relocation_val, std.builtin.ExternOptions.Relocation);
2576625969
......@@ -25773,8 +25976,8 @@ fn resolveExternOptions(
2577325976 }
2577425977
2577525978 return .{
25776 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
25777 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
25979 .name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls),
25980 .library_name = try ip.getOrPutStringOpt(gpa, io, pt.tid, library_name, .no_embedded_nulls),
2577825981 .linkage = linkage,
2577925982 .visibility = visibility,
2578025983 .is_thread_local = is_thread_local_val.toBool(),
......@@ -25919,7 +26122,9 @@ fn zirInComptime(
2591926122fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
2592026123 const pt = sema.pt;
2592126124 const zcu = pt.zcu;
25922 const gpa = zcu.gpa;
26125 const comp = zcu.comp;
26126 const gpa = comp.gpa;
26127 const io = comp.io;
2592326128 const ip = &zcu.intern_pool;
2592426129
2592526130 const src_node: std.zig.Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
......@@ -25955,7 +26160,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
2595526160 block,
2595626161 src,
2595726162 callconv_ty.getNamespaceIndex(zcu),
25958 try ip.getOrPutString(gpa, pt.tid, "c", .no_embedded_nulls),
26163 try ip.getOrPutString(gpa, io, pt.tid, "c", .no_embedded_nulls),
2595926164 ) orelse @panic("std.builtin is corrupt");
2596026165 },
2596126166 .calling_convention_inline => {
......@@ -26492,11 +26697,12 @@ fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !vo
2649226697
2649326698fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !InternPool.Index {
2649426699 const zcu = sema.pt.zcu;
26700 const io = zcu.comp.io;
2649526701 try sema.ensureMemoizedStateResolved(src, .panic);
2649626702 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());
2649726703 switch (sema.owner.unwrap()) {
2649826704 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
26499 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),
26705 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),
2650026706 }
2650126707 return panic_fn_index;
2650226708}
......@@ -28539,10 +28745,15 @@ fn coerceExtra(
2853928745 inst_src: LazySrcLoc,
2854028746 opts: CoerceOpts,
2854128747) CoersionError!Air.Inst.Ref {
28542 if (dest_ty.isGenericPoison()) return inst;
2854328748 const pt = sema.pt;
2854428749 const zcu = pt.zcu;
28750 const comp = zcu.comp;
28751 const gpa = comp.gpa;
28752 const io = comp.io;
2854528753 const ip = &zcu.intern_pool;
28754
28755 if (dest_ty.isGenericPoison()) return inst;
28756
2854628757 const dest_ty_src = inst_src; // TODO better source location
2854728758 try dest_ty.resolveFields(pt);
2854828759 const inst_ty = sema.typeOf(inst);
......@@ -28904,7 +29115,7 @@ fn coerceExtra(
2890429115 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
2890529116 .undef => try pt.undefRef(dest_ty),
2890629117 .int => |int| Air.internedToRef(
28907 try zcu.intern_pool.getCoercedInts(zcu.gpa, pt.tid, int, dest_ty.toIntern()),
29118 try zcu.intern_pool.getCoercedInts(gpa, io, pt.tid, int, dest_ty.toIntern()),
2890829119 ),
2890929120 else => unreachable,
2891029121 };
......@@ -30070,6 +30281,10 @@ fn coerceInMemoryAllowedPtrs(
3007030281) !InMemoryCoercionResult {
3007130282 const pt = sema.pt;
3007230283 const zcu = pt.zcu;
30284 const comp = zcu.comp;
30285 const gpa = comp.gpa;
30286 const io = comp.io;
30287
3007330288 const dest_info = dest_ptr_ty.ptrInfo(zcu);
3007430289 const src_info = src_ptr_ty.ptrInfo(zcu);
3007530290
......@@ -30175,7 +30390,7 @@ fn coerceInMemoryAllowedPtrs(
3017530390 const ds = dest_info.sentinel;
3017630391 if (ss == .none and ds == .none) break :ok true;
3017730392 if (ss != .none and ds != .none) {
30178 if (ds == try zcu.intern_pool.getCoerced(sema.gpa, pt.tid, ss, dest_info.child)) break :ok true;
30393 if (ds == try zcu.intern_pool.getCoerced(gpa, io, pt.tid, ss, dest_info.child)) break :ok true;
3017930394 }
3018030395 if (src_info.flags.size == .c) break :ok true;
3018130396 if (!dest_is_mut and dest_info.sentinel == .none) break :ok true;
......@@ -33086,6 +33301,9 @@ fn resolvePeerTypesInner(
3308633301) !PeerResolveResult {
3308733302 const pt = sema.pt;
3308833303 const zcu = pt.zcu;
33304 const comp = zcu.comp;
33305 const gpa = comp.gpa;
33306 const io = comp.io;
3308933307 const ip = &zcu.intern_pool;
3309033308
3309133309 var strat_reason: usize = 0;
......@@ -33412,8 +33630,8 @@ fn resolvePeerTypesInner(
3341233630 }).toIntern();
3341333631
3341433632 if (ptr_info.sentinel != .none and peer_info.sentinel != .none) {
33415 const peer_sent = try ip.getCoerced(sema.gpa, pt.tid, ptr_info.sentinel, ptr_info.child);
33416 const ptr_sent = try ip.getCoerced(sema.gpa, pt.tid, peer_info.sentinel, ptr_info.child);
33633 const peer_sent = try ip.getCoerced(gpa, io, pt.tid, ptr_info.sentinel, ptr_info.child);
33634 const ptr_sent = try ip.getCoerced(gpa, io, pt.tid, peer_info.sentinel, ptr_info.child);
3341733635 if (ptr_sent == peer_sent) {
3341833636 ptr_info.sentinel = ptr_sent;
3341933637 } else {
......@@ -33715,8 +33933,8 @@ fn resolvePeerTypesInner(
3371533933 no_sentinel: {
3371633934 if (peer_sentinel == .none) break :no_sentinel;
3371733935 if (cur_sentinel == .none) break :no_sentinel;
33718 const peer_sent_coerced = try ip.getCoerced(sema.gpa, pt.tid, peer_sentinel, sentinel_ty);
33719 const cur_sent_coerced = try ip.getCoerced(sema.gpa, pt.tid, cur_sentinel, sentinel_ty);
33936 const peer_sent_coerced = try ip.getCoerced(gpa, io, pt.tid, peer_sentinel, sentinel_ty);
33937 const cur_sent_coerced = try ip.getCoerced(gpa, io, pt.tid, cur_sentinel, sentinel_ty);
3372033938 if (peer_sent_coerced != cur_sent_coerced) break :no_sentinel;
3372133939 // Sentinels match
3372233940 if (ptr_info.flags.size == .one) switch (ip.indexToKey(ptr_info.child)) {
......@@ -34081,7 +34299,7 @@ fn resolvePeerTypesInner(
3408134299 else => |result| {
3408234300 const result_buf = try sema.arena.create(PeerResolveResult);
3408334301 result_buf.* = result;
34084 const field_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
34302 const field_name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
3408534303
3408634304 // The error info needs the field types, but we can't reuse sub_peer_tys
3408734305 // since the recursive call may have clobbered it.
......@@ -34136,7 +34354,7 @@ fn resolvePeerTypesInner(
3413634354 field_val.* = if (comptime_val) |v| v.toIntern() else .none;
3413734355 }
3413834356
34139 const final_ty = try ip.getTupleType(zcu.gpa, pt.tid, .{
34357 const final_ty = try ip.getTupleType(gpa, io, pt.tid, .{
3414034358 .types = field_types,
3414134359 .values = field_vals,
3414234360 });
......@@ -34274,6 +34492,7 @@ pub fn resolveStructAlignment(
3427434492) SemaError!void {
3427534493 const pt = sema.pt;
3427634494 const zcu = pt.zcu;
34495 const io = zcu.comp.io;
3427734496 const ip = &zcu.intern_pool;
3427834497 const target = zcu.getTarget();
3427934498
......@@ -34287,15 +34506,15 @@ pub fn resolveStructAlignment(
3428734506 // We'll guess "pointer-aligned", if the struct has an
3428834507 // underaligned pointer field then some allocations
3428934508 // might require explicit alignment.
34290 if (struct_type.assumePointerAlignedIfFieldTypesWip(ip, ptr_align)) return;
34509 if (struct_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
3429134510
3429234511 try sema.resolveStructFieldTypes(ty, struct_type);
3429334512
3429434513 // We'll guess "pointer-aligned", if the struct has an
3429534514 // underaligned pointer field then some allocations
3429634515 // might require explicit alignment.
34297 if (struct_type.assumePointerAlignedIfWip(ip, ptr_align)) return;
34298 defer struct_type.clearAlignmentWip(ip);
34516 if (struct_type.assumePointerAlignedIfWip(ip, io, ptr_align)) return;
34517 defer struct_type.clearAlignmentWip(ip, io);
3429934518
3430034519 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
3430134520 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
......@@ -34314,13 +34533,14 @@ pub fn resolveStructAlignment(
3431434533 alignment = alignment.maxStrict(field_align);
3431534534 }
3431634535
34317 struct_type.setAlignment(ip, alignment);
34536 struct_type.setAlignment(ip, io, alignment);
3431834537}
3431934538
3432034539pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3432134540 const pt = sema.pt;
3432234541 const zcu = pt.zcu;
3432334542 const ip = &zcu.intern_pool;
34543 const io = zcu.comp.io;
3432434544 const struct_type = zcu.typeToStruct(ty) orelse return;
3432534545
3432634546 assert(sema.owner.unwrap().type == ty.toIntern());
......@@ -34341,7 +34561,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3434134561 return;
3434234562 }
3434334563
34344 if (struct_type.setLayoutWip(ip)) {
34564 if (struct_type.setLayoutWip(ip, io)) {
3434534565 const msg = try sema.errMsg(
3434634566 ty.srcLoc(zcu),
3434734567 "struct '{f}' depends on itself",
......@@ -34349,7 +34569,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3434934569 );
3435034570 return sema.failWithOwnedErrorMsg(null, msg);
3435134571 }
34352 defer struct_type.clearLayoutWip(ip);
34572 defer struct_type.clearLayoutWip(ip, io);
3435334573
3435434574 const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
3435534575 const sizes = try sema.arena.alloc(u64, struct_type.field_types.len);
......@@ -34468,7 +34688,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3446834688 );
3446934689 return sema.failWithOwnedErrorMsg(null, msg);
3447034690 };
34471 struct_type.setLayoutResolved(ip, size, big_align);
34691 struct_type.setLayoutResolved(ip, io, size, big_align);
3447234692 _ = try ty.comptimeOnlySema(pt);
3447334693}
3447434694
......@@ -34478,7 +34698,9 @@ fn backingIntType(
3447834698) CompileError!void {
3447934699 const pt = sema.pt;
3448034700 const zcu = pt.zcu;
34481 const gpa = zcu.gpa;
34701 const comp = zcu.comp;
34702 const gpa = comp.gpa;
34703 const io = comp.io;
3448234704 const ip = &zcu.intern_pool;
3448334705
3448434706 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
......@@ -34546,13 +34768,13 @@ fn backingIntType(
3454634768 };
3454734769
3454834770 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
34549 struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
34771 struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
3455034772 } else {
3455134773 if (fields_bit_sum > std.math.maxInt(u16)) {
3455234774 return sema.fail(&block, block.nodeOffset(.zero), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
3455334775 }
3455434776 const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
34555 struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
34777 struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
3455634778 }
3455734779
3455834780 try sema.flushExports();
......@@ -34620,6 +34842,7 @@ pub fn resolveUnionAlignment(
3462034842) SemaError!void {
3462134843 const pt = sema.pt;
3462234844 const zcu = pt.zcu;
34845 const io = zcu.comp.io;
3462334846 const ip = &zcu.intern_pool;
3462434847 const target = zcu.getTarget();
3462534848
......@@ -34632,7 +34855,7 @@ pub fn resolveUnionAlignment(
3463234855 // We'll guess "pointer-aligned", if the union has an
3463334856 // underaligned pointer field then some allocations
3463434857 // might require explicit alignment.
34635 if (union_type.assumePointerAlignedIfFieldTypesWip(ip, ptr_align)) return;
34858 if (union_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
3463634859
3463734860 try sema.resolveUnionFieldTypes(ty, union_type);
3463834861
......@@ -34653,12 +34876,13 @@ pub fn resolveUnionAlignment(
3465334876 max_align = max_align.max(field_align);
3465434877 }
3465534878
34656 union_type.setAlignment(ip, max_align);
34879 union_type.setAlignment(ip, io, max_align);
3465734880}
3465834881
3465934882/// This logic must be kept in sync with `Type.getUnionLayout`.
3466034883pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3466134884 const pt = sema.pt;
34885 const io = pt.zcu.comp.io;
3466234886 const ip = &pt.zcu.intern_pool;
3466334887
3466434888 try sema.resolveUnionFieldTypes(ty, ip.loadUnionType(ty.ip_index));
......@@ -34682,9 +34906,9 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3468234906 .have_layout, .fully_resolved_wip, .fully_resolved => return,
3468334907 }
3468434908
34685 errdefer union_type.setStatusIfLayoutWip(ip, old_flags.status);
34909 errdefer union_type.setStatusIfLayoutWip(ip, io, old_flags.status);
3468634910
34687 union_type.setStatus(ip, .layout_wip);
34911 union_type.setStatus(ip, io, .layout_wip);
3468834912
3468934913 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
3469034914 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
......@@ -34765,7 +34989,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3476534989 );
3476634990 return sema.failWithOwnedErrorMsg(null, msg);
3476734991 };
34768 union_type.setHaveLayout(ip, casted_size, padding, alignment);
34992 union_type.setHaveLayout(ip, io, casted_size, padding, alignment);
3476934993
3477034994 if (union_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) {
3477134995 const msg = try sema.errMsg(
......@@ -34797,13 +35021,14 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
3479735021
3479835022 const pt = sema.pt;
3479935023 const zcu = pt.zcu;
35024 const io = zcu.comp.io;
3480035025 const ip = &zcu.intern_pool;
3480135026 const struct_type = zcu.typeToStruct(ty).?;
3480235027
3480335028 assert(sema.owner.unwrap().type == ty.toIntern());
3480435029
34805 if (struct_type.setFullyResolved(ip)) return;
34806 errdefer struct_type.clearFullyResolved(ip);
35030 if (struct_type.setFullyResolved(ip, io)) return;
35031 errdefer struct_type.clearFullyResolved(ip, io);
3480735032
3480835033 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
3480935034 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
......@@ -34823,6 +35048,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
3482335048
3482435049 const pt = sema.pt;
3482535050 const zcu = pt.zcu;
35051 const io = zcu.comp.io;
3482635052 const ip = &zcu.intern_pool;
3482735053 const union_obj = zcu.typeToUnion(ty).?;
3482835054
......@@ -34841,14 +35067,14 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
3484135067 // make sure pointer fields get their child types resolved as well.
3484235068 // See also similar code for structs.
3484335069 const prev_status = union_obj.flagsUnordered(ip).status;
34844 errdefer union_obj.setStatus(ip, prev_status);
35070 errdefer union_obj.setStatus(ip, io, prev_status);
3484535071
34846 union_obj.setStatus(ip, .fully_resolved_wip);
35072 union_obj.setStatus(ip, io, .fully_resolved_wip);
3484735073 for (0..union_obj.field_types.len) |field_index| {
3484835074 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
3484935075 try field_ty.resolveFully(pt);
3485035076 }
34851 union_obj.setStatus(ip, .fully_resolved);
35077 union_obj.setStatus(ip, io, .fully_resolved);
3485235078 }
3485335079
3485435080 // And let's not forget comptime-only status.
......@@ -34862,13 +35088,14 @@ pub fn resolveStructFieldTypes(
3486235088) SemaError!void {
3486335089 const pt = sema.pt;
3486435090 const zcu = pt.zcu;
35091 const io = zcu.comp.io;
3486535092 const ip = &zcu.intern_pool;
3486635093
3486735094 assert(sema.owner.unwrap().type == ty);
3486835095
3486935096 if (struct_type.haveFieldTypes(ip)) return;
3487035097
34871 if (struct_type.setFieldTypesWip(ip)) {
35098 if (struct_type.setFieldTypesWip(ip, io)) {
3487235099 const msg = try sema.errMsg(
3487335100 Type.fromInterned(ty).srcLoc(zcu),
3487435101 "struct '{f}' depends on itself",
......@@ -34876,7 +35103,7 @@ pub fn resolveStructFieldTypes(
3487635103 );
3487735104 return sema.failWithOwnedErrorMsg(null, msg);
3487835105 }
34879 defer struct_type.clearFieldTypesWip(ip);
35106 defer struct_type.clearFieldTypesWip(ip, io);
3488035107
3488135108 // can't happen earlier than this because we only want the progress node if not already resolved
3488235109 const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
......@@ -34891,6 +35118,7 @@ pub fn resolveStructFieldTypes(
3489135118pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3489235119 const pt = sema.pt;
3489335120 const zcu = pt.zcu;
35121 const io = zcu.comp.io;
3489435122 const ip = &zcu.intern_pool;
3489535123 const struct_type = zcu.typeToStruct(ty) orelse return;
3489635124
......@@ -34901,7 +35129,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3490135129
3490235130 try sema.resolveStructLayout(ty);
3490335131
34904 if (struct_type.setInitsWip(ip)) {
35132 if (struct_type.setInitsWip(ip, io)) {
3490535133 const msg = try sema.errMsg(
3490635134 ty.srcLoc(zcu),
3490735135 "struct '{f}' depends on itself",
......@@ -34909,7 +35137,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3490935137 );
3491035138 return sema.failWithOwnedErrorMsg(null, msg);
3491135139 }
34912 defer struct_type.clearInitsWip(ip);
35140 defer struct_type.clearInitsWip(ip, io);
3491335141
3491435142 // can't happen earlier than this because we only want the progress node if not already resolved
3491535143 const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
......@@ -34919,12 +35147,13 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3491935147 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
3492035148 error.ComptimeBreak, error.ComptimeReturn => unreachable,
3492135149 };
34922 struct_type.setHaveFieldInits(ip);
35150 struct_type.setHaveFieldInits(ip, io);
3492335151}
3492435152
3492535153pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void {
3492635154 const pt = sema.pt;
3492735155 const zcu = pt.zcu;
35156 const io = zcu.comp.io;
3492835157 const ip = &zcu.intern_pool;
3492935158
3493035159 assert(sema.owner.unwrap().type == ty.toIntern());
......@@ -34947,13 +35176,13 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load
3494735176 const tracked_unit = zcu.trackUnitSema(union_type.name.toSlice(ip), null);
3494835177 defer tracked_unit.end(zcu);
3494935178
34950 union_type.setStatus(ip, .field_types_wip);
34951 errdefer union_type.setStatus(ip, .none);
35179 union_type.setStatus(ip, io, .field_types_wip);
35180 errdefer union_type.setStatus(ip, io, .none);
3495235181 sema.unionFields(ty.toIntern(), union_type) catch |err| switch (err) {
3495335182 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
3495435183 error.ComptimeBreak, error.ComptimeReturn => unreachable,
3495535184 };
34956 union_type.setStatus(ip, .have_field_types);
35185 union_type.setStatus(ip, io, .have_field_types);
3495735186}
3495835187
3495935188/// Returns a normal error set corresponding to the fully populated inferred
......@@ -35055,11 +35284,14 @@ fn resolveAdHocInferredErrorSet(
3505535284) CompileError!InternPool.Index {
3505635285 const pt = sema.pt;
3505735286 const zcu = pt.zcu;
35058 const gpa = sema.gpa;
35287 const comp = zcu.comp;
35288 const gpa = comp.gpa;
35289 const io = comp.io;
3505935290 const ip = &zcu.intern_pool;
35291
3506035292 const new_ty = try resolveAdHocInferredErrorSetTy(sema, block, src, ip.typeOf(value));
3506135293 if (new_ty == .none) return value;
35062 return ip.getCoerced(gpa, pt.tid, value, new_ty);
35294 return ip.getCoerced(gpa, io, pt.tid, value, new_ty);
3506335295}
3506435296
3506535297fn resolveAdHocInferredErrorSetTy(
......@@ -35159,8 +35391,11 @@ fn structFields(
3515935391) CompileError!void {
3516035392 const pt = sema.pt;
3516135393 const zcu = pt.zcu;
35162 const gpa = zcu.gpa;
35394 const comp = zcu.comp;
35395 const gpa = comp.gpa;
35396 const io = comp.io;
3516335397 const ip = &zcu.intern_pool;
35398
3516435399 const namespace_index = struct_type.namespace;
3516535400 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
3516635401 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
......@@ -35173,7 +35408,7 @@ fn structFields(
3517335408 return;
3517435409 },
3517535410 .auto, .@"extern" => {
35176 struct_type.setLayoutResolved(ip, 0, .none);
35411 struct_type.setLayoutResolved(ip, io, 0, .none);
3517735412 return;
3517835413 },
3517935414 };
......@@ -35245,7 +35480,7 @@ fn structFields(
3524535480 extra_index += 1;
3524635481
3524735482 // This string needs to outlive the ZIR code.
35248 const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls);
35483 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
3524935484 assert(struct_type.addFieldName(ip, field_name) == null);
3525035485
3525135486 if (has_align) {
......@@ -35345,8 +35580,8 @@ fn structFields(
3534535580 extra_index += zir_field.init_body_len;
3534635581 }
3534735582
35348 struct_type.clearFieldTypesWip(ip);
35349 if (!any_inits) struct_type.setHaveFieldInits(ip);
35583 struct_type.clearFieldTypesWip(ip, io);
35584 if (!any_inits) struct_type.setHaveFieldInits(ip, io);
3535035585
3535135586 try sema.flushExports();
3535235587}
......@@ -35485,8 +35720,11 @@ fn unionFields(
3548535720
3548635721 const pt = sema.pt;
3548735722 const zcu = pt.zcu;
35488 const gpa = zcu.gpa;
35723 const comp = zcu.comp;
35724 const gpa = comp.gpa;
35725 const io = comp.io;
3548935726 const ip = &zcu.intern_pool;
35727
3549035728 const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir.?;
3549135729 const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3549235730 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
......@@ -35595,7 +35833,7 @@ fn unionFields(
3559535833 .enum_type => ip.loadEnumType(provided_ty.toIntern()),
3559635834 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}),
3559735835 };
35598 union_type.setTagType(ip, provided_ty.toIntern());
35836 union_type.setTagType(ip, io, provided_ty.toIntern());
3559935837 // The fields of the union must match the enum exactly.
3560035838 // A flag per field is used to check for missing and extraneous fields.
3560135839 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
......@@ -35727,7 +35965,7 @@ fn unionFields(
3572735965 }
3572835966
3572935967 // This string needs to outlive the ZIR code.
35730 const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls);
35968 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
3573135969 if (enum_field_names.len != 0) {
3573235970 enum_field_names[field_i] = field_name;
3573335971 }
......@@ -35871,10 +36109,10 @@ fn unionFields(
3587136109 }
3587236110 } else if (enum_field_vals.count() > 0) {
3587336111 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_ty, union_type.name);
35874 union_type.setTagType(ip, enum_ty);
36112 union_type.setTagType(ip, io, enum_ty);
3587536113 } else {
3587636114 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_ty, union_type.name);
35877 union_type.setTagType(ip, enum_ty);
36115 union_type.setTagType(ip, io, enum_ty);
3587836116 }
3587936117
3588036118 try sema.flushExports();
......@@ -35890,18 +36128,21 @@ fn generateUnionTagTypeNumbered(
3589036128) !InternPool.Index {
3589136129 const pt = sema.pt;
3589236130 const zcu = pt.zcu;
35893 const gpa = sema.gpa;
36131 const comp = zcu.comp;
36132 const gpa = comp.gpa;
36133 const io = comp.io;
3589436134 const ip = &zcu.intern_pool;
3589536135
3589636136 const name = try ip.getOrPutStringFmt(
3589736137 gpa,
36138 io,
3589836139 pt.tid,
3589936140 "@typeInfo({f}).@\"union\".tag_type.?",
3590036141 .{union_name.fmt(ip)},
3590136142 .no_embedded_nulls,
3590236143 );
3590336144
35904 const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{
36145 const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
3590536146 .name = name,
3590636147 .owner_union_ty = union_type,
3590736148 .tag_ty = if (enum_field_vals.len == 0)
......@@ -35926,18 +36167,21 @@ fn generateUnionTagTypeSimple(
3592636167) !InternPool.Index {
3592736168 const pt = sema.pt;
3592836169 const zcu = pt.zcu;
36170 const comp = zcu.comp;
36171 const gpa = comp.gpa;
36172 const io = comp.io;
3592936173 const ip = &zcu.intern_pool;
35930 const gpa = sema.gpa;
3593136174
3593236175 const name = try ip.getOrPutStringFmt(
3593336176 gpa,
36177 io,
3593436178 pt.tid,
3593536179 "@typeInfo({f}).@\"union\".tag_type.?",
3593636180 .{union_name.fmt(ip)},
3593736181 .no_embedded_nulls,
3593836182 );
3593936183
35940 const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{
36184 const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
3594136185 .name = name,
3594236186 .owner_union_ty = union_type,
3594336187 .tag_ty = (try pt.smallestUnsignedInt(enum_field_names.len -| 1)).toIntern(),
......@@ -35958,7 +36202,11 @@ fn generateUnionTagTypeSimple(
3595836202pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3595936203 const pt = sema.pt;
3596036204 const zcu = pt.zcu;
36205 const comp = zcu.comp;
36206 const gpa = comp.gpa;
36207 const io = comp.io;
3596136208 const ip = &zcu.intern_pool;
36209
3596236210 return switch (ty.toIntern()) {
3596336211 .u0_type,
3596436212 .i0_type,
......@@ -36302,7 +36550,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3630236550 (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
3630336551 else
3630436552 try ip.getCoercedInts(
36305 zcu.gpa,
36553 gpa,
36554 io,
3630636555 pt.tid,
3630736556 ip.indexToKey(enum_type.values.get(ip)[0]).int,
3630836557 enum_type.tag_ty,
......@@ -36936,12 +37185,16 @@ fn checkRuntimeValue(sema: *Sema, ptr: Air.Inst.Ref) bool {
3693637185fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Air.Inst.Ref) CompileError!void {
3693737186 if (sema.checkRuntimeValue(val)) return;
3693837187 return sema.failWithOwnedErrorMsg(block, msg: {
36939 const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{});
36940 errdefer msg.destroy(sema.gpa);
36941 try sema.errNote(val_src, msg, "comptime var pointers are not available at runtime", .{});
3694237188 const pt = sema.pt;
3694337189 const zcu = pt.zcu;
36944 const val_str = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, "runtime_value", .no_embedded_nulls);
37190 const comp = zcu.comp;
37191 const gpa = comp.gpa;
37192 const io = comp.io;
37193
37194 const msg = try sema.errMsg(val_src, "runtime value contains reference to comptime var", .{});
37195 errdefer msg.destroy(gpa);
37196 try sema.errNote(val_src, msg, "comptime var pointers are not available at runtime", .{});
37197 const val_str = try pt.zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "runtime_value", .no_embedded_nulls);
3694537198 try sema.explainWhyValueContainsReferenceToComptimeVar(msg, val_src, val_str, .fromInterned(val.toInterned().?));
3694637199 break :msg msg;
3694737200 });
......@@ -37385,7 +37638,9 @@ fn resolveDeclaredEnumInner(
3738537638) Zcu.CompileError!void {
3738637639 const pt = sema.pt;
3738737640 const zcu = pt.zcu;
37388 const gpa = zcu.gpa;
37641 const comp = zcu.comp;
37642 const gpa = comp.gpa;
37643 const io = comp.io;
3738937644 const ip = &zcu.intern_pool;
3739037645
3739137646 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
......@@ -37430,7 +37685,7 @@ fn resolveDeclaredEnumInner(
3743037685 const field_name_zir = zir.nullTerminatedString(field_name_index);
3743137686 extra_index += 1; // field name
3743237687
37433 const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls);
37688 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
3743437689
3743537690 const value_src: LazySrcLoc = .{
3743637691 .base_node_inst = tracked_inst,
......@@ -37541,7 +37796,9 @@ pub fn resolveNavPtrModifiers(
3754137796) CompileError!NavPtrModifiers {
3754237797 const pt = sema.pt;
3754337798 const zcu = pt.zcu;
37544 const gpa = zcu.gpa;
37799 const comp = zcu.comp;
37800 const gpa = comp.gpa;
37801 const io = comp.io;
3754537802 const ip = &zcu.intern_pool;
3754637803
3754737804 const align_src = block.src(.{ .node_offset_var_decl_align = .zero });
......@@ -37563,7 +37820,7 @@ pub fn resolveNavPtrModifiers(
3756337820 } else if (bytes.len == 0) {
3756437821 return sema.fail(block, section_src, "linksection cannot be empty", .{});
3756537822 }
37566 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
37823 break :ls try ip.getOrPutStringOpt(gpa, io, pt.tid, bytes, .no_embedded_nulls);
3756737824 };
3756837825
3756937826 const @"addrspace": std.builtin.AddressSpace = as: {
......@@ -37595,8 +37852,10 @@ pub fn resolveNavPtrModifiers(
3759537852pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, builtin_namespace: InternPool.NamespaceIndex, stage: InternPool.MemoizedStateStage) CompileError!bool {
3759637853 const pt = sema.pt;
3759737854 const zcu = pt.zcu;
37855 const comp = zcu.comp;
37856 const gpa = comp.gpa;
37857 const io = comp.io;
3759837858 const ip = &zcu.intern_pool;
37599 const gpa = zcu.gpa;
3760037859
3760137860 var any_changed = false;
3760237861
......@@ -37613,7 +37872,7 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
3761337872 },
3761437873 };
3761537874
37616 const name_nts = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
37875 const name_nts = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
3761737876 const nav = try sema.namespaceLookup(block, simple_src, parent_ns, name_nts) orelse
3761837877 return sema.fail(block, simple_src, "{s} missing {s}", .{ parent_name, name });
3761937878
src/Sema/LowerZon.zig+51-24
......@@ -38,8 +38,11 @@ pub fn run(
3838 block: *Sema.Block,
3939) CompileError!InternPool.Index {
4040 const pt = sema.pt;
41 const comp = pt.zcu.comp;
42 const gpa = comp.gpa;
43 const io = comp.io;
4144
42 const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
45 const tracked_inst = try pt.zcu.intern_pool.trackZir(gpa, io, pt.tid, .{
4346 .file = file_index,
4447 .inst = .main_struct_inst, // this is the only trackable instruction in a ZON file
4548 });
......@@ -63,8 +66,10 @@ pub fn run(
6366}
6467
6568fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!InternPool.Index {
66 const gpa = self.sema.gpa;
6769 const pt = self.sema.pt;
70 const comp = pt.zcu.comp;
71 const gpa = comp.gpa;
72 const io = comp.io;
6873 const ip = &pt.zcu.intern_pool;
6974 switch (node.get(self.file.zoir.?)) {
7075 .true => return .bool_true,
......@@ -94,13 +99,14 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
9499 .enum_literal => |val| return pt.intern(.{
95100 .enum_literal = try ip.getOrPutString(
96101 gpa,
102 io,
97103 pt.tid,
98104 val.get(self.file.zoir.?),
99105 .no_embedded_nulls,
100106 ),
101107 }),
102108 .string_literal => |val| {
103 const ip_str = try ip.getOrPutString(gpa, pt.tid, val, .maybe_embedded_nulls);
109 const ip_str = try ip.getOrPutString(gpa, io, pt.tid, val, .maybe_embedded_nulls);
104110 const result = try self.sema.addStrLit(ip_str, val.len);
105111 return result.toInterned().?;
106112 },
......@@ -112,14 +118,10 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
112118 values[i] = try self.lowerExprAnonResTy(nodes.at(@intCast(i)));
113119 types[i] = Value.fromInterned(values[i]).typeOf(pt.zcu).toIntern();
114120 }
115 const ty = try ip.getTupleType(
116 gpa,
117 pt.tid,
118 .{
119 .types = types,
120 .values = values,
121 },
122 );
121 const ty = try ip.getTupleType(gpa, io, pt.tid, .{
122 .types = types,
123 .values = values,
124 });
123125 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();
124126 },
125127 .struct_literal => |init| {
......@@ -129,6 +131,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
129131 }
130132 const struct_ty = switch (try ip.getStructType(
131133 gpa,
134 io,
132135 pt.tid,
133136 .{
134137 .layout = .auto,
......@@ -168,6 +171,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
168171 for (init.names, 0..) |name, field_idx| {
169172 const name_interned = try ip.getOrPutString(
170173 gpa,
174 io,
171175 pt.tid,
172176 name.get(self.file.zoir.?),
173177 .no_embedded_nulls,
......@@ -636,11 +640,16 @@ fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
636640}
637641
638642fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
639 const ip = &self.sema.pt.zcu.intern_pool;
643 const pt = self.sema.pt;
644 const comp = pt.zcu.comp;
645 const gpa = comp.gpa;
646 const io = comp.io;
647 const ip = &pt.zcu.intern_pool;
640648 switch (node.get(self.file.zoir.?)) {
641649 .enum_literal => |field_name| {
642650 const field_name_interned = try ip.getOrPutString(
643 self.sema.gpa,
651 gpa,
652 io,
644653 self.sema.pt.tid,
645654 field_name.get(self.file.zoir.?),
646655 .no_embedded_nulls,
......@@ -665,11 +674,16 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
665674}
666675
667676fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
668 const ip = &self.sema.pt.zcu.intern_pool;
677 const pt = self.sema.pt;
678 const comp = pt.zcu.comp;
679 const gpa = comp.gpa;
680 const io = comp.io;
681 const ip = &pt.zcu.intern_pool;
669682 switch (node.get(self.file.zoir.?)) {
670683 .enum_literal => |field_name| {
671684 const field_name_interned = try ip.getOrPutString(
672 self.sema.gpa,
685 gpa,
686 io,
673687 self.sema.pt.tid,
674688 field_name.get(self.file.zoir.?),
675689 .no_embedded_nulls,
......@@ -747,8 +761,11 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
747761}
748762
749763fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
750 const ip = &self.sema.pt.zcu.intern_pool;
751 const gpa = self.sema.gpa;
764 const pt = self.sema.pt;
765 const comp = pt.zcu.comp;
766 const gpa = comp.gpa;
767 const io = comp.io;
768 const ip = &pt.zcu.intern_pool;
752769
753770 try res_ty.resolveFields(self.sema.pt);
754771 try res_ty.resolveStructFieldInits(self.sema.pt);
......@@ -772,6 +789,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
772789 for (0..fields.names.len) |i| {
773790 const field_name = try ip.getOrPutString(
774791 gpa,
792 io,
775793 self.sema.pt.tid,
776794 fields.names[i].get(self.file.zoir.?),
777795 .no_embedded_nulls,
......@@ -807,8 +825,11 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
807825}
808826
809827fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
810 const ip = &self.sema.pt.zcu.intern_pool;
811 const gpa = self.sema.gpa;
828 const pt = self.sema.pt;
829 const comp = pt.zcu.comp;
830 const gpa = comp.gpa;
831 const io = comp.io;
832 const ip = &pt.zcu.intern_pool;
812833
813834 const ptr_info = res_ty.ptrInfo(self.sema.pt.zcu);
814835
......@@ -820,7 +841,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
820841 if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
821842 switch (node.get(self.file.zoir.?)) {
822843 .string_literal => |val| {
823 const ip_str = try ip.getOrPutString(gpa, self.sema.pt.tid, val, .maybe_embedded_nulls);
844 const ip_str = try ip.getOrPutString(gpa, io, self.sema.pt.tid, val, .maybe_embedded_nulls);
824845 const str_ref = try self.sema.addStrLit(ip_str, val.len);
825846 return (try self.sema.coerce(
826847 self.block,
......@@ -892,7 +913,11 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
892913}
893914
894915fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
895 const ip = &self.sema.pt.zcu.intern_pool;
916 const pt = self.sema.pt;
917 const comp = pt.zcu.comp;
918 const gpa = comp.gpa;
919 const io = comp.io;
920 const ip = &pt.zcu.intern_pool;
896921 try res_ty.resolveFields(self.sema.pt);
897922 const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
898923 const enum_tag_info = union_info.loadTagType(ip);
......@@ -900,7 +925,8 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
900925 const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
901926 .enum_literal => |name| b: {
902927 const field_name = try ip.getOrPutString(
903 self.sema.gpa,
928 gpa,
929 io,
904930 self.sema.pt.tid,
905931 name.get(self.file.zoir.?),
906932 .no_embedded_nulls,
......@@ -916,7 +942,8 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
916942 return error.WrongType;
917943 }
918944 const field_name = try ip.getOrPutString(
919 self.sema.gpa,
945 gpa,
946 io,
920947 self.sema.pt.tid,
921948 fields.names[0].get(self.file.zoir.?),
922949 .no_embedded_nulls,
......@@ -942,7 +969,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
942969 }
943970 break :b .void_value;
944971 };
945 return ip.getUnion(self.sema.pt.zcu.gpa, self.sema.pt.tid, .{
972 return ip.getUnion(gpa, io, self.sema.pt.tid, .{
946973 .ty = res_ty.toIntern(),
947974 .tag = tag.toIntern(),
948975 .val = val,
src/Type.zig+20-14
......@@ -486,6 +486,7 @@ pub fn hasRuntimeBitsInner(
486486 tid: strat.Tid(),
487487) RuntimeBitsError!bool {
488488 const ip = &zcu.intern_pool;
489 const io = zcu.comp.io;
489490 return switch (ty.toIntern()) {
490491 .empty_tuple_type => false,
491492 else => switch (ip.indexToKey(ty.toIntern())) {
......@@ -571,7 +572,7 @@ pub fn hasRuntimeBitsInner(
571572 },
572573 .struct_type => {
573574 const struct_type = ip.loadStructType(ty.toIntern());
574 if (strat != .eager and struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
575 if (strat != .eager and struct_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) {
575576 // In this case, we guess that hasRuntimeBits() for this type is true,
576577 // and then later if our guess was incorrect, we emit a compile error.
577578 return true;
......@@ -610,7 +611,7 @@ pub fn hasRuntimeBitsInner(
610611 .none => if (strat != .eager) {
611612 // In this case, we guess that hasRuntimeBits() for this type is true,
612613 // and then later if our guess was incorrect, we emit a compile error.
613 if (union_type.assumeRuntimeBitsIfFieldTypesWip(ip)) return true;
614 if (union_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) return true;
614615 },
615616 .safety, .tagged => {},
616617 }
......@@ -2491,8 +2492,11 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {
24912492/// resolves field types rather than asserting they are already resolved.
24922493pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
24932494 const zcu = pt.zcu;
2494 var ty = starting_type;
2495 const comp = zcu.comp;
2496 const gpa = comp.gpa;
2497 const io = comp.io;
24952498 const ip = &zcu.intern_pool;
2499 var ty = starting_type;
24962500 while (true) switch (ty.toIntern()) {
24972501 .empty_tuple_type => return Value.empty_tuple,
24982502
......@@ -2664,7 +2668,8 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
26642668 (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
26652669 else
26662670 try ip.getCoercedInts(
2667 zcu.gpa,
2671 gpa,
2672 io,
26682673 pt.tid,
26692674 ip.indexToKey(enum_type.values.get(ip)[0]).int,
26702675 enum_type.tag_ty,
......@@ -2720,6 +2725,7 @@ pub fn comptimeOnlyInner(
27202725 tid: strat.Tid(),
27212726) SemaError!bool {
27222727 const ip = &zcu.intern_pool;
2728 const io = zcu.comp.io;
27232729 return switch (ty.toIntern()) {
27242730 .empty_tuple_type => false,
27252731
......@@ -2798,16 +2804,16 @@ pub fn comptimeOnlyInner(
27982804 .yes => true,
27992805 .unknown => unreachable,
28002806 },
2801 .sema => switch (struct_type.setRequiresComptimeWip(ip)) {
2807 .sema => switch (struct_type.setRequiresComptimeWip(ip, io)) {
28022808 .no, .wip => false,
28032809 .yes => true,
28042810 .unknown => {
28052811 if (struct_type.flagsUnordered(ip).field_types_wip) {
2806 struct_type.setRequiresComptime(ip, .unknown);
2812 struct_type.setRequiresComptime(ip, io, .unknown);
28072813 return false;
28082814 }
28092815
2810 errdefer struct_type.setRequiresComptime(ip, .unknown);
2816 errdefer struct_type.setRequiresComptime(ip, io, .unknown);
28112817
28122818 const pt = strat.pt(zcu, tid);
28132819 try ty.resolveFields(pt);
......@@ -2821,12 +2827,12 @@ pub fn comptimeOnlyInner(
28212827 // be considered resolved. Comptime-only types
28222828 // still maintain a layout of their
28232829 // runtime-known fields.
2824 struct_type.setRequiresComptime(ip, .yes);
2830 struct_type.setRequiresComptime(ip, io, .yes);
28252831 return true;
28262832 }
28272833 }
28282834
2829 struct_type.setRequiresComptime(ip, .no);
2835 struct_type.setRequiresComptime(ip, io, .no);
28302836 return false;
28312837 },
28322838 },
......@@ -2850,16 +2856,16 @@ pub fn comptimeOnlyInner(
28502856 .yes => true,
28512857 .unknown => unreachable,
28522858 },
2853 .sema => switch (union_type.setRequiresComptimeWip(ip)) {
2859 .sema => switch (union_type.setRequiresComptimeWip(ip, io)) {
28542860 .no, .wip => return false,
28552861 .yes => return true,
28562862 .unknown => {
28572863 if (union_type.flagsUnordered(ip).status == .field_types_wip) {
2858 union_type.setRequiresComptime(ip, .unknown);
2864 union_type.setRequiresComptime(ip, io, .unknown);
28592865 return false;
28602866 }
28612867
2862 errdefer union_type.setRequiresComptime(ip, .unknown);
2868 errdefer union_type.setRequiresComptime(ip, io, .unknown);
28632869
28642870 const pt = strat.pt(zcu, tid);
28652871 try ty.resolveFields(pt);
......@@ -2867,12 +2873,12 @@ pub fn comptimeOnlyInner(
28672873 for (0..union_type.field_types.len) |field_idx| {
28682874 const field_ty = union_type.field_types.get(ip)[field_idx];
28692875 if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) {
2870 union_type.setRequiresComptime(ip, .yes);
2876 union_type.setRequiresComptime(ip, io, .yes);
28712877 return true;
28722878 }
28732879 }
28742880
2875 union_type.setRequiresComptime(ip, .no);
2881 union_type.setRequiresComptime(ip, io, .no);
28762882 return false;
28772883 },
28782884 },
src/Value.zig+18-9
......@@ -60,18 +60,21 @@ pub fn fmtValueSemaFull(ctx: print_value.FormatContext) std.fmt.Alt(print_value.
6060/// Asserts `val` is an array of `u8`
6161pub fn toIpString(val: Value, ty: Type, pt: Zcu.PerThread) !InternPool.NullTerminatedString {
6262 const zcu = pt.zcu;
63 const comp = zcu.comp;
64 const gpa = comp.gpa;
65 const io = comp.io;
66 const ip = &zcu.intern_pool;
6367 assert(ty.zigTypeTag(zcu) == .array);
6468 assert(ty.childType(zcu).toIntern() == .u8_type);
65 const ip = &zcu.intern_pool;
6669 switch (zcu.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
6770 .bytes => |bytes| return bytes.toNullTerminatedString(ty.arrayLen(zcu), ip),
6871 .elems => return arrayToIpString(val, ty.arrayLen(zcu), pt),
6972 .repeated_elem => |elem| {
7073 const byte: u8 = @intCast(Value.fromInterned(elem).toUnsignedInt(zcu));
7174 const len: u32 = @intCast(ty.arrayLen(zcu));
72 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(zcu.gpa);
75 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa, io);
7376 try string_bytes.appendNTimes(.{byte}, len);
74 return ip.getOrPutTrailingString(zcu.gpa, pt.tid, len, .no_embedded_nulls);
77 return ip.getOrPutTrailingString(gpa, io, pt.tid, len, .no_embedded_nulls);
7578 },
7679 }
7780}
......@@ -109,10 +112,12 @@ fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, pt: Zcu.Per
109112
110113fn arrayToIpString(val: Value, len_u64: u64, pt: Zcu.PerThread) !InternPool.NullTerminatedString {
111114 const zcu = pt.zcu;
112 const gpa = zcu.gpa;
115 const comp = zcu.comp;
116 const gpa = comp.gpa;
117 const io = comp.io;
113118 const ip = &zcu.intern_pool;
114119 const len: u32 = @intCast(len_u64);
115 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa);
120 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa, io);
116121 try string_bytes.ensureUnusedCapacity(len);
117122 for (0..len) |i| {
118123 // I don't think elemValue has the possibility to affect ip.string_bytes. Let's
......@@ -123,7 +128,7 @@ fn arrayToIpString(val: Value, len_u64: u64, pt: Zcu.PerThread) !InternPool.Null
123128 const byte: u8 = @intCast(elem_val.toUnsignedInt(zcu));
124129 string_bytes.appendAssumeCapacity(.{byte});
125130 }
126 return ip.getOrPutTrailingString(gpa, pt.tid, len, .no_embedded_nulls);
131 return ip.getOrPutTrailingString(gpa, io, pt.tid, len, .no_embedded_nulls);
127132}
128133
129134pub fn fromInterned(i: InternPool.Index) Value {
......@@ -1141,6 +1146,7 @@ pub fn sliceArray(
11411146) error{OutOfMemory}!Value {
11421147 const pt = sema.pt;
11431148 const ip = &pt.zcu.intern_pool;
1149 const io = pt.zcu.comp.io;
11441150 return Value.fromInterned(try pt.intern(.{
11451151 .aggregate = .{
11461152 .ty = switch (pt.zcu.intern_pool.indexToKey(pt.zcu.intern_pool.typeOf(val.toIntern()))) {
......@@ -1160,6 +1166,7 @@ pub fn sliceArray(
11601166 try ip.string_bytes.ensureUnusedCapacity(sema.gpa, end - start + 1);
11611167 break :storage .{ .bytes = try ip.getOrPutString(
11621168 sema.gpa,
1169 io,
11631170 bytes.toSlice(end, ip)[start..],
11641171 .maybe_embedded_nulls,
11651172 ) };
......@@ -2874,6 +2881,7 @@ const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_optio
28742881/// `val` must be fully resolved.
28752882pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T {
28762883 const zcu = pt.zcu;
2884 const io = zcu.comp.io;
28772885 const ip = &zcu.intern_pool;
28782886 const ty = val.typeOf(zcu);
28792887 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;
......@@ -2960,7 +2968,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
29602968 const struct_obj = zcu.typeToStruct(ty) orelse return error.TypeMismatch;
29612969 var result: T = undefined;
29622970 inline for (@"struct".fields) |field| {
2963 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls);
2971 const field_name_ip = try ip.getOrPutString(zcu.gpa, io, pt.tid, field.name, .no_embedded_nulls);
29642972 @field(result, field.name) = if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| f: {
29652973 const field_val = try val.fieldValue(pt, field_idx);
29662974 break :f try field_val.interpret(field.type, pt);
......@@ -2979,6 +2987,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
29792987 const T = @TypeOf(val);
29802988
29812989 const zcu = pt.zcu;
2990 const io = zcu.comp.io;
29822991 const ip = &zcu.intern_pool;
29832992 if (ty.zigTypeTag(zcu) != @typeInfo(T)) return error.TypeMismatch;
29842993
......@@ -3022,7 +3031,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
30223031 .@"enum" => switch (interpret_mode) {
30233032 .direct => try pt.enumValue(ty, (try uninterpret(@intFromEnum(val), ty.intTagType(zcu), pt)).toIntern()),
30243033 .by_name => {
3025 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, @tagName(val), .no_embedded_nulls);
3034 const field_name_ip = try ip.getOrPutString(zcu.gpa, io, pt.tid, @tagName(val), .no_embedded_nulls);
30263035 const field_idx = ty.enumFieldIndex(field_name_ip, zcu) orelse return error.TypeMismatch;
30273036 return pt.enumValueFieldIndex(ty, field_idx);
30283037 },
......@@ -3059,7 +3068,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
30593068 defer zcu.gpa.free(field_vals);
30603069 @memset(field_vals, .none);
30613070 inline for (@"struct".fields) |field| {
3062 const field_name_ip = try ip.getOrPutString(zcu.gpa, pt.tid, field.name, .no_embedded_nulls);
3071 const field_name_ip = try ip.getOrPutString(zcu.gpa, io, pt.tid, field.name, .no_embedded_nulls);
30633072 if (struct_obj.nameIndex(ip, field_name_ip)) |field_idx| {
30643073 const field_ty = ty.fieldType(field_idx, zcu);
30653074 field_vals[field_idx] = (try uninterpret(@field(val, field.name), field_ty, pt)).toIntern();
src/Zcu.zig+196-17
......@@ -37,6 +37,7 @@ const InternPool = @import("InternPool.zig");
3737const Alignment = InternPool.Alignment;
3838const AnalUnit = InternPool.AnalUnit;
3939const BuiltinFn = std.zig.BuiltinFn;
40const codegen = @import("codegen.zig");
4041const LlvmObject = @import("codegen/llvm.zig").Object;
4142const dev = @import("dev.zig");
4243const Zoir = std.zig.Zoir;
......@@ -317,6 +318,8 @@ incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalD
317318/// this timer must be temporarily paused and resumed later.
318319cur_analysis_timer: ?Compilation.Timer = null,
319320
321codegen_task_pool: CodegenTaskPool,
322
320323generation: u32 = 0,
321324
322325pub const IncrementalDebugState = struct {
......@@ -895,12 +898,13 @@ pub const Namespace = struct {
895898 ns: Namespace,
896899 ip: *InternPool,
897900 gpa: Allocator,
901 io: Io,
898902 tid: Zcu.PerThread.Id,
899903 name: InternPool.NullTerminatedString,
900904 ) !InternPool.NullTerminatedString {
901905 const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip);
902906 if (name == .empty) return ns_name;
903 return ip.getOrPutStringFmt(gpa, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
907 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
904908 }
905909};
906910
......@@ -1139,13 +1143,15 @@ pub const File = struct {
11391143 }
11401144
11411145 pub fn internFullyQualifiedName(file: File, pt: Zcu.PerThread) !InternPool.NullTerminatedString {
1142 const gpa = pt.zcu.gpa;
11431146 const ip = &pt.zcu.intern_pool;
1144 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa);
1147 const comp = pt.zcu.comp;
1148 const gpa = comp.gpa;
1149 const io = comp.io;
1150 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa, io);
11451151 var w: Writer = .fixed((try string_bytes.addManyAsSlice(file.fullyQualifiedNameLen()))[0]);
11461152 file.renderFullyQualifiedName(&w) catch unreachable;
11471153 assert(w.end == w.buffer.len);
1148 return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(w.end), .no_embedded_nulls);
1154 return ip.getOrPutTrailingString(gpa, io, pt.tid, @intCast(w.end), .no_embedded_nulls);
11491155 }
11501156
11511157 pub const Index = InternPool.FileIndex;
......@@ -2801,13 +2807,14 @@ pub const CompileError = error{
28012807 ComptimeBreak,
28022808};
28032809
2804pub fn init(zcu: *Zcu, thread_count: usize) !void {
2805 const gpa = zcu.gpa;
2806 try zcu.intern_pool.init(gpa, thread_count);
2810pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {
2811 try zcu.intern_pool.init(gpa, io, thread_count);
28072812}
28082813
28092814pub fn deinit(zcu: *Zcu) void {
2810 const gpa = zcu.gpa;
2815 const comp = zcu.comp;
2816 const gpa = comp.gpa;
2817 const io = comp.io;
28112818 {
28122819 const pt: Zcu.PerThread = .activate(zcu, .main);
28132820 defer pt.deactivate();
......@@ -2897,7 +2904,7 @@ pub fn deinit(zcu: *Zcu) void {
28972904 zcu.incremental_debug_state.deinit(gpa);
28982905 }
28992906 }
2900 zcu.intern_pool.deinit(gpa);
2907 zcu.intern_pool.deinit(gpa, io);
29012908}
29022909
29032910pub fn namespacePtr(zcu: *Zcu, index: Namespace.Index) *Namespace {
......@@ -4442,7 +4449,7 @@ pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {
44424449 try zcu.outdated_ready.put(gpa, unit, {});
44434450 }
44444451 }
4445 zcu.intern_pool.funcSetIesResolved(func_index, .none);
4452 zcu.intern_pool.funcSetIesResolved(zcu.comp.io, func_index, .none);
44464453 }
44474454}
44484455
......@@ -4620,10 +4627,12 @@ pub fn codegenFail(
46204627
46214628/// Takes ownership of `msg`, even on OOM.
46224629pub fn codegenFailMsg(zcu: *Zcu, nav_index: InternPool.Nav.Index, msg: *ErrorMsg) CodegenFailError {
4623 const gpa = zcu.gpa;
4630 const comp = zcu.comp;
4631 const gpa = comp.gpa;
4632 const io = comp.io;
46244633 {
4625 zcu.comp.mutex.lock();
4626 defer zcu.comp.mutex.unlock();
4634 comp.mutex.lockUncancelable(io);
4635 defer comp.mutex.unlock(io);
46274636 errdefer msg.deinit(gpa);
46284637 try zcu.failed_codegen.putNoClobber(gpa, nav_index, msg);
46294638 }
......@@ -4632,8 +4641,10 @@ pub fn codegenFailMsg(zcu: *Zcu, nav_index: InternPool.Nav.Index, msg: *ErrorMsg
46324641
46334642/// Asserts that `zcu.failed_codegen` contains the key `nav`, with the necessary lock held.
46344643pub fn assertCodegenFailed(zcu: *Zcu, nav: InternPool.Nav.Index) void {
4635 zcu.comp.mutex.lock();
4636 defer zcu.comp.mutex.unlock();
4644 const comp = zcu.comp;
4645 const io = comp.io;
4646 comp.mutex.lockUncancelable(io);
4647 defer comp.mutex.unlock(io);
46374648 assert(zcu.failed_codegen.contains(nav));
46384649}
46394650
......@@ -4794,8 +4805,9 @@ const TrackedUnitSema = struct {
47944805 report_time: {
47954806 const sema_ns = zcu.cur_analysis_timer.?.finish() orelse break :report_time;
47964807 const zir_decl = tus.analysis_timer_decl orelse break :report_time;
4797 comp.mutex.lock();
4798 defer comp.mutex.unlock();
4808 const io = comp.io;
4809 comp.mutex.lockUncancelable(io);
4810 defer comp.mutex.unlock(io);
47994811 comp.time_report.?.stats.cpu_ns_sema += sema_ns;
48004812 const gop = comp.time_report.?.decl_sema_info.getOrPut(comp.gpa, zir_decl) catch |err| switch (err) {
48014813 error.OutOfMemory => {
......@@ -4830,3 +4842,170 @@ pub fn trackUnitSema(zcu: *Zcu, name: []const u8, zir_inst: ?InternPool.TrackedI
48304842 .analysis_timer_decl = zir_inst,
48314843 };
48324844}
4845
4846pub const CodegenTaskPool = struct {
4847 const CodegenResult = PerThread.RunCodegenError!codegen.AnyMir;
4848
4849 /// In the worst observed case, MIR is around 50 times as large as AIR. More typically, the ratio is
4850 /// around 20. Going by that 50x multiplier, and assuming we want to consume no more than 500 MiB of
4851 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight.
4852 const max_air_bytes_in_flight = 10 * 1024 * 1024;
4853
4854 const max_funcs_in_flight = @import("link.zig").Queue.buffer_size;
4855
4856 available_air_bytes: u32,
4857
4858 /// Locks the freelist and `available_air_bytes`.
4859 mutex: Io.Mutex,
4860
4861 /// Signaled when an item is added to the freelist.
4862 free_cond: Io.Condition,
4863 /// Pre-allocated with enough capacity for all indices.
4864 free: std.ArrayList(Index),
4865
4866 /// `.none` means this task is in the freelist. The `task_air_bytes` and
4867 /// `task_futures` entries are `undefined`.
4868 task_funcs: []InternPool.Index,
4869 task_air_bytes: []u32,
4870 task_futures: []Io.Future(CodegenResult),
4871
4872 pub fn init(arena: Allocator) Allocator.Error!CodegenTaskPool {
4873 const task_funcs = try arena.alloc(InternPool.Index, max_funcs_in_flight);
4874 const task_air_bytes = try arena.alloc(u32, max_funcs_in_flight);
4875 const task_futures = try arena.alloc(Io.Future(CodegenResult), max_funcs_in_flight);
4876 @memset(task_funcs, .none);
4877
4878 var free: std.ArrayList(Index) = try .initCapacity(arena, max_funcs_in_flight);
4879 for (0..max_funcs_in_flight) |index| free.appendAssumeCapacity(@enumFromInt(index));
4880
4881 return .{
4882 .available_air_bytes = max_air_bytes_in_flight,
4883 .mutex = .init,
4884 .free_cond = .init,
4885 .free = free,
4886 .task_funcs = task_funcs,
4887 .task_air_bytes = task_air_bytes,
4888 .task_futures = task_futures,
4889 };
4890 }
4891
4892 pub fn cancel(pool: *CodegenTaskPool, zcu: *const Zcu) void {
4893 const io = zcu.comp.io;
4894 for (
4895 pool.task_funcs,
4896 pool.task_air_bytes,
4897 pool.task_futures,
4898 ) |func, effective_air_bytes, *future| {
4899 if (func == .none) continue;
4900 pool.available_air_bytes += effective_air_bytes;
4901 var mir = future.cancel(io) catch continue;
4902 mir.deinit(zcu);
4903 }
4904 assert(pool.available_air_bytes == max_air_bytes_in_flight);
4905 }
4906
4907 pub fn start(
4908 pool: *CodegenTaskPool,
4909 zcu: *Zcu,
4910 func_index: InternPool.Index,
4911 air: *Air,
4912 /// If `true`, this function will take ownership of `air`, freeing it after codegen
4913 /// completes; it is not assumed that `air` will outlive this function. If `false`,
4914 /// codegen will operate on `air` via the given pointer, which it is assumed will
4915 /// outline the codegen task.
4916 move_air: bool,
4917 ) Io.Cancelable!Index {
4918 const io = zcu.comp.io;
4919
4920 // To avoid consuming an excessive amount of memory, there is a limit on the total number of AIR
4921 // bytes which can be in the codegen/link pipeline at one time. If we exceed this limit, we must
4922 // wait for codegen/link to finish some WIP functions so they catch up with us.
4923 const actual_air_bytes: u32 = @intCast(air.instructions.len * 5 + air.extra.items.len * 4);
4924 // We need to let all AIR through eventually, even if one function exceeds `max_air_bytes_in_flight`.
4925 const effective_air_bytes: u32 = @min(actual_air_bytes, max_air_bytes_in_flight);
4926 assert(effective_air_bytes > 0);
4927
4928 const index: Index = index: {
4929 try pool.mutex.lock(io);
4930 defer pool.mutex.unlock(io);
4931
4932 while (pool.free.items.len == 0 or pool.available_air_bytes < effective_air_bytes) {
4933 // The linker thread needs to catch up!
4934 try pool.free_cond.wait(io, &pool.mutex);
4935 }
4936
4937 pool.available_air_bytes -= effective_air_bytes;
4938 break :index pool.free.pop().?;
4939 };
4940
4941 // No turning back now: we're incrementing `pending_codegen_jobs` and starting the worker.
4942 errdefer comptime unreachable;
4943
4944 assert(zcu.pending_codegen_jobs.fetchAdd(1, .monotonic) > 0); // the "Code Generation" node is still active
4945 assert(pool.task_funcs[@intFromEnum(index)] == .none);
4946 pool.task_funcs[@intFromEnum(index)] = func_index;
4947 pool.task_air_bytes[@intFromEnum(index)] = actual_air_bytes;
4948 pool.task_futures[@intFromEnum(index)] = if (move_air) io.async(
4949 workerCodegenOwnedAir,
4950 .{ zcu, func_index, air.* },
4951 ) else io.async(
4952 workerCodegenExternalAir,
4953 .{ zcu, func_index, air },
4954 );
4955
4956 return index;
4957 }
4958 pub const Index = enum(u32) {
4959 _,
4960
4961 /// Blocks until codegen has completed, successfully or otherwise.
4962 /// The returned MIR is owned by the caller.
4963 pub fn wait(
4964 index: Index,
4965 pool: *CodegenTaskPool,
4966 io: Io,
4967 ) PerThread.RunCodegenError!struct { InternPool.Index, codegen.AnyMir } {
4968 const func = pool.task_funcs[@intFromEnum(index)];
4969 assert(func != .none);
4970 const effective_air_bytes = pool.task_air_bytes[@intFromEnum(index)];
4971 const result = pool.task_futures[@intFromEnum(index)].await(io);
4972
4973 pool.task_funcs[@intFromEnum(index)] = .none;
4974 pool.task_air_bytes[@intFromEnum(index)] = undefined;
4975 pool.task_futures[@intFromEnum(index)] = undefined;
4976
4977 {
4978 pool.mutex.lockUncancelable(io);
4979 defer pool.mutex.unlock(io);
4980 pool.available_air_bytes += effective_air_bytes;
4981 pool.free.appendAssumeCapacity(index);
4982 pool.free_cond.signal(io);
4983 }
4984
4985 return .{ func, try result };
4986 }
4987 };
4988 fn workerCodegenOwnedAir(
4989 zcu: *Zcu,
4990 func_index: InternPool.Index,
4991 orig_air: Air,
4992 ) CodegenResult {
4993 // We own `air` now, so we are responsbile for freeing it.
4994 var air = orig_air;
4995 defer air.deinit(zcu.comp.gpa);
4996 const tid = Compilation.getTid();
4997 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
4998 defer pt.deactivate();
4999 return pt.runCodegen(func_index, &air);
5000 }
5001 fn workerCodegenExternalAir(
5002 zcu: *Zcu,
5003 func_index: InternPool.Index,
5004 air: *Air,
5005 ) CodegenResult {
5006 const tid = Compilation.getTid();
5007 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
5008 defer pt.deactivate();
5009 return pt.runCodegen(func_index, air);
5010 }
5011};
src/Zcu/PerThread.zig+177-121
......@@ -269,8 +269,8 @@ pub fn updateFile(
269269 // Any potential AST errors are converted to ZIR errors when we run AstGen/ZonGen.
270270 file.tree = try Ast.parse(gpa, source, file.getMode());
271271 if (timer.finish()) |ns_parse| {
272 comp.mutex.lock();
273 defer comp.mutex.unlock();
272 comp.mutex.lockUncancelable(io);
273 defer comp.mutex.unlock(io);
274274 comp.time_report.?.stats.cpu_ns_parse += ns_parse;
275275 }
276276
......@@ -295,8 +295,8 @@ pub fn updateFile(
295295 },
296296 }
297297 if (timer.finish()) |ns_astgen| {
298 comp.mutex.lock();
299 defer comp.mutex.unlock();
298 comp.mutex.lockUncancelable(io);
299 defer comp.mutex.unlock(io);
300300 comp.time_report.?.stats.cpu_ns_astgen += ns_astgen;
301301 }
302302
......@@ -315,8 +315,8 @@ pub fn updateFile(
315315 switch (file.getMode()) {
316316 .zig => {
317317 if (file.zir.?.hasCompileErrors()) {
318 comp.mutex.lock();
319 defer comp.mutex.unlock();
318 comp.mutex.lockUncancelable(io);
319 defer comp.mutex.unlock(io);
320320 try zcu.failed_files.putNoClobber(gpa, file_index, null);
321321 }
322322 if (file.zir.?.loweringFailed()) {
......@@ -328,8 +328,8 @@ pub fn updateFile(
328328 .zon => {
329329 if (file.zoir.?.hasCompileErrors()) {
330330 file.status = .astgen_failure;
331 comp.mutex.lock();
332 defer comp.mutex.unlock();
331 comp.mutex.lockUncancelable(io);
332 defer comp.mutex.unlock(io);
333333 try zcu.failed_files.putNoClobber(gpa, file_index, null);
334334 } else {
335335 file.status = .success;
......@@ -415,7 +415,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
415415 const zcu = pt.zcu;
416416 const comp = zcu.comp;
417417 const ip = &zcu.intern_pool;
418 const gpa = zcu.gpa;
418 const gpa = comp.gpa;
419 const io = comp.io;
419420
420421 // We need to visit every updated File for every TrackedInst in InternPool.
421422 // This only includes Zig files; ZON files are omitted.
......@@ -459,7 +460,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
459460 return;
460461
461462 for (ip.locals, 0..) |*local, tid| {
462 const tracked_insts_list = local.getMutableTrackedInsts(gpa);
463 const tracked_insts_list = local.getMutableTrackedInsts(gpa, io);
463464 for (tracked_insts_list.viewAllowEmpty().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {
464465 const file_index = tracked_inst.file;
465466 const updated_file = updated_files.get(file_index) orelse continue;
......@@ -530,6 +531,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
530531 if (old_decl.name == .empty) continue;
531532 const name_ip = try zcu.intern_pool.getOrPutString(
532533 zcu.gpa,
534 io,
533535 pt.tid,
534536 old_zir.nullTerminatedString(old_decl.name),
535537 .no_embedded_nulls,
......@@ -545,6 +547,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
545547 if (new_decl.name == .empty) continue;
546548 const name_ip = try zcu.intern_pool.getOrPutString(
547549 zcu.gpa,
550 io,
548551 pt.tid,
549552 new_zir.nullTerminatedString(new_decl.name),
550553 .no_embedded_nulls,
......@@ -575,7 +578,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
575578 }
576579 }
577580
578 try ip.rehashTrackedInsts(gpa, pt.tid);
581 try ip.rehashTrackedInsts(gpa, io, pt.tid);
579582
580583 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
581584 const file = updated_file.file;
......@@ -700,7 +703,9 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
700703fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool {
701704 const zcu = pt.zcu;
702705 const ip = &zcu.intern_pool;
703 const gpa = zcu.gpa;
706 const comp = zcu.comp;
707 const gpa = comp.gpa;
708 const io = comp.io;
704709
705710 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
706711
......@@ -716,7 +721,7 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage)
716721 const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index));
717722 const std_namespace = std_type.getNamespaceIndex(zcu);
718723 try pt.ensureNamespaceUpToDate(std_namespace);
719 const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
724 const builtin_str = try ip.getOrPutString(gpa, io, pt.tid, "builtin", .no_embedded_nulls);
720725 const builtin_nav = zcu.namespacePtr(std_namespace).pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
721726 @panic("lib/std.zig is corrupt and missing 'builtin'");
722727 try pt.ensureNavValUpToDate(builtin_nav);
......@@ -857,8 +862,10 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
857862/// to `transitive_failed_analysis` if necessary.
858863fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void {
859864 const zcu = pt.zcu;
860 const gpa = zcu.gpa;
861865 const ip = &zcu.intern_pool;
866 const comp = zcu.comp;
867 const gpa = comp.gpa;
868 const io = comp.io;
862869
863870 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
864871 const comptime_unit = ip.getComptimeUnit(cu_id);
......@@ -909,7 +916,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
909916 .r = .{ .simple = .comptime_keyword },
910917 } },
911918 .src_base_inst = comptime_unit.zir_index,
912 .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.comptime", .{
919 .type_name_ctx = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.comptime", .{
913920 Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip),
914921 }, .no_embedded_nulls),
915922 };
......@@ -1087,8 +1094,10 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
10871094
10881095fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } {
10891096 const zcu = pt.zcu;
1090 const gpa = zcu.gpa;
10911097 const ip = &zcu.intern_pool;
1098 const comp = zcu.comp;
1099 const gpa = comp.gpa;
1100 const io = comp.io;
10921101
10931102 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
10941103 const old_nav = ip.getNav(nav_id);
......@@ -1253,7 +1262,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12531262 break :val .fromInterned(try pt.getExtern(.{
12541263 .name = old_nav.name,
12551264 .ty = nav_ty.toIntern(),
1256 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1265 .lib_name = try ip.getOrPutStringOpt(gpa, io, pt.tid, lib_name, .no_embedded_nulls),
12571266 .is_threadlocal = zir_decl.is_threadlocal,
12581267 .linkage = .strong,
12591268 .visibility = .default,
......@@ -1310,7 +1319,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13101319 }
13111320 }
13121321
1313 ip.resolveNavValue(nav_id, .{
1322 ip.resolveNavValue(io, nav_id, .{
13141323 .val = nav_val.toIntern(),
13151324 .is_const = is_const,
13161325 .alignment = modifiers.alignment,
......@@ -1327,7 +1336,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13271336 if (zir_decl.linkage == .@"export") {
13281337 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });
13291338 const name_slice = zir.nullTerminatedString(zir_decl.name);
1330 const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
1339 const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
13311340 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id);
13321341 }
13331342
......@@ -1472,7 +1481,9 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
14721481
14731482fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } {
14741483 const zcu = pt.zcu;
1475 const gpa = zcu.gpa;
1484 const comp = zcu.comp;
1485 const gpa = comp.gpa;
1486 const io = comp.io;
14761487 const ip = &zcu.intern_pool;
14771488
14781489 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
......@@ -1579,7 +1590,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15791590
15801591 if (!changed) return .{ .type_changed = false };
15811592
1582 ip.resolveNavType(nav_id, .{
1593 ip.resolveNavType(io, nav_id, .{
15831594 .type = resolved_ty.toIntern(),
15841595 .is_const = is_const,
15851596 .alignment = modifiers.alignment,
......@@ -1775,6 +1786,7 @@ fn createFileRootStruct(
17751786) Allocator.Error!InternPool.Index {
17761787 const zcu = pt.zcu;
17771788 const gpa = zcu.gpa;
1789 const io = zcu.comp.io;
17781790 const ip = &zcu.intern_pool;
17791791 const file = zcu.fileByIndex(file_index);
17801792 const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
......@@ -1797,11 +1809,11 @@ fn createFileRootStruct(
17971809 const decls = file.zir.?.bodySlice(extra_index, decls_len);
17981810 extra_index += decls_len;
17991811
1800 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
1812 const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
18011813 .file = file_index,
18021814 .inst = .main_struct_inst,
18031815 });
1804 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
1816 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
18051817 .layout = .auto,
18061818 .fields_len = fields_len,
18071819 .known_non_opv = small.known_non_opv,
......@@ -1916,7 +1928,9 @@ pub fn discoverImport(
19161928 },
19171929} {
19181930 const zcu = pt.zcu;
1919 const gpa = zcu.gpa;
1931 const comp = zcu.comp;
1932 const io = comp.io;
1933 const gpa = comp.gpa;
19201934
19211935 if (!mem.endsWith(u8, import_string, ".zig") and !mem.endsWith(u8, import_string, ".zon")) {
19221936 return .module;
......@@ -1926,8 +1940,8 @@ pub fn discoverImport(
19261940 errdefer new_path.deinit(gpa);
19271941
19281942 // We're about to do a GOP on `import_table`, so we need the mutex.
1929 zcu.comp.mutex.lock();
1930 defer zcu.comp.mutex.unlock();
1943 comp.mutex.lockUncancelable(io);
1944 defer comp.mutex.unlock(io);
19311945
19321946 const gop = try zcu.import_table.getOrPutAdapted(gpa, new_path, Zcu.ImportTableAdapter{ .zcu = zcu });
19331947 errdefer _ = zcu.import_table.pop();
......@@ -1942,7 +1956,7 @@ pub fn discoverImport(
19421956 const new_file = try gpa.create(Zcu.File);
19431957 errdefer gpa.destroy(new_file);
19441958
1945 const new_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
1959 const new_file_index = try zcu.intern_pool.createFile(gpa, io, pt.tid, .{
19461960 .bin_digest = new_path.digest(),
19471961 .file = new_file,
19481962 .root_type = .none,
......@@ -2027,7 +2041,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
20272041 IllegalZigImport,
20282042}!void {
20292043 const zcu = pt.zcu;
2030 const gpa = zcu.gpa;
2044 const comp = zcu.comp;
2045 const gpa = comp.gpa;
2046 const io = comp.io;
20312047
20322048 // We'll initially add [mod, undefined] pairs, and when we reach the pair while
20332049 // iterating, rewrite the undefined value.
......@@ -2085,7 +2101,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
20852101 const new_file = try gpa.create(Zcu.File);
20862102 errdefer gpa.destroy(new_file);
20872103
2088 const new_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
2104 const new_file_index = try zcu.intern_pool.createFile(gpa, io, pt.tid, .{
20892105 .bin_digest = path.digest(),
20902106 .file = new_file,
20912107 .root_type = .none,
......@@ -2291,7 +2307,8 @@ pub fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool {
22912307pub fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!void {
22922308 const zcu = pt.zcu;
22932309 const comp = zcu.comp;
2294 const gpa = zcu.gpa;
2310 const gpa = comp.gpa;
2311 const io = comp.io;
22952312
22962313 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());
22972314 if (gop.found_existing) return; // the `File` is up-to-date
......@@ -2330,7 +2347,7 @@ pub fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!voi
23302347 .zoir_invalidated = false,
23312348 };
23322349
2333 const file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
2350 const file_index = try zcu.intern_pool.createFile(gpa, io, pt.tid, .{
23342351 .bin_digest = path.digest(),
23352352 .file = file,
23362353 .root_type = .none,
......@@ -2469,7 +2486,7 @@ fn updateEmbedFileInner(
24692486
24702487 // The loaded bytes of the file, including a sentinel 0 byte.
24712488 const ip_str: InternPool.String = str: {
2472 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa);
2489 const string_bytes = ip.getLocal(tid).getMutableStringBytes(gpa, io);
24732490 const old_len = string_bytes.mutate.len;
24742491 errdefer string_bytes.shrinkRetainingCapacity(old_len);
24752492 const bytes = (try string_bytes.addManyAsSlice(size_plus_one))[0];
......@@ -2480,7 +2497,7 @@ fn updateEmbedFileInner(
24802497 error.EndOfStream => return error.UnexpectedEof,
24812498 };
24822499 bytes[size] = 0;
2483 break :str try ip.getOrPutTrailingString(gpa, tid, @intCast(bytes.len), .maybe_embedded_nulls);
2500 break :str try ip.getOrPutTrailingString(gpa, io, tid, @intCast(bytes.len), .maybe_embedded_nulls);
24842501 };
24852502 if (ip_str_out) |p| p.* = ip_str;
24862503
......@@ -2516,7 +2533,8 @@ fn newEmbedFile(
25162533) !*Zcu.EmbedFile {
25172534 const zcu = pt.zcu;
25182535 const comp = zcu.comp;
2519 const gpa = zcu.gpa;
2536 const io = comp.io;
2537 const gpa = comp.gpa;
25202538 const ip = &zcu.intern_pool;
25212539
25222540 const new_file = try gpa.create(Zcu.EmbedFile);
......@@ -2549,8 +2567,8 @@ fn newEmbedFile(
25492567 const path_str = try path.toAbsolute(comp.dirs, gpa);
25502568 defer gpa.free(path_str);
25512569
2552 whole.cache_manifest_mutex.lock();
2553 defer whole.cache_manifest_mutex.unlock();
2570 try whole.cache_manifest_mutex.lock(io);
2571 defer whole.cache_manifest_mutex.unlock(io);
25542572
25552573 man.addFilePostContents(path_str, contents, new_file.stat) catch |err| switch (err) {
25562574 error.Unexpected => unreachable,
......@@ -2647,13 +2665,15 @@ const ScanDeclIter = struct {
26472665
26482666 fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString {
26492667 const pt = iter.pt;
2650 const gpa = pt.zcu.gpa;
26512668 const ip = &pt.zcu.intern_pool;
2652 var name = try ip.getOrPutStringFmt(gpa, pt.tid, fmt, args, .no_embedded_nulls);
2669 const comp = pt.zcu.comp;
2670 const gpa = comp.gpa;
2671 const io = comp.io;
2672 var name = try ip.getOrPutStringFmt(gpa, io, pt.tid, fmt, args, .no_embedded_nulls);
26532673 var gop = try iter.seen_decls.getOrPut(gpa, name);
26542674 var next_suffix: u32 = 0;
26552675 while (gop.found_existing) {
2656 name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
2676 name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
26572677 gop = try iter.seen_decls.getOrPut(gpa, name);
26582678 next_suffix += 1;
26592679 }
......@@ -2669,7 +2689,8 @@ const ScanDeclIter = struct {
26692689 const comp = zcu.comp;
26702690 const namespace_index = iter.namespace_index;
26712691 const namespace = zcu.namespacePtr(namespace_index);
2672 const gpa = zcu.gpa;
2692 const gpa = comp.gpa;
2693 const io = comp.io;
26732694 const file = namespace.fileScope(zcu);
26742695 const zir = file.zir.?;
26752696 const ip = &zcu.intern_pool;
......@@ -2697,6 +2718,7 @@ const ScanDeclIter = struct {
26972718 if (iter.pass != .named) return;
26982719 const name = try ip.getOrPutString(
26992720 gpa,
2721 io,
27002722 pt.tid,
27012723 zir.nullTerminatedString(decl.name),
27022724 .no_embedded_nulls,
......@@ -2706,7 +2728,7 @@ const ScanDeclIter = struct {
27062728 },
27072729 };
27082730
2709 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
2731 const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
27102732 .file = namespace.file_scope,
27112733 .inst = decl_inst,
27122734 });
......@@ -2718,7 +2740,7 @@ const ScanDeclIter = struct {
27182740 const cu = if (existing_unit) |eu|
27192741 eu.unwrap().@"comptime"
27202742 else
2721 try ip.createComptimeUnit(gpa, pt.tid, tracked_inst, namespace_index);
2743 try ip.createComptimeUnit(gpa, io, pt.tid, tracked_inst, namespace_index);
27222744
27232745 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
27242746
......@@ -2737,9 +2759,9 @@ const ScanDeclIter = struct {
27372759 },
27382760 else => unit: {
27392761 const name = maybe_name.unwrap().?;
2740 const fqn = try namespace.internFullyQualifiedName(ip, gpa, pt.tid, name);
2762 const fqn = try namespace.internFullyQualifiedName(ip, gpa, io, pt.tid, name);
27412763 const nav = if (existing_unit) |eu| eu.unwrap().nav_val else nav: {
2742 const nav = try ip.createDeclNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index);
2764 const nav = try ip.createDeclNav(gpa, io, pt.tid, name, fqn, tracked_inst, namespace_index);
27432765 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
27442766 break :nav nav;
27452767 };
......@@ -2798,7 +2820,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
27982820 defer tracy.end();
27992821
28002822 const zcu = pt.zcu;
2801 const gpa = zcu.gpa;
2823 const comp = zcu.comp;
2824 const gpa = comp.gpa;
2825 const io = comp.io;
28022826 const ip = &zcu.intern_pool;
28032827
28042828 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
......@@ -2810,9 +2834,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
28102834 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
28112835 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
28122836
2813 func.setAnalyzed(ip);
2837 func.setAnalyzed(ip, io);
28142838 if (func.analysisUnordered(ip).inferred_error_set) {
2815 func.setResolvedErrorSet(ip, .none);
2839 func.setResolvedErrorSet(ip, io, .none);
28162840 }
28172841
28182842 if (zcu.comp.time_report) |*tr| {
......@@ -2872,7 +2896,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
28722896 }
28732897
28742898 // reset in case calls to errorable functions are removed.
2875 ip.funcSetHasErrorTrace(func_index, fn_ty_info.cc == .auto);
2899 ip.funcSetHasErrorTrace(io, func_index, fn_ty_info.cc == .auto);
28762900
28772901 // First few indexes of extra are reserved and set at the end.
28782902 const reserved_count = @typeInfo(Air.ExtraIndex).@"enum".fields.len;
......@@ -2971,7 +2995,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
29712995 });
29722996 }
29732997
2974 func.setBranchHint(ip, sema.branch_hint orelse .none);
2998 func.setBranchHint(ip, io, sema.branch_hint orelse .none);
29752999
29763000 if (zcu.comp.config.any_error_tracing and func.analysisUnordered(ip).has_error_trace and fn_ty_info.cc != .auto) {
29773001 // We're using an error trace, but didn't start out with one from the caller.
......@@ -3005,7 +3029,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
30053029 else => |e| return e,
30063030 };
30073031 assert(ies.resolved != .none);
3008 func.setResolvedErrorSet(ip, ies.resolved);
3032 func.setResolvedErrorSet(ip, io, ies.resolved);
30093033 }
30103034
30113035 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
......@@ -3036,7 +3060,8 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
30363060}
30373061
30383062pub fn createNamespace(pt: Zcu.PerThread, initialization: Zcu.Namespace) !Zcu.Namespace.Index {
3039 return pt.zcu.intern_pool.createNamespace(pt.zcu.gpa, pt.tid, initialization);
3063 const comp = pt.zcu.comp;
3064 return pt.zcu.intern_pool.createNamespace(comp.gpa, comp.io, pt.tid, initialization);
30403065}
30413066
30423067pub fn destroyNamespace(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) void {
......@@ -3047,11 +3072,15 @@ pub fn getErrorValue(
30473072 pt: Zcu.PerThread,
30483073 name: InternPool.NullTerminatedString,
30493074) Allocator.Error!Zcu.ErrorInt {
3050 return pt.zcu.intern_pool.getErrorValue(pt.zcu.gpa, pt.tid, name);
3075 const comp = pt.zcu.comp;
3076 return pt.zcu.intern_pool.getErrorValue(comp.gpa, comp.io, pt.tid, name);
30513077}
30523078
30533079pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Zcu.ErrorInt {
3054 return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, name));
3080 const comp = pt.zcu.comp;
3081 const gpa = comp.gpa;
3082 const io = comp.io;
3083 return pt.getErrorValue(try pt.zcu.intern_pool.getOrPutString(gpa, io, name));
30553084}
30563085
30573086/// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed.
......@@ -3078,8 +3107,10 @@ fn lockAndClearFileCompileError(pt: Zcu.PerThread, file_index: Zcu.File.Index, f
30783107 return;
30793108 }
30803109
3081 pt.zcu.comp.mutex.lock();
3082 defer pt.zcu.comp.mutex.unlock();
3110 const comp = pt.zcu.comp;
3111 const io = comp.io;
3112 comp.mutex.lockUncancelable(io);
3113 defer comp.mutex.unlock(io);
30833114 if (pt.zcu.failed_files.fetchSwapRemove(file_index)) |kv| {
30843115 assert(maybe_has_error); // the runtime safety case above
30853116 if (kv.value) |msg| pt.zcu.gpa.free(msg); // delete previous error message
......@@ -3266,7 +3297,9 @@ fn processExportsInner(
32663297
32673298pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
32683299 const zcu = pt.zcu;
3269 const gpa = zcu.gpa;
3300 const comp = zcu.comp;
3301 const gpa = comp.gpa;
3302 const io = comp.io;
32703303 const ip = &zcu.intern_pool;
32713304
32723305 // Our job is to correctly set the value of the `test_functions` declaration if it has been
......@@ -3284,7 +3317,7 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
32843317 const builtin_namespace = Type.fromInterned(builtin_root_type).getNamespace(zcu).unwrap().?;
32853318 // We know that the namespace has a `test_functions`...
32863319 const nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted(
3287 try ip.getOrPutString(gpa, pt.tid, "test_functions", .no_embedded_nulls),
3320 try ip.getOrPutString(gpa, io, pt.tid, "test_functions", .no_embedded_nulls),
32883321 Zcu.Namespace.NameAdapter{ .zcu = zcu },
32893322 ).?;
32903323 // ...but it might not be populated, so let's check that!
......@@ -3392,7 +3425,7 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
33923425 } }),
33933426 .len = (try pt.intValue(Type.usize, zcu.test_functions.count())).toIntern(),
33943427 } });
3395 ip.mutateVarInit(test_fns_val.toIntern(), new_init);
3428 ip.mutateVarInit(io, test_fns_val.toIntern(), new_init);
33963429 }
33973430 // The linker thread is not running, so we actually need to dispatch this task directly.
33983431 @import("../link.zig").linkTestFunctionsNav(pt, nav_index);
......@@ -3407,7 +3440,9 @@ pub fn reportRetryableFileError(
34073440 args: anytype,
34083441) error{OutOfMemory}!void {
34093442 const zcu = pt.zcu;
3410 const gpa = zcu.gpa;
3443 const comp = zcu.comp;
3444 const io = comp.io;
3445 const gpa = comp.gpa;
34113446
34123447 const file = zcu.fileByIndex(file_index);
34133448
......@@ -3417,8 +3452,8 @@ pub fn reportRetryableFileError(
34173452 errdefer gpa.free(msg);
34183453
34193454 const old_msg: ?[]u8 = old_msg: {
3420 zcu.comp.mutex.lock();
3421 defer zcu.comp.mutex.unlock();
3455 comp.mutex.lockUncancelable(io);
3456 defer comp.mutex.unlock(io);
34223457
34233458 const gop = try zcu.failed_files.getOrPut(gpa, file_index);
34243459 const old: ?[]u8 = if (gop.found_existing) old: {
......@@ -3433,12 +3468,8 @@ pub fn reportRetryableFileError(
34333468
34343469/// Shortcut for calling `intern_pool.get`.
34353470pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index {
3436 return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key);
3437}
3438
3439/// Shortcut for calling `intern_pool.getUnion`.
3440pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!InternPool.Index {
3441 return pt.zcu.intern_pool.getUnion(pt.zcu.gpa, pt.tid, un);
3471 const comp = pt.zcu.comp;
3472 return pt.zcu.intern_pool.get(comp.gpa, comp.io, pt.tid, key);
34423473}
34433474
34443475/// Essentially a shortcut for calling `intern_pool.getCoerced`.
......@@ -3446,6 +3477,9 @@ pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!
34463477/// this because it requires potentially pushing to the job queue.
34473478pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
34483479 const ip = &pt.zcu.intern_pool;
3480 const comp = pt.zcu.comp;
3481 const gpa = comp.gpa;
3482 const io = comp.io;
34493483 switch (ip.indexToKey(val.toIntern())) {
34503484 .@"extern" => |e| {
34513485 const coerced = try pt.getExtern(.{
......@@ -3468,7 +3502,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
34683502 },
34693503 else => {},
34703504 }
3471 return Value.fromInterned(try ip.getCoerced(pt.zcu.gpa, pt.tid, val.toIntern(), new_ty.toIntern()));
3505 return Value.fromInterned(try ip.getCoerced(gpa, io, pt.tid, val.toIntern(), new_ty.toIntern()));
34723506}
34733507
34743508pub fn intType(pt: Zcu.PerThread, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type {
......@@ -3566,7 +3600,8 @@ pub fn adjustPtrTypeChild(pt: Zcu.PerThread, ptr_ty: Type, new_child: Type) Allo
35663600}
35673601
35683602pub fn funcType(pt: Zcu.PerThread, key: InternPool.GetFuncTypeKey) Allocator.Error!Type {
3569 return Type.fromInterned(try pt.zcu.intern_pool.getFuncType(pt.zcu.gpa, pt.tid, key));
3603 const comp = pt.zcu.comp;
3604 return .fromInterned(try pt.zcu.intern_pool.getFuncType(comp.gpa, comp.io, pt.tid, key));
35703605}
35713606
35723607/// Use this for `anyframe->T` only.
......@@ -3584,7 +3619,8 @@ pub fn errorUnionType(pt: Zcu.PerThread, error_set_ty: Type, payload_ty: Type) A
35843619
35853620pub fn singleErrorSetType(pt: Zcu.PerThread, name: InternPool.NullTerminatedString) Allocator.Error!Type {
35863621 const names: *const [1]InternPool.NullTerminatedString = &name;
3587 return Type.fromInterned(try pt.zcu.intern_pool.getErrorSetType(pt.zcu.gpa, pt.tid, names));
3622 const comp = pt.zcu.comp;
3623 return Type.fromInterned(try pt.zcu.intern_pool.getErrorSetType(comp.gpa, comp.io, pt.tid, names));
35883624}
35893625
35903626/// Sorts `names` in place.
......@@ -3598,7 +3634,8 @@ pub fn errorSetFromUnsortedNames(
35983634 {},
35993635 InternPool.NullTerminatedString.indexLessThan,
36003636 );
3601 const new_ty = try pt.zcu.intern_pool.getErrorSetType(pt.zcu.gpa, pt.tid, names);
3637 const comp = pt.zcu.comp;
3638 const new_ty = try pt.zcu.intern_pool.getErrorSetType(comp.gpa, comp.io, pt.tid, names);
36023639 return Type.fromInterned(new_ty);
36033640}
36043641
......@@ -3709,9 +3746,17 @@ pub fn intValue_i64(pt: Zcu.PerThread, ty: Type, x: i64) Allocator.Error!Value {
37093746 } }));
37103747}
37113748
3749/// Shortcut for calling `intern_pool.getUnion`.
3750/// TODO: remove either this or `unionValue`.
3751pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!InternPool.Index {
3752 const comp = pt.zcu.comp;
3753 return pt.zcu.intern_pool.getUnion(comp.gpa, comp.io, pt.tid, un);
3754}
3755
3756/// TODO: remove either this or `internUnion`.
37123757pub fn unionValue(pt: Zcu.PerThread, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value {
3713 const zcu = pt.zcu;
3714 return Value.fromInterned(try zcu.intern_pool.getUnion(zcu.gpa, pt.tid, .{
3758 const comp = pt.zcu.comp;
3759 return Value.fromInterned(try pt.zcu.intern_pool.getUnion(comp.gpa, comp.io, pt.tid, .{
37153760 .ty = union_ty.toIntern(),
37163761 .tag = tag.toIntern(),
37173762 .val = val.toIntern(),
......@@ -3771,12 +3816,12 @@ pub fn nullValue(pt: Zcu.PerThread, opt_ty: Type) Allocator.Error!Value {
37713816/// `ty` is an integer or a vector of integers.
37723817pub fn overflowArithmeticTupleType(pt: Zcu.PerThread, ty: Type) !Type {
37733818 const zcu = pt.zcu;
3774 const ip = &zcu.intern_pool;
3819 const comp = zcu.comp;
37753820 const ov_ty: Type = if (ty.zigTypeTag(zcu) == .vector) try pt.vectorType(.{
37763821 .len = ty.vectorLen(zcu),
37773822 .child = .u1_type,
37783823 }) else .u1;
3779 const tuple_ty = try ip.getTupleType(zcu.gpa, pt.tid, .{
3824 const tuple_ty = try zcu.intern_pool.getTupleType(comp.gpa, comp.io, pt.tid, .{
37803825 .types = &.{ ty.toIntern(), ov_ty.toIntern() },
37813826 .values = &.{ .none, .none },
37823827 });
......@@ -3872,12 +3917,14 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
38723917/// If necessary, the new `Nav` is queued for codegen.
38733918/// `key.owner_nav` is ignored and may be `undefined`.
38743919pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!InternPool.Index {
3875 const result = try pt.zcu.intern_pool.getExtern(pt.zcu.gpa, pt.tid, key);
3920 const zcu = pt.zcu;
3921 const comp = zcu.comp;
3922 const result = try zcu.intern_pool.getExtern(comp.gpa, comp.io, pt.tid, key);
38763923 if (result.new_nav.unwrap()) |nav| {
38773924 // This job depends on any resolve_type_fully jobs queued up before it.
3878 pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
3879 try pt.zcu.comp.queueJob(.{ .link_nav = nav });
3880 if (pt.zcu.comp.debugIncremental()) try pt.zcu.incremental_debug_state.newNav(pt.zcu, nav);
3925 comp.link_prog_node.increaseEstimatedTotalItems(1);
3926 try comp.queueJob(.{ .link_nav = nav });
3927 if (comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
38813928 }
38823929 return result.index;
38833930}
......@@ -3966,7 +4013,9 @@ fn recreateStructType(
39664013 key: InternPool.Key.NamespaceType.Declared,
39674014) Allocator.Error!InternPool.Index {
39684015 const zcu = pt.zcu;
3969 const gpa = zcu.gpa;
4016 const comp = zcu.comp;
4017 const gpa = comp.gpa;
4018 const io = comp.io;
39704019 const ip = &zcu.intern_pool;
39714020
39724021 const inst_info = key.zir_index.resolveFull(ip).?;
......@@ -3995,7 +4044,7 @@ fn recreateStructType(
39954044
39964045 const struct_obj = ip.loadStructType(old_ty);
39974046
3998 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
4047 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
39994048 .layout = small.layout,
40004049 .fields_len = fields_len,
40014050 .known_non_opv = small.known_non_opv,
......@@ -4042,7 +4091,9 @@ fn recreateUnionType(
40424091 key: InternPool.Key.NamespaceType.Declared,
40434092) Allocator.Error!InternPool.Index {
40444093 const zcu = pt.zcu;
4045 const gpa = zcu.gpa;
4094 const comp = zcu.comp;
4095 const gpa = comp.gpa;
4096 const io = comp.io;
40464097 const ip = &zcu.intern_pool;
40474098
40484099 const inst_info = key.zir_index.resolveFull(ip).?;
......@@ -4075,7 +4126,7 @@ fn recreateUnionType(
40754126
40764127 const namespace_index = union_obj.namespace;
40774128
4078 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{
4129 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
40794130 .flags = .{
40804131 .layout = small.layout,
40814132 .status = .none,
......@@ -4133,7 +4184,9 @@ fn recreateEnumType(
41334184 key: InternPool.Key.NamespaceType.Declared,
41344185) (Allocator.Error || Io.Cancelable)!InternPool.Index {
41354186 const zcu = pt.zcu;
4136 const gpa = zcu.gpa;
4187 const comp = zcu.comp;
4188 const gpa = comp.gpa;
4189 const io = comp.io;
41374190 const ip = &zcu.intern_pool;
41384191
41394192 const inst_info = key.zir_index.resolveFull(ip).?;
......@@ -4197,7 +4250,7 @@ fn recreateEnumType(
41974250
41984251 const namespace_index = enum_obj.namespace;
41994252
4200 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
4253 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
42014254 .has_values = any_values,
42024255 .tag_mode = if (small.nonexhaustive)
42034256 .nonexhaustive
......@@ -4404,7 +4457,7 @@ pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPo
44044457
44054458pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dependee) Allocator.Error!void {
44064459 const zcu = pt.zcu;
4407 const gpa = zcu.gpa;
4460 const gpa = zcu.comp.gpa;
44084461 try zcu.intern_pool.addDependency(gpa, unit, dependee);
44094462 if (zcu.comp.debugIncremental()) {
44104463 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, unit);
......@@ -4412,50 +4465,38 @@ pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dep
44124465 }
44134466}
44144467
4415/// Performs code generation, which comes after `Sema` but before `link` in the pipeline.
4416/// This part of the pipeline is self-contained/"pure", so can be run in parallel with most
4417/// other code. This function is currently run either on the main thread, or on a separate
4418/// codegen thread, depending on whether the backend supports `Zcu.Feature.separate_thread`.
4419pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air, out: *@import("../link.zig").ZcuTask.LinkFunc.SharedMir) void {
4468pub const RunCodegenError = Io.Cancelable || error{AlreadyReported};
4469
4470/// Performs code generation, which comes after `Sema` but before `link` in the pipeline. This part
4471/// of the pipeline is self-contained and can usually be run concurrently with other components.
4472///
4473/// This function is called asynchronously by `Zcu.CodegenTaskPool.start` and awaited by the linker.
4474/// However, if the codegen backend does not support `Zcu.Feature.separate_thread`, then
4475/// `Compilation.processOneJob` will immediately await the result of the linker task, meaning the
4476/// pipeline becomes effectively single-threaded.
4477pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) RunCodegenError!codegen.AnyMir {
44204478 const zcu = pt.zcu;
4479 const comp = zcu.comp;
4480 const io = comp.io;
44214481
44224482 crash_report.CodegenFunc.start(zcu, func_index);
44234483 defer crash_report.CodegenFunc.stop(func_index);
44244484
4425 var timer = zcu.comp.startTimer();
4485 var timer = comp.startTimer();
44264486
4427 const success: bool = if (runCodegenInner(pt, func_index, air)) |mir| success: {
4428 out.value = mir;
4429 break :success true;
4430 } else |err| success: {
4431 switch (err) {
4432 error.OutOfMemory => zcu.comp.setAllocFailure(),
4433 error.CodegenFail => zcu.assertCodegenFailed(zcu.funcInfo(func_index).owner_nav),
4434 error.NoLinkFile => assert(zcu.comp.bin_file == null),
4435 error.BackendDoesNotProduceMir => switch (target_util.zigBackend(
4436 &zcu.root_mod.resolved_target.result,
4437 zcu.comp.config.use_llvm,
4438 )) {
4439 else => unreachable, // assertion failure
4440 .stage2_spirv,
4441 .stage2_llvm,
4442 => {},
4443 },
4444 }
4445 break :success false;
4446 };
4487 const codegen_result = runCodegenInner(pt, func_index, air);
44474488
44484489 if (timer.finish()) |ns_codegen| report_time: {
44494490 const ip = &zcu.intern_pool;
44504491 const nav = ip.indexToKey(func_index).func.owner_nav;
44514492 const zir_decl = ip.getNav(nav).srcInst(ip);
4452 zcu.comp.mutex.lock();
4453 defer zcu.comp.mutex.unlock();
4493 comp.mutex.lockUncancelable(io);
4494 defer comp.mutex.unlock(io);
44544495 const tr = &zcu.comp.time_report.?;
44554496 tr.stats.cpu_ns_codegen += ns_codegen;
4456 const gop = tr.decl_codegen_ns.getOrPut(zcu.gpa, zir_decl) catch |err| switch (err) {
4497 const gop = tr.decl_codegen_ns.getOrPut(comp.gpa, zir_decl) catch |err| switch (err) {
44574498 error.OutOfMemory => {
4458 zcu.comp.setAllocFailure();
4499 comp.setAllocFailure();
44594500 break :report_time;
44604501 },
44614502 };
......@@ -4463,14 +4504,29 @@ pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air, ou
44634504 gop.value_ptr.* += ns_codegen;
44644505 }
44654506
4466 // release `out.value` with this store; synchronizes with acquire loads in `link`
4467 out.status.store(if (success) .ready else .failed, .release);
4468 zcu.comp.link_task_queue.mirReady(zcu.comp, func_index, out);
44694507 if (zcu.pending_codegen_jobs.rmw(.Sub, 1, .monotonic) == 1) {
44704508 // Decremented to 0, so all done.
44714509 zcu.codegen_prog_node.end();
44724510 zcu.codegen_prog_node = .none;
44734511 }
4512
4513 return codegen_result catch |err| {
4514 switch (err) {
4515 error.OutOfMemory => comp.setAllocFailure(),
4516 error.CodegenFail => zcu.assertCodegenFailed(zcu.funcInfo(func_index).owner_nav),
4517 error.NoLinkFile => assert(comp.bin_file == null),
4518 error.BackendDoesNotProduceMir => switch (target_util.zigBackend(
4519 &zcu.root_mod.resolved_target.result,
4520 comp.config.use_llvm,
4521 )) {
4522 else => unreachable, // assertion failure
4523 .stage2_spirv,
4524 .stage2_llvm,
4525 => {},
4526 },
4527 }
4528 return error.AlreadyReported;
4529 };
44744530}
44754531fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) error{
44764532 OutOfMemory,
......@@ -4527,7 +4583,7 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45274583 // "emit" step because LLVM does not support incremental linking. Our linker (LLD or self-hosted)
45284584 // will just see the ZCU object file which LLVM ultimately emits.
45294585 if (zcu.llvm_object) |llvm_object| {
4530 assert(pt.tid == .main); // LLVM has a lot of shared state
4586 assert(zcu.pending_codegen_jobs.load(.monotonic) == 2); // only one codegen at a time (but the value is 2 because 1 is the base)
45314587 try llvm_object.updateFunc(pt, func_index, air, &liveness);
45324588 return error.BackendDoesNotProduceMir;
45334589 }
......@@ -4536,7 +4592,7 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45364592
45374593 // Just like LLVM, the SPIR-V backend can't multi-threaded due to SPIR-V design limitations.
45384594 if (lf.cast(.spirv)) |spirv_file| {
4539 assert(pt.tid == .main); // SPIR-V has a lot of shared state
4595 assert(zcu.pending_codegen_jobs.load(.monotonic) == 2); // only one codegen at a time (but the value is 2 because 1 is the base)
45404596 spirv_file.updateFunc(pt, func_index, air, &liveness) catch |err| {
45414597 switch (err) {
45424598 error.OutOfMemory => comp.link_diags.setAllocFailure(),
src/codegen/spirv/CodeGen.zig+9-6
......@@ -2270,6 +2270,9 @@ fn buildWideMul(
22702270) !struct { Temporary, Temporary } {
22712271 const pt = cg.pt;
22722272 const zcu = cg.module.zcu;
2273 const comp = zcu.comp;
2274 const gpa = comp.gpa;
2275 const io = comp.io;
22732276 const target = cg.module.zcu.getTarget();
22742277 const ip = &zcu.intern_pool;
22752278
......@@ -2297,14 +2300,14 @@ fn buildWideMul(
22972300 };
22982301
22992302 for (0..ops) |i| {
2300 try cg.body.emit(cg.module.gpa, .OpIMul, .{
2303 try cg.body.emit(gpa, .OpIMul, .{
23012304 .id_result_type = arith_op_ty_id,
23022305 .id_result = value_results.at(i),
23032306 .operand_1 = lhs_op.at(i),
23042307 .operand_2 = rhs_op.at(i),
23052308 });
23062309
2307 try cg.body.emit(cg.module.gpa, .OpExtInst, .{
2310 try cg.body.emit(gpa, .OpExtInst, .{
23082311 .id_result_type = arith_op_ty_id,
23092312 .id_result = overflow_results.at(i),
23102313 .set = set,
......@@ -2316,7 +2319,7 @@ fn buildWideMul(
23162319 .vulkan, .opengl => {
23172320 // Operations return a struct{T, T}
23182321 // where T is maybe vectorized.
2319 const op_result_ty: Type = .fromInterned(try ip.getTupleType(zcu.gpa, pt.tid, .{
2322 const op_result_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
23202323 .types = &.{ arith_op_ty.toIntern(), arith_op_ty.toIntern() },
23212324 .values = &.{ .none, .none },
23222325 }));
......@@ -2330,7 +2333,7 @@ fn buildWideMul(
23302333 for (0..ops) |i| {
23312334 const op_result = cg.module.allocId();
23322335
2333 try cg.body.emitRaw(cg.module.gpa, opcode, 4);
2336 try cg.body.emitRaw(gpa, opcode, 4);
23342337 cg.body.writeOperand(Id, op_result_ty_id);
23352338 cg.body.writeOperand(Id, op_result);
23362339 cg.body.writeOperand(Id, lhs_op.at(i));
......@@ -2340,14 +2343,14 @@ fn buildWideMul(
23402343 // Temporary to deal with the fact that these are structs eventually,
23412344 // but for now, take the struct apart and return two separate vectors.
23422345
2343 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
2346 try cg.body.emit(gpa, .OpCompositeExtract, .{
23442347 .id_result_type = arith_op_ty_id,
23452348 .id_result = value_results.at(i),
23462349 .composite = op_result,
23472350 .indexes = &.{0},
23482351 });
23492352
2350 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
2353 try cg.body.emit(gpa, .OpCompositeExtract, .{
23512354 .id_result_type = arith_op_ty_id,
23522355 .id_result = overflow_results.at(i),
23532356 .composite = op_result,
src/codegen/x86_64/CodeGen.zig+10-8
......@@ -180204,6 +180204,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
180204180204fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
180205180205 const pt = self.pt;
180206180206 const zcu = pt.zcu;
180207 const io = zcu.comp.io;
180207180208 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
180208180209 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
180209180210 const ty = self.typeOfIndex(inst);
......@@ -180477,7 +180478,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
180477180478 for (mask_elems, 0..) |*elem, bit| elem.* = @intCast(bit / elem_bits);
180478180479 const mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{
180479180480 .ty = mask_ty.toIntern(),
180480 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, mask_elems, .maybe_embedded_nulls) },
180481 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, mask_elems, .maybe_embedded_nulls) },
180481180482 } })));
180482180483 const mask_mem: Memory = .{
180483180484 .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) },
......@@ -188476,6 +188477,7 @@ const Select = struct {
188476188477 fn create(spec: TempSpec, s: *const Select) InnerError!struct { Temp, bool } {
188477188478 const cg = s.cg;
188478188479 const pt = cg.pt;
188480 const io = pt.zcu.comp.io;
188479188481 return switch (spec.kind) {
188480188482 .unused => .{ undefined, false },
188481188483 .any => .{ try cg.tempAlloc(spec.type), true },
......@@ -188693,7 +188695,7 @@ const Select = struct {
188693188695 };
188694188696 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188695188697 .ty = spec.type.toIntern(),
188696 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188698 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188697188699 } }))), true };
188698188700 },
188699188701 .pshufb_trunc_mem => |trunc_spec| {
......@@ -188720,7 +188722,7 @@ const Select = struct {
188720188722 };
188721188723 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188722188724 .ty = spec.type.toIntern(),
188723 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188725 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188724188726 } }))), true };
188725188727 },
188726188728 .pand_trunc_mem => |trunc_spec| {
......@@ -188734,7 +188736,7 @@ const Select = struct {
188734188736 while (index < elems.len) : (index += from_bytes) @memset(elems[index..][0..to_bytes], std.math.maxInt(u8));
188735188737 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188736188738 .ty = spec.type.toIntern(),
188737 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188739 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188738188740 } }))), true };
188739188741 },
188740188742 .pand_mask_mem => |mask_spec| {
......@@ -188753,7 +188755,7 @@ const Select = struct {
188753188755 @memset(elems[mask_len..], invert_mask);
188754188756 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188755188757 .ty = spec.type.toIntern(),
188756 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188758 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188757188759 } }))), true };
188758188760 },
188759188761 .ptest_mask_mem => |mask_ref| {
......@@ -188778,7 +188780,7 @@ const Select = struct {
188778188780 }
188779188781 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188780188782 .ty = spec.type.toIntern(),
188781 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188783 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188782188784 } }))), true };
188783188785 },
188784188786 .pshufb_bswap_mem => |bswap_spec| {
......@@ -188794,7 +188796,7 @@ const Select = struct {
188794188796 };
188795188797 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188796188798 .ty = spec.type.toIntern(),
188797 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188799 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188798188800 } }))), true };
188799188801 },
188800188802 .bits_mem => |direction| {
......@@ -188808,7 +188810,7 @@ const Select = struct {
188808188810 };
188809188811 return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{
188810188812 .ty = spec.type.toIntern(),
188811 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, elems, .maybe_embedded_nulls) },
188813 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) },
188812188814 } }))), true };
188813188815 },
188814188816 .splat_int_mem => |splat_spec| {
src/libs/freebsd.zig+6-5
......@@ -991,7 +991,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
991991 });
992992}
993993
994fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
994fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) std.Io.Cancelable!void {
995 const io = comp.io;
995996 const target = comp.getTarget();
996997 const target_os_version = target.os.version_range.semver.min;
997998
......@@ -1002,8 +1003,8 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
10021003 var task_buffer_i: usize = 0;
10031004
10041005 {
1005 comp.mutex.lock(); // protect comp.arena
1006 defer comp.mutex.unlock();
1006 comp.mutex.lockUncancelable(io); // protect comp.arena
1007 defer comp.mutex.unlock(io);
10071008
10081009 for (libs) |lib| {
10091010 if (lib.added_in) |add_in| {
......@@ -1021,7 +1022,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
10211022 }
10221023 }
10231024
1024 comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
1025 try comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
10251026}
10261027
10271028fn buildSharedLib(
......@@ -1094,8 +1095,8 @@ fn buildSharedLib(
10941095
10951096 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
10961097 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
1098 .thread_limit = comp.thread_limit,
10971099 .dirs = comp.dirs.withoutLocalCache(),
1098 .thread_pool = comp.thread_pool,
10991100 .self_exe_path = comp.self_exe_path,
11001101 // Because we manually cache the whole set of objects, we don't cache the individual objects
11011102 // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path.
src/libs/glibc.zig+6-5
......@@ -1135,7 +1135,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
11351135 });
11361136}
11371137
1138fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
1138fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) std.Io.Cancelable!void {
1139 const io = comp.io;
11391140 const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;
11401141
11411142 assert(comp.glibc_so_files == null);
......@@ -1145,8 +1146,8 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
11451146 var task_buffer_i: usize = 0;
11461147
11471148 {
1148 comp.mutex.lock(); // protect comp.arena
1149 defer comp.mutex.unlock();
1149 comp.mutex.lockUncancelable(io); // protect comp.arena
1150 defer comp.mutex.unlock(io);
11501151
11511152 for (libs) |lib| {
11521153 if (lib.removed_in) |rem_in| {
......@@ -1163,7 +1164,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
11631164 }
11641165 }
11651166
1166 comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
1167 try comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
11671168}
11681169
11691170fn buildSharedLib(
......@@ -1233,8 +1234,8 @@ fn buildSharedLib(
12331234
12341235 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
12351236 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
1237 .thread_limit = comp.thread_limit,
12361238 .dirs = comp.dirs.withoutLocalCache(),
1237 .thread_pool = comp.thread_pool,
12381239 .self_exe_path = comp.self_exe_path,
12391240 // Because we manually cache the whole set of objects, we don't cache the individual objects
12401241 // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path.
src/libs/libcxx.zig+5-5
......@@ -106,7 +106,7 @@ pub const BuildError = error{
106106 OutOfMemory,
107107 AlreadyReported,
108108 ZigCompilerNotBuiltWithLLVMExtensions,
109};
109} || std.Io.Cancelable;
110110
111111pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
112112 if (!build_options.have_llvm) {
......@@ -256,13 +256,13 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
256256
257257 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
258258 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
259 .thread_limit = comp.thread_limit,
259260 .dirs = comp.dirs.withoutLocalCache(),
260261 .self_exe_path = comp.self_exe_path,
261262 .cache_mode = .whole,
262263 .config = config,
263264 .root_mod = root_mod,
264265 .root_name = root_name,
265 .thread_pool = comp.thread_pool,
266266 .libc_installation = comp.libc_installation,
267267 .emit_bin = .yes_cache,
268268 .c_source_files = c_source_files.items,
......@@ -295,7 +295,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
295295 assert(comp.libcxx_static_lib == null);
296296 const crt_file = try sub_compilation.toCrtFile();
297297 comp.libcxx_static_lib = crt_file;
298 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
298 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
299299}
300300
301301pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
......@@ -449,13 +449,13 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
449449
450450 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
451451 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
452 .thread_limit = comp.thread_limit,
452453 .dirs = comp.dirs.withoutLocalCache(),
453454 .self_exe_path = comp.self_exe_path,
454455 .cache_mode = .whole,
455456 .config = config,
456457 .root_mod = root_mod,
457458 .root_name = root_name,
458 .thread_pool = comp.thread_pool,
459459 .libc_installation = comp.libc_installation,
460460 .emit_bin = .yes_cache,
461461 .c_source_files = c_source_files.items,
......@@ -492,7 +492,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
492492 assert(comp.libcxxabi_static_lib == null);
493493 const crt_file = try sub_compilation.toCrtFile();
494494 comp.libcxxabi_static_lib = crt_file;
495 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
495 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
496496}
497497
498498pub fn addCxxArgs(
src/libs/libtsan.zig+3-3
......@@ -11,7 +11,7 @@ pub const BuildError = error{
1111 AlreadyReported,
1212 ZigCompilerNotBuiltWithLLVMExtensions,
1313 TSANUnsupportedCPUArchitecture,
14};
14} || std.Io.Cancelable;
1515
1616pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
1717 if (!build_options.have_llvm) {
......@@ -279,8 +279,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
279279
280280 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
281281 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
282 .thread_limit = comp.thread_limit,
282283 .dirs = comp.dirs.withoutLocalCache(),
283 .thread_pool = comp.thread_pool,
284284 .self_exe_path = comp.self_exe_path,
285285 .cache_mode = .whole,
286286 .config = config,
......@@ -319,7 +319,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
319319 };
320320
321321 const crt_file = try sub_compilation.toCrtFile();
322 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
322 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
323323 assert(comp.tsan_lib == null);
324324 comp.tsan_lib = crt_file;
325325}
src/libs/libunwind.zig+3-3
......@@ -12,7 +12,7 @@ pub const BuildError = error{
1212 OutOfMemory,
1313 AlreadyReported,
1414 ZigCompilerNotBuiltWithLLVMExtensions,
15};
15} || std.Io.Cancelable;
1616
1717pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
1818 if (!build_options.have_llvm) {
......@@ -145,6 +145,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
145145
146146 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
147147 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
148 .thread_limit = comp.thread_limit,
148149 .dirs = comp.dirs.withoutLocalCache(),
149150 .self_exe_path = comp.self_exe_path,
150151 .config = config,
......@@ -152,7 +153,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
152153 .cache_mode = .whole,
153154 .root_name = root_name,
154155 .main_mod = null,
155 .thread_pool = comp.thread_pool,
156156 .libc_installation = comp.libc_installation,
157157 .emit_bin = .yes_cache,
158158 .function_sections = comp.function_sections,
......@@ -184,7 +184,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
184184 };
185185
186186 const crt_file = try sub_compilation.toCrtFile();
187 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
187 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
188188 assert(comp.libunwind_static_lib == null);
189189 comp.libunwind_static_lib = crt_file;
190190}
src/libs/mingw.zig+4-4
......@@ -281,8 +281,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
281281 const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
282282 errdefer gpa.free(sub_path);
283283
284 comp.mutex.lock();
285 defer comp.mutex.unlock();
284 comp.mutex.lockUncancelable(io);
285 defer comp.mutex.unlock(io);
286286 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
287287 comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{
288288 .full_object_path = .{
......@@ -388,8 +388,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
388388 log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });
389389 };
390390
391 comp.mutex.lock();
392 defer comp.mutex.unlock();
391 comp.mutex.lockUncancelable(io);
392 defer comp.mutex.unlock(io);
393393 try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{
394394 .full_object_path = .{
395395 .root_dir = comp.dirs.global_cache,
src/libs/musl.zig+4-4
......@@ -248,12 +248,12 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
248248
249249 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
250250 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
251 .thread_limit = comp.thread_limit,
251252 .dirs = comp.dirs.withoutLocalCache(),
252253 .self_exe_path = comp.self_exe_path,
253254 .cache_mode = .whole,
254255 .config = config,
255256 .root_mod = root_mod,
256 .thread_pool = comp.thread_pool,
257257 .root_name = "c",
258258 .libc_installation = comp.libc_installation,
259259 .emit_bin = .yes_cache,
......@@ -287,10 +287,10 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
287287 errdefer comp.gpa.free(basename);
288288
289289 const crt_file = try sub_compilation.toCrtFile();
290 comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
290 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);
291291 {
292 comp.mutex.lock();
293 defer comp.mutex.unlock();
292 comp.mutex.lockUncancelable(io);
293 defer comp.mutex.unlock(io);
294294 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
295295 comp.crt_files.putAssumeCapacityNoClobber(basename, crt_file);
296296 }
src/libs/netbsd.zig+6-5
......@@ -645,7 +645,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
645645 });
646646}
647647
648fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
648fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) std.Io.Cancelable!void {
649 const io = comp.io;
649650 assert(comp.netbsd_so_files == null);
650651 comp.netbsd_so_files = so_files;
651652
......@@ -653,8 +654,8 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
653654 var task_buffer_i: usize = 0;
654655
655656 {
656 comp.mutex.lock(); // protect comp.arena
657 defer comp.mutex.unlock();
657 comp.mutex.lockUncancelable(io); // protect comp.arena
658 defer comp.mutex.unlock(io);
658659
659660 for (libs) |lib| {
660661 const so_path: Path = .{
......@@ -668,7 +669,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
668669 }
669670 }
670671
671 comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
672 try comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]);
672673}
673674
674675fn buildSharedLib(
......@@ -737,8 +738,8 @@ fn buildSharedLib(
737738
738739 var sub_create_diag: Compilation.CreateDiagnostic = undefined;
739740 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{
741 .thread_limit = comp.thread_limit,
740742 .dirs = comp.dirs.withoutLocalCache(),
741 .thread_pool = comp.thread_pool,
742743 .self_exe_path = comp.self_exe_path,
743744 // Because we manually cache the whole set of objects, we don't cache the individual objects
744745 // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path.
src/link.zig+64-93
......@@ -34,7 +34,8 @@ pub const Diags = struct {
3434 /// Stored here so that function definitions can distinguish between
3535 /// needing an allocator for things besides error reporting.
3636 gpa: Allocator,
37 mutex: std.Thread.Mutex,
37 io: Io,
38 mutex: Io.Mutex,
3839 msgs: std.ArrayList(Msg),
3940 flags: Flags,
4041 lld: std.ArrayList(Lld),
......@@ -126,10 +127,11 @@ pub const Diags = struct {
126127 }
127128 };
128129
129 pub fn init(gpa: Allocator) Diags {
130 pub fn init(gpa: Allocator, io: Io) Diags {
130131 return .{
131132 .gpa = gpa,
132 .mutex = .{},
133 .io = io,
134 .mutex = .init,
133135 .msgs = .empty,
134136 .flags = .{},
135137 .lld = .empty,
......@@ -153,8 +155,10 @@ pub const Diags = struct {
153155 }
154156
155157 pub fn lockAndParseLldStderr(diags: *Diags, prefix: []const u8, stderr: []const u8) void {
156 diags.mutex.lock();
157 defer diags.mutex.unlock();
158 const io = diags.io;
159
160 diags.mutex.lockUncancelable(io);
161 defer diags.mutex.unlock(io);
158162
159163 diags.parseLldStderr(prefix, stderr) catch diags.setAllocFailure();
160164 }
......@@ -226,9 +230,10 @@ pub const Diags = struct {
226230 pub fn addErrorSourceLocation(diags: *Diags, sl: SourceLocation, comptime format: []const u8, args: anytype) void {
227231 @branchHint(.cold);
228232 const gpa = diags.gpa;
233 const io = diags.io;
229234 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
230 diags.mutex.lock();
231 defer diags.mutex.unlock();
235 diags.mutex.lockUncancelable(io);
236 defer diags.mutex.unlock(io);
232237 addErrorLockedFallible(diags, sl, eu_main_msg) catch |err| switch (err) {
233238 error.OutOfMemory => diags.setAllocFailureLocked(),
234239 };
......@@ -247,8 +252,9 @@ pub const Diags = struct {
247252 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
248253 @branchHint(.cold);
249254 const gpa = diags.gpa;
250 diags.mutex.lock();
251 defer diags.mutex.unlock();
255 const io = diags.io;
256 diags.mutex.lockUncancelable(io);
257 defer diags.mutex.unlock(io);
252258 try diags.msgs.ensureUnusedCapacity(gpa, 1);
253259 return addErrorWithNotesAssumeCapacity(diags, note_count);
254260 }
......@@ -276,9 +282,10 @@ pub const Diags = struct {
276282 ) void {
277283 @branchHint(.cold);
278284 const gpa = diags.gpa;
285 const io = diags.io;
279286 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
280 diags.mutex.lock();
281 defer diags.mutex.unlock();
287 diags.mutex.lockUncancelable(io);
288 defer diags.mutex.unlock(io);
282289 addMissingLibraryErrorLockedFallible(diags, checked_paths, eu_main_msg) catch |err| switch (err) {
283290 error.OutOfMemory => diags.setAllocFailureLocked(),
284291 };
......@@ -312,9 +319,10 @@ pub const Diags = struct {
312319 ) void {
313320 @branchHint(.cold);
314321 const gpa = diags.gpa;
322 const io = diags.io;
315323 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
316 diags.mutex.lock();
317 defer diags.mutex.unlock();
324 diags.mutex.lockUncancelable(io);
325 defer diags.mutex.unlock(io);
318326 addParseErrorLockedFallible(diags, path, eu_main_msg) catch |err| switch (err) {
319327 error.OutOfMemory => diags.setAllocFailureLocked(),
320328 };
......@@ -349,8 +357,9 @@ pub const Diags = struct {
349357
350358 pub fn setAllocFailure(diags: *Diags) void {
351359 @branchHint(.cold);
352 diags.mutex.lock();
353 defer diags.mutex.unlock();
360 const io = diags.io;
361 diags.mutex.lockUncancelable(io);
362 defer diags.mutex.unlock(io);
354363 setAllocFailureLocked(diags);
355364 }
356365
......@@ -1101,6 +1110,7 @@ pub const File = struct {
11011110 const comp = base.comp;
11021111 const diags = &comp.link_diags;
11031112 const gpa = comp.gpa;
1113 const io = comp.io;
11041114 const stat = try file.stat();
11051115 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;
11061116 const buf = try gpa.alloc(u8, size);
......@@ -1123,8 +1133,8 @@ pub const File = struct {
11231133 } else {
11241134 if (fs.path.isAbsolute(arg.path)) {
11251135 const new_path = Path.initCwd(path: {
1126 comp.mutex.lock();
1127 defer comp.mutex.unlock();
1136 comp.mutex.lockUncancelable(io);
1137 defer comp.mutex.unlock(io);
11281138 break :path try comp.arena.dupe(u8, arg.path);
11291139 });
11301140 switch (Compilation.classifyFileExt(arg.path)) {
......@@ -1309,61 +1319,13 @@ pub const ZcuTask = union(enum) {
13091319 /// Write the constant value for a Decl to the output file.
13101320 link_nav: InternPool.Nav.Index,
13111321 /// Write the machine code for a function to the output file.
1312 link_func: LinkFunc,
1322 link_func: Zcu.CodegenTaskPool.Index,
13131323 link_type: InternPool.Index,
13141324 update_line_number: InternPool.TrackedInst.Index,
1315 pub fn deinit(task: ZcuTask, zcu: *const Zcu) void {
1316 switch (task) {
1317 .link_nav,
1318 .link_type,
1319 .update_line_number,
1320 => {},
1321 .link_func => |link_func| {
1322 switch (link_func.mir.status.load(.acquire)) {
1323 .pending => unreachable, // cannot deinit until MIR done
1324 .failed => {}, // MIR not populated so doesn't need freeing
1325 .ready => link_func.mir.value.deinit(zcu),
1326 }
1327 zcu.gpa.destroy(link_func.mir);
1328 },
1329 }
1330 }
1331 pub const LinkFunc = struct {
1332 /// This will either be a non-generic `func_decl` or a `func_instance`.
1333 func: InternPool.Index,
1334 /// This pointer is allocated into `gpa` and must be freed when the `ZcuTask` is processed.
1335 /// The pointer is shared with the codegen worker, which will populate the MIR inside once
1336 /// it has been generated. It's important that the `link_func` is queued at the same time as
1337 /// the codegen job to ensure that the linker receives functions in a deterministic order,
1338 /// allowing reproducible builds.
1339 mir: *SharedMir,
1340 /// This is not actually used by `doZcuTask`. Instead, `Queue` uses this value as a heuristic
1341 /// to avoid queueing too much AIR/MIR for codegen/link at a time. Essentially, we cap the
1342 /// total number of AIR bytes which are being processed at once, preventing unbounded memory
1343 /// usage when AIR is produced faster than it is processed.
1344 air_bytes: u32,
1345
1346 pub const SharedMir = struct {
1347 /// This is initially `.pending`. When `value` is populated, the codegen thread will set
1348 /// this to `.ready`, and alert the queue if needed. It could also end up `.failed`.
1349 /// The action of storing a value (other than `.pending`) to this atomic transfers
1350 /// ownership of memory assoicated with `value` to this `ZcuTask`.
1351 status: std.atomic.Value(enum(u8) {
1352 /// We are waiting on codegen to generate MIR (or die trying).
1353 pending,
1354 /// `value` is not populated and will not be populated. Just drop the task from the queue and move on.
1355 failed,
1356 /// `value` is populated with the MIR from the backend in use, which is not LLVM.
1357 ready,
1358 }),
1359 /// This is `undefined` until `ready` is set to `true`. Once populated, this MIR belongs
1360 /// to the `ZcuTask`, and must be `deinit`ed when it is processed. Allocated into `gpa`.
1361 value: codegen.AnyMir,
1362 };
1363 };
13641325};
13651326
13661327pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1328 const io = comp.io;
13671329 const diags = &comp.link_diags;
13681330 const base = comp.bin_file orelse {
13691331 comp.link_prog_node.completeOne();
......@@ -1372,8 +1334,8 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
13721334
13731335 var timer = comp.startTimer();
13741336 defer if (timer.finish()) |ns| {
1375 comp.mutex.lock();
1376 defer comp.mutex.unlock();
1337 comp.mutex.lockUncancelable(io);
1338 defer comp.mutex.unlock(io);
13771339 comp.time_report.?.stats.cpu_ns_link += ns;
13781340 };
13791341
......@@ -1484,6 +1446,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
14841446 }
14851447}
14861448pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
1449 const io = comp.io;
14871450 const diags = &comp.link_diags;
14881451 const zcu = comp.zcu.?;
14891452 const ip = &zcu.intern_pool;
......@@ -1492,8 +1455,8 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
14921455
14931456 var timer = comp.startTimer();
14941457
1495 switch (task) {
1496 .link_nav => |nav_index| {
1458 const maybe_nav: ?InternPool.Nav.Index = switch (task) {
1459 .link_nav => |nav_index| nav: {
14971460 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
14981461 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);
14991462 defer nav_prog_node.end();
......@@ -1514,21 +1477,25 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
15141477 },
15151478 };
15161479 }
1480 break :nav nav_index;
15171481 },
1518 .link_func => |func| {
1519 const nav = zcu.funcInfo(func.func).owner_nav;
1482 .link_func => |codegen_task| nav: {
1483 timer.pause();
1484 const func, var mir = codegen_task.wait(&zcu.codegen_task_pool, io) catch |err| switch (err) {
1485 error.Canceled, error.AlreadyReported => return,
1486 };
1487 defer mir.deinit(zcu);
1488 timer.@"resume"();
1489
1490 const nav = zcu.funcInfo(func).owner_nav;
15201491 const fqn_slice = ip.getNav(nav).fqn.toSlice(ip);
1492
15211493 const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0);
15221494 defer nav_prog_node.end();
1523 switch (func.mir.status.load(.acquire)) {
1524 .pending => unreachable,
1525 .ready => {},
1526 .failed => return,
1527 }
1495
15281496 assert(zcu.llvm_object == null); // LLVM codegen doesn't produce MIR
1529 const mir = &func.mir.value;
15301497 if (comp.bin_file) |lf| {
1531 lf.updateFunc(pt, func.func, mir) catch |err| switch (err) {
1498 lf.updateFunc(pt, func, &mir) catch |err| switch (err) {
15321499 error.OutOfMemory => return diags.setAllocFailure(),
15331500 error.CodegenFail => return zcu.assertCodegenFailed(nav),
15341501 error.Overflow, error.RelocationNotByteAligned => {
......@@ -1539,8 +1506,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
15391506 },
15401507 };
15411508 }
1509 break :nav ip.indexToKey(func).func.owner_nav;
15421510 },
1543 .link_type => |ty| {
1511 .link_type => |ty| nav: {
15441512 const name = Type.fromInterned(ty).containerTypeName(ip).toSlice(ip);
15451513 const nav_prog_node = comp.link_prog_node.start(name, 0);
15461514 defer nav_prog_node.end();
......@@ -1552,8 +1520,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
15521520 };
15531521 }
15541522 }
1523 break :nav null;
15551524 },
1556 .update_line_number => |ti| {
1525 .update_line_number => |ti| nav: {
15571526 const nav_prog_node = comp.link_prog_node.start("Update line number", 0);
15581527 defer nav_prog_node.end();
15591528 if (pt.zcu.llvm_object == null) {
......@@ -1564,21 +1533,18 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
15641533 };
15651534 }
15661535 }
1536 break :nav null;
15671537 },
1568 }
1538 };
15691539
15701540 if (timer.finish()) |ns_link| report_time: {
1571 const zir_decl: ?InternPool.TrackedInst.Index = switch (task) {
1572 .link_type, .update_line_number => null,
1573 .link_nav => |nav| ip.getNav(nav).srcInst(ip),
1574 .link_func => |f| ip.getNav(ip.indexToKey(f.func).func.owner_nav).srcInst(ip),
1575 };
1576 comp.mutex.lock();
1577 defer comp.mutex.unlock();
1541 comp.mutex.lockUncancelable(io);
1542 defer comp.mutex.unlock(io);
15781543 const tr = &zcu.comp.time_report.?;
15791544 tr.stats.cpu_ns_link += ns_link;
1580 if (zir_decl) |inst| {
1581 const gop = tr.decl_link_ns.getOrPut(zcu.gpa, inst) catch |err| switch (err) {
1545 if (maybe_nav) |nav| {
1546 const zir_decl = ip.getNav(nav).srcInst(ip);
1547 const gop = tr.decl_link_ns.getOrPut(zcu.gpa, zir_decl) catch |err| switch (err) {
15821548 error.OutOfMemory => {
15831549 zcu.comp.setAllocFailure();
15841550 break :report_time;
......@@ -2208,8 +2174,13 @@ fn resolvePathInputLib(
22082174 const n2 = file.preadAll(buf2, n) catch |err|
22092175 fatal("failed to read {f}: {s}", .{ test_path, @errorName(err) });
22102176 if (n2 != buf2.len) fatal("failed to read {f}: unexpected end of file", .{test_path});
2211 var diags = Diags.init(gpa);
2177
2178 // This `Io` is only used for a mutex, and we know we aren't doing anything async/concurrent.
2179 var threaded: Io.Threaded = .init_single_threaded;
2180 defer threaded.deinit();
2181 var diags: Diags = .init(gpa, threaded.io());
22122182 defer diags.deinit();
2183
22132184 const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items);
22142185 if (diags.hasErrors()) {
22152186 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
src/link/Elf.zig+3-2
......@@ -713,6 +713,7 @@ pub fn allocateChunk(self: *Elf, args: struct {
713713pub fn loadInput(self: *Elf, input: link.Input) !void {
714714 const comp = self.base.comp;
715715 const gpa = comp.gpa;
716 const io = comp.io;
716717 const diags = &comp.link_diags;
717718 const target = self.getTarget();
718719 const debug_fmt_strip = comp.config.debug_format == .strip;
......@@ -720,8 +721,8 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
720721 const is_static_lib = self.base.isStaticLib();
721722
722723 if (comp.verbose_link) {
723 comp.mutex.lock(); // protect comp.arena
724 defer comp.mutex.unlock();
724 comp.mutex.lockUncancelable(io); // protect comp.arena
725 defer comp.mutex.unlock(io);
725726
726727 const argv = &self.dump_argv_list;
727728 switch (input) {
src/link/MachO.zig+2-2
......@@ -29,9 +29,9 @@ resolver: SymbolResolver = .{},
2929/// This table will be populated after `scanRelocs` has run.
3030/// Key is symbol index.
3131undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, UndefRefs) = .empty,
32undefs_mutex: std.Thread.Mutex = .{},
32undefs_mutex: std.Io.Mutex = .init,
3333dupes: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayList(File.Index)) = .empty,
34dupes_mutex: std.Thread.Mutex = .{},
34dupes_mutex: std.Io.Mutex = .init,
3535
3636dyld_info_cmd: macho.dyld_info_command = .{},
3737symtab_cmd: macho.symtab_command = .{},
src/link/MachO/Atom.zig+3-2
......@@ -555,9 +555,10 @@ fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {
555555 const file = self.getFile(macho_file);
556556 const ref = file.getSymbolRef(rel.target, macho_file);
557557 if (ref.getFile(macho_file) == null) {
558 macho_file.undefs_mutex.lock();
559 defer macho_file.undefs_mutex.unlock();
560558 const gpa = macho_file.base.comp.gpa;
559 const io = macho_file.base.comp.io;
560 macho_file.undefs_mutex.lockUncancelable(io);
561 defer macho_file.undefs_mutex.unlock(io);
561562 const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]);
562563 if (!gop.found_existing) {
563564 gop.value_ptr.* = .{ .refs = .{} };
src/link/MachO/CodeSignature.zig+1-1
......@@ -289,7 +289,7 @@ pub fn writeAdhocSignature(
289289 self.code_directory.inner.nCodeSlots = total_pages;
290290
291291 // Calculate hash for each page (in file) and write it to the buffer
292 var hasher = Hasher(Sha256){ .allocator = allocator, .thread_pool = macho_file.base.comp.thread_pool };
292 var hasher = Hasher(Sha256){ .allocator = allocator, .io = macho_file.base.comp.io };
293293 try hasher.hash(opts.file, self.code_directory.code_slots.items, .{
294294 .chunk_size = self.page_size,
295295 .max_file_size = opts.file_size,
src/link/MachO/InternalObject.zig+3-2
......@@ -512,8 +512,9 @@ pub fn checkUndefs(self: InternalObject, macho_file: *MachO) !void {
512512 const addUndef = struct {
513513 fn addUndef(mf: *MachO, index: MachO.SymbolResolver.Index, tag: anytype) !void {
514514 const gpa = mf.base.comp.gpa;
515 mf.undefs_mutex.lock();
516 defer mf.undefs_mutex.unlock();
515 const io = mf.base.comp.io;
516 mf.undefs_mutex.lockUncancelable(io);
517 defer mf.undefs_mutex.unlock(io);
517518 const gop = try mf.undefs.getOrPut(gpa, index);
518519 if (!gop.found_existing) {
519520 gop.value_ptr.* = tag;
src/link/MachO/file.zig+3-2
......@@ -242,6 +242,7 @@ pub const File = union(enum) {
242242 const tracy = trace(@src());
243243 defer tracy.end();
244244
245 const io = macho_file.base.comp.io;
245246 const gpa = macho_file.base.comp.gpa;
246247
247248 for (file.getSymbols(), file.getNlists(), 0..) |sym, nlist, i| {
......@@ -252,8 +253,8 @@ pub const File = union(enum) {
252253 const ref_file = ref.getFile(macho_file) orelse continue;
253254 if (ref_file.getIndex() == file.getIndex()) continue;
254255
255 macho_file.dupes_mutex.lock();
256 defer macho_file.dupes_mutex.unlock();
256 macho_file.dupes_mutex.lockUncancelable(io);
257 defer macho_file.dupes_mutex.unlock(io);
257258
258259 const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]);
259260 if (!gop.found_existing) {
src/link/MachO/hasher.zig+7-7
......@@ -3,7 +3,7 @@ pub fn ParallelHasher(comptime Hasher: type) type {
33
44 return struct {
55 allocator: Allocator,
6 thread_pool: *ThreadPool,
6 io: std.Io,
77
88 pub fn hash(self: Self, file: fs.File, out: [][hash_size]u8, opts: struct {
99 chunk_size: u64 = 0x4000,
......@@ -12,7 +12,7 @@ pub fn ParallelHasher(comptime Hasher: type) type {
1212 const tracy = trace(@src());
1313 defer tracy.end();
1414
15 var wg: WaitGroup = .{};
15 const io = self.io;
1616
1717 const file_size = blk: {
1818 const file_size = opts.max_file_size orelse try file.getEndPos();
......@@ -27,8 +27,8 @@ pub fn ParallelHasher(comptime Hasher: type) type {
2727 defer self.allocator.free(results);
2828
2929 {
30 wg.reset();
31 defer wg.wait();
30 var group: std.Io.Group = .init;
31 errdefer group.cancel(io);
3232
3333 for (out, results, 0..) |*out_buf, *result, i| {
3434 const fstart = i * chunk_size;
......@@ -36,7 +36,7 @@ pub fn ParallelHasher(comptime Hasher: type) type {
3636 file_size - fstart
3737 else
3838 chunk_size;
39 self.thread_pool.spawnWg(&wg, worker, .{
39 group.async(io, worker, .{
4040 file,
4141 fstart,
4242 buffer[fstart..][0..fsize],
......@@ -44,6 +44,8 @@ pub fn ParallelHasher(comptime Hasher: type) type {
4444 &(result.*),
4545 });
4646 }
47
48 group.wait(io);
4749 }
4850 for (results) |result| _ = try result;
4951 }
......@@ -72,5 +74,3 @@ const std = @import("std");
7274const trace = @import("../../tracy.zig").trace;
7375
7476const Allocator = mem.Allocator;
75const ThreadPool = std.Thread.Pool;
76const WaitGroup = std.Thread.WaitGroup;
src/link/MachO/relocatable.zig-1
......@@ -773,7 +773,6 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
773773
774774const std = @import("std");
775775const Path = std.Build.Cache.Path;
776const WaitGroup = std.Thread.WaitGroup;
777776const assert = std.debug.assert;
778777const log = std.log.scoped(.link);
779778const macho = std.macho;
src/link/MachO/uuid.zig+1-2
......@@ -15,7 +15,7 @@ pub fn calcUuid(comp: *const Compilation, file: fs.File, file_size: u64, out: *[
1515 const hashes = try comp.gpa.alloc([Md5.digest_length]u8, actual_num_chunks);
1616 defer comp.gpa.free(hashes);
1717
18 var hasher = Hasher(Md5){ .allocator = comp.gpa, .thread_pool = comp.thread_pool };
18 var hasher = Hasher(Md5){ .allocator = comp.gpa, .io = comp.io };
1919 try hasher.hash(file, hashes, .{
2020 .chunk_size = chunk_size,
2121 .max_file_size = file_size,
......@@ -46,4 +46,3 @@ const trace = @import("../../tracy.zig").trace;
4646const Compilation = @import("../../Compilation.zig");
4747const Md5 = std.crypto.hash.Md5;
4848const Hasher = @import("hasher.zig").ParallelHasher;
49const ThreadPool = std.Thread.Pool;
src/link/Queue.zig+154-279
......@@ -1,254 +1,171 @@
11//! Stores and manages the queue of link tasks. Each task is either a `PrelinkTask` or a `ZcuTask`.
22//!
3//! There must be at most one link thread (the thread processing these tasks) active at a time. If
4//! `!comp.separateCodegenThreadOk()`, then ZCU tasks will be run on the main thread, bypassing this
5//! queue entirely.
3//! There are two `std.Io.Queue`s, for prelink and ZCU tasks respectively. The compiler writes tasks
4//! to these queues, and a single concurrent linker task receives and processes them. `Compilation`
5//! is responsible for calling `finishPrelinkQueue` and `finishZcuQueue` once all relevant tasks
6//! have been queued. All prelink tasks must be queued and completed before any ZCU tasks can be
7//! processed.
68//!
7//! All prelink tasks must be processed before any ZCU tasks are processed. After all prelink tasks
8//! are run, but before any ZCU tasks are run, `prelink` must be called on the `link.File`.
9//! If concurrency is unavailable, the `enqueuePrelink` and `enqueueZcu` functions will instead run
10//! the given tasks immediately---the queues are unused.
911//!
10//! There will sometimes be a `ZcuTask` in the queue which is not yet ready because it depends on
11//! MIR which has not yet been generated by any codegen thread. In this case, we must pause
12//! processing of linker tasks until the MIR is ready. It would be incorrect to run any other link
13//! tasks first, since this would make builds unreproducible.
12//! If the codegen backend does not permit concurrency, then `Compilation` will call `finishZcuQueue`
13//! early so that the concurrent linker task exists after prelink and ZCU tasks will run
14//! non-concurrently in `enqueueZcu`.
1415
15mutex: std.Thread.Mutex,
16/// Validates that only one `flushTaskQueue` thread is running at a time.
17flush_safety: std.debug.SafetyLock,
16/// This is the concurrent call to `runLinkTasks`. It may be set to non-`null` in `start`, and is
17/// set to `null` by the main thread after it is canceled. It is not otherwise modified; as such, it
18/// may be checked non-atomically. If a task is being queued and this is `null`, tasks must be run
19/// eagerly.
20future: ?std.Io.Future(void),
1821
19/// This value is positive while there are still prelink tasks yet to be queued. Once they are
20/// all queued, this value becomes 0, and ZCU tasks can be run. Guarded by `mutex`.
21prelink_wait_count: u32,
22/// This is only used if `future == null` during prelink. In that case, it is used to ensure that
23/// only one prelink task is run at a time.
24prelink_mutex: std.Io.Mutex,
2225
23/// Prelink tasks which have been enqueued and are not yet owned by the worker thread.
24/// Allocated into `gpa`, guarded by `mutex`.
25queued_prelink: std.ArrayList(PrelinkTask),
26/// The worker thread moves items from `queued_prelink` into this array in order to process them.
27/// Allocated into `gpa`, accessed only by the worker thread.
28wip_prelink: std.ArrayList(PrelinkTask),
26/// Only valid if `future != null`.
27prelink_queue: std.Io.Queue(PrelinkTask),
28/// Only valid if `future != null`.
29zcu_queue: std.Io.Queue(ZcuTask),
2930
30/// Like `queued_prelink`, but for ZCU tasks.
31/// Allocated into `gpa`, guarded by `mutex`.
32queued_zcu: std.ArrayList(ZcuTask),
33/// Like `wip_prelink`, but for ZCU tasks.
34/// Allocated into `gpa`, accessed only by the worker thread.
35wip_zcu: std.ArrayList(ZcuTask),
36
37/// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this
38/// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the
39/// index into `wip_zcu` which we have reached.
40wip_zcu_idx: usize,
41
42/// The sum of all `air_bytes` for all currently-queued `ZcuTask.link_func` tasks. Because
43/// MIR bytes are approximately proportional to AIR bytes, this acts to limit the amount of
44/// AIR and MIR which is queued for codegen and link respectively, to prevent excessive
45/// memory usage if analysis produces AIR faster than it can be processed by codegen/link.
46/// The cap is `max_air_bytes_in_flight`.
47/// Guarded by `mutex`.
48air_bytes_in_flight: u32,
49/// If nonzero, then a call to `enqueueZcu` is blocked waiting to add a `link_func` task, but
50/// cannot until `air_bytes_in_flight` is no greater than this value.
51/// Guarded by `mutex`.
52air_bytes_waiting: u32,
53/// After setting `air_bytes_waiting`, `enqueueZcu` will wait on this condition (with `mutex`).
54/// When `air_bytes_waiting` many bytes can be queued, this condition should be signaled.
55air_bytes_cond: std.Thread.Condition,
56
57/// Guarded by `mutex`.
58state: union(enum) {
59 /// The link thread is currently running or queued to run.
60 running,
61 /// The link thread is not running or queued, because it has exhausted all immediately available
62 /// tasks. It should be spawned when more tasks are enqueued. If `prelink_wait_count` is not
63 /// zero, we are specifically waiting for prelink tasks.
64 finished,
65 /// The link thread is not running or queued, because it is waiting for this MIR to be populated.
66 /// Once codegen completes, it must call `mirReady` which will restart the link thread.
67 wait_for_mir: InternPool.Index,
68},
69
70/// In the worst observed case, MIR is around 50 times as large as AIR. More typically, the ratio is
71/// around 20. Going by that 50x multiplier, and assuming we want to consume no more than 500 MiB of
72/// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight.
73const max_air_bytes_in_flight = 10 * 1024 * 1024;
31/// The capacity of the task queue buffers.
32pub const buffer_size = 512;
7433
7534/// The initial `Queue` state, containing no tasks, expecting no prelink tasks, and with no running worker thread.
7635/// The `queued_prelink` field may be appended to before calling `start`.
7736pub const empty: Queue = .{
78 .mutex = .{},
79 .flush_safety = .{},
80 .prelink_wait_count = undefined, // set in `start`
81 .queued_prelink = .empty,
82 .wip_prelink = .empty,
83 .queued_zcu = .empty,
84 .wip_zcu = .empty,
85 .wip_zcu_idx = 0,
86 .state = .finished,
87 .air_bytes_in_flight = 0,
88 .air_bytes_waiting = 0,
89 .air_bytes_cond = .{},
37 .future = null,
38 .prelink_mutex = .init,
39 .prelink_queue = undefined, // set in `start` if needed
40 .zcu_queue = undefined, // set in `start` if needed
9041};
91/// `lf` is needed to correctly deinit any pending `ZcuTask`s.
92pub fn deinit(q: *Queue, comp: *Compilation) void {
93 const gpa = comp.gpa;
94 for (q.queued_zcu.items) |t| t.deinit(comp.zcu.?);
95 for (q.wip_zcu.items[q.wip_zcu_idx..]) |t| t.deinit(comp.zcu.?);
96 q.queued_prelink.deinit(gpa);
97 q.wip_prelink.deinit(gpa);
98 q.queued_zcu.deinit(gpa);
99 q.wip_zcu.deinit(gpa);
42
43pub fn cancel(q: *Queue, io: Io) void {
44 if (q.future) |*f| {
45 f.cancel(io);
46 q.future = null;
47 }
48}
49
50pub fn wait(q: *Queue, io: Io) void {
51 if (q.future) |*f| {
52 f.await(io);
53 q.future = null;
54 }
10055}
10156
10257/// This is expected to be called exactly once, after which the caller must not directly access
10358/// `queued_prelink` any longer. This will spawn the link thread if necessary.
104pub fn start(q: *Queue, comp: *Compilation) void {
105 assert(q.state == .finished);
106 assert(q.queued_zcu.items.len == 0);
107 // Reset this to 1. We can't init it to 1 in `empty`, because it would fall to 0 on successive
108 // incremental updates, but we still need the initial 1.
109 q.prelink_wait_count = 1;
110 if (q.queued_prelink.items.len != 0) {
111 q.state = .running;
112 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
59pub fn start(
60 q: *Queue,
61 comp: *Compilation,
62 arena: Allocator,
63) Allocator.Error!void {
64 assert(q.future == null);
65 q.prelink_queue = .init(try arena.alloc(PrelinkTask, buffer_size));
66 q.zcu_queue = .init(try arena.alloc(ZcuTask, buffer_size));
67 if (comp.io.concurrent(runLinkTasks, .{ q, comp })) |future| {
68 // We will run link tasks concurrently.
69 q.future = future;
70 } else |err| switch (err) {
71 error.ConcurrencyUnavailable => {
72 // We will run link tasks on the main thread.
73 q.prelink_queue = undefined;
74 q.zcu_queue = undefined;
75 },
11376 }
11477}
11578
116/// Every call to this must be paired with a call to `finishPrelinkItem`.
117pub fn startPrelinkItem(q: *Queue) void {
118 q.mutex.lock();
119 defer q.mutex.unlock();
120 assert(q.prelink_wait_count > 0); // must not have finished everything already
121 q.prelink_wait_count += 1;
122}
123/// This function must be called exactly one more time than `startPrelinkItem` is. The final call
124/// indicates that we have finished calling `startPrelinkItem`, so once all pending items finish,
125/// we are ready to move on to ZCU tasks.
126pub fn finishPrelinkItem(q: *Queue, comp: *Compilation) void {
127 {
128 q.mutex.lock();
129 defer q.mutex.unlock();
130 q.prelink_wait_count -= 1;
131 if (q.prelink_wait_count != 0) return;
132 // The prelink task count dropped to 0; restart the linker thread if necessary.
133 switch (q.state) {
134 .wait_for_mir => unreachable, // we've not started zcu tasks yet
135 .running => return,
136 .finished => {},
137 }
138 assert(q.queued_prelink.items.len == 0);
139 // Even if there are no ZCU tasks, we must restart the linker thread to make sure
140 // that `link.File.prelink()` is called.
141 q.state = .running;
79/// Enqueues all prelink tasks in `tasks`. Asserts that they were expected, i.e. that
80/// the queue is not yet closed. Also asserts that `tasks.len` is not 0.
81pub fn enqueuePrelink(q: *Queue, comp: *Compilation, tasks: []const PrelinkTask) Io.Cancelable!void {
82 const io = comp.io;
83
84 if (q.future != null) {
85 q.prelink_queue.putAll(io, tasks) catch |err| switch (err) {
86 error.Canceled => |e| return e,
87 error.Closed => unreachable,
88 };
89 } else {
90 try q.prelink_mutex.lock(io);
91 defer q.prelink_mutex.unlock(io);
92 for (tasks) |task| link.doPrelinkTask(comp, task);
14293 }
143 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
14494}
14595
146/// Called by codegen workers after they have populated a `ZcuTask.LinkFunc.SharedMir`. If the link
147/// thread was waiting for this MIR, it can resume.
148pub fn mirReady(q: *Queue, comp: *Compilation, func_index: InternPool.Index, mir: *ZcuTask.LinkFunc.SharedMir) void {
149 // We would like to assert that `mir` is not pending, but that would race with a worker thread
150 // potentially freeing it.
151 {
152 q.mutex.lock();
153 defer q.mutex.unlock();
154 switch (q.state) {
155 .finished, .running => return,
156 .wait_for_mir => |wait_for| if (wait_for != func_index) return,
96pub fn enqueueZcu(
97 q: *Queue,
98 comp: *Compilation,
99 tid: usize,
100 task: ZcuTask,
101) Io.Cancelable!void {
102 const io = comp.io;
103
104 assert(tid == 0);
105
106 if (q.future != null) {
107 if (q.zcu_queue.putOne(io, task)) |_| {
108 return;
109 } else |err| switch (err) {
110 error.Canceled => |e| return e,
111 error.Closed => {
112 // The linker is still processing prelink tasks. Wait for those
113 // to finish, after which the linker task will exist, and ZCU
114 // tasks will be run non-concurrently. This logic exists for
115 // backends which do not support `Zcu.Feature.separate_thread`.
116 q.wait(io);
117 },
157118 }
158 // We were waiting for `mir`, so we will restart the linker thread.
159 q.state = .running;
160119 }
161 assert(mir.status.load(.acquire) != .pending);
162 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
120
121 link.doZcuTask(comp, tid, task);
163122}
164123
165/// Enqueues all prelink tasks in `tasks`. Asserts that they were expected, i.e. that
166/// `prelink_wait_count` is not yet 0. Also asserts that `tasks.len` is not 0.
167pub fn enqueuePrelink(q: *Queue, comp: *Compilation, tasks: []const PrelinkTask) Allocator.Error!void {
168 {
169 q.mutex.lock();
170 defer q.mutex.unlock();
171 assert(q.prelink_wait_count > 0);
172 try q.queued_prelink.appendSlice(comp.gpa, tasks);
173 switch (q.state) {
174 .wait_for_mir => unreachable, // we've not started zcu tasks yet
175 .running => return,
176 .finished => {},
124pub fn finishPrelinkQueue(q: *Queue, comp: *Compilation) void {
125 if (q.future != null) {
126 q.prelink_queue.close(comp.io);
127 return;
128 }
129 // If linking non-concurrently, we must run prelink.
130 prelink: {
131 const lf = comp.bin_file orelse break :prelink;
132 if (lf.post_prelink) break :prelink;
133
134 if (lf.prelink()) |_| {
135 lf.post_prelink = true;
136 } else |err| switch (err) {
137 error.OutOfMemory => comp.link_diags.setAllocFailure(),
138 error.LinkFailure => {},
177139 }
178 // Restart the linker thread, because it was waiting for a task
179 q.state = .running;
180140 }
181 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
182141}
183142
184pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!void {
185 assert(comp.separateCodegenThreadOk());
186 {
187 q.mutex.lock();
188 defer q.mutex.unlock();
189 // If this is a `link_func` task, we might need to wait for `air_bytes_in_flight` to fall.
190 if (task == .link_func) {
191 const max_in_flight = max_air_bytes_in_flight -| task.link_func.air_bytes;
192 while (q.air_bytes_in_flight > max_in_flight) {
193 q.air_bytes_waiting = task.link_func.air_bytes;
194 q.air_bytes_cond.wait(&q.mutex);
195 q.air_bytes_waiting = 0;
196 }
197 q.air_bytes_in_flight += task.link_func.air_bytes;
198 }
199 try q.queued_zcu.append(comp.gpa, task);
200 switch (q.state) {
201 .running, .wait_for_mir => return,
202 .finished => if (q.prelink_wait_count > 0) return,
203 }
204 // Restart the linker thread, unless it would immediately be blocked
205 if (task == .link_func and task.link_func.mir.status.load(.acquire) == .pending) {
206 q.state = .{ .wait_for_mir = task.link_func.func };
207 return;
208 }
209 q.state = .running;
143pub fn finishZcuQueue(q: *Queue, comp: *Compilation) void {
144 if (q.future != null) {
145 q.zcu_queue.close(comp.io);
210146 }
211 comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp });
212147}
213148
214fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
215 q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex`
216 if (std.debug.runtime_safety) {
217 q.mutex.lock();
218 defer q.mutex.unlock();
219 assert(q.state == .running);
220 }
149fn runLinkTasks(q: *Queue, comp: *Compilation) void {
150 const tid = Compilation.getTid();
151 const io = comp.io;
221152
222153 var have_idle_tasks = true;
223 prelink: while (true) {
224 assert(q.wip_prelink.items.len == 0);
225 swap_queues: while (true) {
226 {
227 q.mutex.lock();
228 defer q.mutex.unlock();
229 std.mem.swap(std.ArrayList(PrelinkTask), &q.queued_prelink, &q.wip_prelink);
230 if (q.wip_prelink.items.len > 0) break :swap_queues;
231 if (q.prelink_wait_count == 0) break :prelink; // prelink is done
232 if (!have_idle_tasks) {
233 // We're expecting more prelink tasks so can't move on to ZCU tasks.
234 q.state = .finished;
235 q.flush_safety.unlock();
236 return;
237 }
238 }
239 have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
240 error.OutOfMemory => have_idle_tasks: {
241 comp.link_diags.setAllocFailure();
242 break :have_idle_tasks false;
243 },
244 error.LinkFailure => false,
245 };
246 }
247 for (q.wip_prelink.items) |task| {
154
155 prelink_tasks: while (true) {
156 var task_buf: [128]PrelinkTask = undefined;
157 const limit: usize = if (have_idle_tasks) 0 else 1;
158 const n = q.prelink_queue.get(io, &task_buf, limit) catch |err| switch (err) {
159 error.Canceled => return,
160 error.Closed => break :prelink_tasks,
161 };
162 if (n == 0) {
163 assert(have_idle_tasks);
164 have_idle_tasks = runIdleTask(comp, tid);
165 } else for (task_buf[0..n]) |task| {
248166 link.doPrelinkTask(comp, task);
167 have_idle_tasks = true;
249168 }
250 have_idle_tasks = true;
251 q.wip_prelink.clearRetainingCapacity();
252169 }
253170
254171 // We've finished the prelink tasks, so run prelink if necessary.
......@@ -263,79 +180,37 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
263180 }
264181 }
265182
266 // Now we can run ZCU tasks.
267 while (true) {
268 if (q.wip_zcu.items.len == q.wip_zcu_idx) swap_queues: {
269 q.wip_zcu.clearRetainingCapacity();
270 q.wip_zcu_idx = 0;
271 while (true) {
272 {
273 q.mutex.lock();
274 defer q.mutex.unlock();
275 std.mem.swap(std.ArrayList(ZcuTask), &q.queued_zcu, &q.wip_zcu);
276 if (q.wip_zcu.items.len > 0) break :swap_queues;
277 if (!have_idle_tasks) {
278 // We've exhausted all available tasks.
279 q.state = .finished;
280 q.flush_safety.unlock();
281 return;
282 }
283 }
284 have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
285 error.OutOfMemory => have_idle_tasks: {
286 comp.link_diags.setAllocFailure();
287 break :have_idle_tasks false;
288 },
289 error.LinkFailure => false,
290 };
291 }
292 }
293 const task = q.wip_zcu.items[q.wip_zcu_idx];
294 // If the task is a `link_func`, we might have to stop until its MIR is populated.
295 pending: {
296 if (task != .link_func) break :pending;
297 const status_ptr = &task.link_func.mir.status;
298 while (true) {
299 // First check without the mutex to optimize for the common case where MIR is ready.
300 if (status_ptr.load(.acquire) != .pending) break :pending;
301 if (have_idle_tasks) have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
302 error.OutOfMemory => have_idle_tasks: {
303 comp.link_diags.setAllocFailure();
304 break :have_idle_tasks false;
305 },
306 error.LinkFailure => false,
307 };
308 if (!have_idle_tasks) break;
309 }
310 q.mutex.lock();
311 defer q.mutex.unlock();
312 if (status_ptr.load(.acquire) != .pending) break :pending;
313 // We will stop for now, and get restarted once this MIR is ready.
314 q.state = .{ .wait_for_mir = task.link_func.func };
315 q.flush_safety.unlock();
316 return;
183 zcu_tasks: while (true) {
184 var task_buf: [128]ZcuTask = undefined;
185 const limit: usize = if (have_idle_tasks) 0 else 1;
186 const n = q.zcu_queue.get(io, &task_buf, limit) catch |err| switch (err) {
187 error.Canceled => return,
188 error.Closed => break :zcu_tasks,
189 };
190 if (n == 0) {
191 assert(have_idle_tasks);
192 have_idle_tasks = runIdleTask(comp, tid);
193 } else for (task_buf[0..n]) |task| {
194 link.doZcuTask(comp, tid, task);
195 have_idle_tasks = true;
317196 }
318 link.doZcuTask(comp, tid, task);
319 task.deinit(comp.zcu.?);
320 if (task == .link_func) {
321 // Decrease `air_bytes_in_flight`, since we've finished processing this MIR.
322 q.mutex.lock();
323 defer q.mutex.unlock();
324 q.air_bytes_in_flight -= task.link_func.air_bytes;
325 if (q.air_bytes_waiting != 0 and
326 q.air_bytes_in_flight <= max_air_bytes_in_flight -| q.air_bytes_waiting)
327 {
328 q.air_bytes_cond.signal();
329 }
330 }
331 q.wip_zcu_idx += 1;
332 have_idle_tasks = true;
333197 }
334198}
199fn runIdleTask(comp: *Compilation, tid: usize) bool {
200 return link.doIdleTask(comp, tid) catch |err| switch (err) {
201 error.OutOfMemory => have_more: {
202 comp.link_diags.setAllocFailure();
203 break :have_more false;
204 },
205 error.LinkFailure => false,
206 };
207}
335208
336209const std = @import("std");
337210const assert = std.debug.assert;
338211const Allocator = std.mem.Allocator;
212const Io = std.Io;
213
339214const Compilation = @import("../Compilation.zig");
340215const InternPool = @import("../InternPool.zig");
341216const link = @import("../link.zig");
src/link/Wasm.zig+3-2
......@@ -3393,10 +3393,11 @@ pub fn updateExports(
33933393pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
33943394 const comp = wasm.base.comp;
33953395 const gpa = comp.gpa;
3396 const io = comp.io;
33963397
33973398 if (comp.verbose_link) {
3398 comp.mutex.lock(); // protect comp.arena
3399 defer comp.mutex.unlock();
3399 comp.mutex.lockUncancelable(io); // protect comp.arena
3400 defer comp.mutex.unlock(io);
34003401
34013402 const argv = &wasm.dump_argv_list;
34023403 switch (input) {
src/main.zig+36-34
......@@ -11,7 +11,6 @@ const Allocator = mem.Allocator;
1111const Ast = std.zig.Ast;
1212const Color = std.zig.Color;
1313const warn = std.log.warn;
14const ThreadPool = std.Thread.Pool;
1514const cleanExit = std.process.cleanExit;
1615const Cache = std.Build.Cache;
1716const Path = std.Build.Cache.Path;
......@@ -200,6 +199,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
200199 const tr = tracy.trace(@src());
201200 defer tr.end();
202201
202 Compilation.setMainThread();
203
203204 if (args.len <= 1) {
204205 std.log.info("{s}", .{usage});
205206 fatal("expected command argument", .{});
......@@ -239,6 +240,8 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
239240
240241 var threaded: Io.Threaded = .init(gpa);
241242 defer threaded.deinit();
243 threaded_impl_ptr = &threaded;
244 threaded.stack_size = thread_stack_size;
242245 const io = threaded.io();
243246
244247 const cmd = args[1];
......@@ -3361,14 +3364,11 @@ fn buildOutputType(
33613364 },
33623365 };
33633366
3364 var thread_pool: ThreadPool = undefined;
3365 try thread_pool.init(.{
3366 .allocator = gpa,
3367 .n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
3368 .track_ids = true,
3369 .stack_size = thread_stack_size,
3370 });
3371 defer thread_pool.deinit();
3367 const thread_limit = @min(
3368 @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1),
3369 std.math.maxInt(Zcu.PerThread.IdBacking),
3370 );
3371 setThreadLimit(thread_limit);
33723372
33733373 for (create_module.c_source_files.items) |*src| {
33743374 dev.check(.c_compiler);
......@@ -3461,7 +3461,7 @@ fn buildOutputType(
34613461 var create_diag: Compilation.CreateDiagnostic = undefined;
34623462 const comp = Compilation.create(gpa, arena, io, &create_diag, .{
34633463 .dirs = dirs,
3464 .thread_pool = &thread_pool,
3464 .thread_limit = thread_limit,
34653465 .self_exe_path = switch (native_os) {
34663466 .wasi => null,
34673467 else => self_exe_path,
......@@ -4150,6 +4150,7 @@ fn serve(
41504150 runtime_args_start: ?usize,
41514151) !void {
41524152 const gpa = comp.gpa;
4153 const io = comp.io;
41534154
41544155 var server = try Server.init(.{
41554156 .in = in,
......@@ -4178,8 +4179,8 @@ fn serve(
41784179 const hdr = try server.receiveMessage();
41794180
41804181 // Lock the debug server while handling the message.
4181 if (comp.debugIncremental()) ids.mutex.lock();
4182 defer if (comp.debugIncremental()) ids.mutex.unlock();
4182 if (comp.debugIncremental()) try ids.mutex.lock(io);
4183 defer if (comp.debugIncremental()) ids.mutex.unlock(io);
41834184
41844185 switch (hdr.tag) {
41854186 .exit => return cleanExit(),
......@@ -5140,14 +5141,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
51405141 child_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;
51415142 child_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path;
51425143
5143 var thread_pool: ThreadPool = undefined;
5144 try thread_pool.init(.{
5145 .allocator = gpa,
5146 .n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
5147 .track_ids = true,
5148 .stack_size = thread_stack_size,
5149 });
5150 defer thread_pool.deinit();
5144 const thread_limit = @min(
5145 @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1),
5146 std.math.maxInt(Zcu.PerThread.IdBacking),
5147 );
5148 setThreadLimit(thread_limit);
51515149
51525150 // Dummy http client that is not actually used when fetch_command is unsupported.
51535151 // Prevents bootstrap from depending on a bunch of unnecessary stuff.
......@@ -5376,7 +5374,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
53765374 .main_mod = build_mod,
53775375 .emit_bin = .yes_cache,
53785376 .self_exe_path = self_exe_path,
5379 .thread_pool = &thread_pool,
5377 .thread_limit = thread_limit,
53805378 .verbose_cc = verbose_cc,
53815379 .verbose_link = verbose_link,
53825380 .verbose_air = verbose_air,
......@@ -5548,14 +5546,11 @@ fn jitCmd(
55485546 );
55495547 defer dirs.deinit();
55505548
5551 var thread_pool: ThreadPool = undefined;
5552 try thread_pool.init(.{
5553 .allocator = gpa,
5554 .n_jobs = @min(@max(std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
5555 .track_ids = true,
5556 .stack_size = thread_stack_size,
5557 });
5558 defer thread_pool.deinit();
5549 const thread_limit = @min(
5550 @max(std.Thread.getCpuCount() catch 1, 1),
5551 std.math.maxInt(Zcu.PerThread.IdBacking),
5552 );
5553 setThreadLimit(thread_limit);
55595554
55605555 var child_argv: std.ArrayList([]const u8) = .empty;
55615556 try child_argv.ensureUnusedCapacity(arena, args.len + 4);
......@@ -5619,7 +5614,7 @@ fn jitCmd(
56195614 .main_mod = root_mod,
56205615 .emit_bin = .yes_cache,
56215616 .self_exe_path = self_exe_path,
5622 .thread_pool = &thread_pool,
5617 .thread_limit = thread_limit,
56235618 .cache_mode = .whole,
56245619 }) catch |err| switch (err) {
56255620 error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
......@@ -6946,10 +6941,6 @@ fn cmdFetch(
69466941
69476942 const path_or_url = opt_path_or_url orelse fatal("missing url or path parameter", .{});
69486943
6949 var thread_pool: ThreadPool = undefined;
6950 try thread_pool.init(.{ .allocator = gpa });
6951 defer thread_pool.deinit();
6952
69536944 var http_client: std.http.Client = .{ .allocator = gpa, .io = io };
69546945 defer http_client.deinit();
69556946
......@@ -7601,3 +7592,14 @@ fn addLibDirectoryWarn2(
76017592 .path = path,
76027593 });
76037594}
7595
7596var threaded_impl_ptr: *Io.Threaded = undefined;
7597fn setThreadLimit(n: usize) void {
7598 // We want a maximum of n total threads to keep the InternPool happy, but
7599 // the main thread doesn't count towards the limits, so use n-1. Also, the
7600 // linker can run concurrently, so we need to set both the async *and* the
7601 // concurrency limit.
7602 const limit: Io.Limit = .limited(n - 1);
7603 threaded_impl_ptr.setAsyncLimit(limit);
7604 threaded_impl_ptr.concurrent_limit = limit;
7605}
src/mutable_value.zig+4-1
......@@ -55,6 +55,9 @@ pub const MutableValue = union(enum) {
5555 };
5656
5757 pub fn intern(mv: MutableValue, pt: Zcu.PerThread, arena: Allocator) Allocator.Error!Value {
58 const zcu = pt.zcu;
59 const comp = zcu.comp;
60 const io = comp.io;
5861 return Value.fromInterned(switch (mv) {
5962 .interned => |ip_index| ip_index,
6063 .eu_payload => |sv| try pt.intern(.{ .error_union = .{
......@@ -68,7 +71,7 @@ pub const MutableValue = union(enum) {
6871 .repeated => |sv| return pt.aggregateSplatValue(.fromInterned(sv.ty), try sv.child.intern(pt, arena)),
6972 .bytes => |b| try pt.intern(.{ .aggregate = .{
7073 .ty = b.ty,
71 .storage = .{ .bytes = try pt.zcu.intern_pool.getOrPutString(pt.zcu.gpa, pt.tid, b.data, .maybe_embedded_nulls) },
74 .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(comp.gpa, io, pt.tid, b.data, .maybe_embedded_nulls) },
7275 } }),
7376 .aggregate => |a| {
7477 const elems = try arena.alloc(InternPool.Index, a.elems.len);
tools/update_cpu_features.zig+24-27
......@@ -1882,10 +1882,18 @@ const targets = [_]ArchTarget{
18821882};
18831883
18841884pub fn main() anyerror!void {
1885 var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1885 var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
1886 defer _ = debug_allocator.deinit();
1887 const gpa = debug_allocator.allocator();
1888
1889 var arena_state: std.heap.ArenaAllocator = .init(gpa);
18861890 defer arena_state.deinit();
18871891 const arena = arena_state.allocator();
18881892
1893 var threaded: std.Io.Threaded = .init(gpa);
1894 defer threaded.deinit();
1895 const io = threaded.io();
1896
18891897 var args = try std.process.argsWithAllocator(arena);
18901898 const args0 = args.next().?;
18911899
......@@ -1925,34 +1933,23 @@ pub fn main() anyerror!void {
19251933 const root_progress = std.Progress.start(.{ .estimated_total_items = targets.len });
19261934 defer root_progress.end();
19271935
1928 if (builtin.single_threaded) {
1929 for (targets) |target| {
1930 if (filter) |zig_name| if (!std.mem.eql(u8, target.zig_name, zig_name)) continue;
1931 try processOneTarget(.{
1932 .llvm_tblgen_exe = llvm_tblgen_exe,
1933 .llvm_src_root = llvm_src_root,
1934 .zig_src_dir = zig_src_dir,
1935 .root_progress = root_progress,
1936 .target = target,
1937 });
1938 }
1939 } else {
1940 var pool: std.Thread.Pool = undefined;
1941 try pool.init(.{ .allocator = arena, .n_jobs = targets.len });
1942 defer pool.deinit();
1943
1944 for (targets) |target| {
1945 if (filter) |zig_name| if (!std.mem.eql(u8, target.zig_name, zig_name)) continue;
1946 const job = Job{
1947 .llvm_tblgen_exe = llvm_tblgen_exe,
1948 .llvm_src_root = llvm_src_root,
1949 .zig_src_dir = zig_src_dir,
1950 .root_progress = root_progress,
1951 .target = target,
1952 };
1953 try pool.spawn(processOneTarget, .{job});
1936 var group: std.Io.Group = .init;
1937 defer group.cancel(io);
1938
1939 for (targets) |target| {
1940 if (filter) |zig_name| {
1941 if (!std.mem.eql(u8, target.zig_name, zig_name)) continue;
19541942 }
1943 group.async(io, processOneTarget, .{.{
1944 .llvm_tblgen_exe = llvm_tblgen_exe,
1945 .llvm_src_root = llvm_src_root,
1946 .zig_src_dir = zig_src_dir,
1947 .root_progress = root_progress,
1948 .target = target,
1949 }});
19551950 }
1951
1952 group.wait(io);
19561953}
19571954
19581955const Job = struct {