authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 13:23:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:36-07:00
log1aa65d094ec737a140d7ab60e1b2af62144edd6a
tree92fb8756cf3ca97dd1ae55e3fe0b8cdf2a55ba2f
parent9eb85c4e5eb65ae987463af33ca24225f12b3a8b

Maker.Step.Run: leak into global arena less

There are still some uses: - fuzzing - generated paths (will require adjusting all step logic) - Step.result_stderr

2 files changed, 70 insertions(+), 80 deletions(-)

lib/compiler/Maker/Step.zig+1-1
...@@ -73,7 +73,7 @@ comptime {...@@ -73,7 +73,7 @@ comptime {
73 // Common cache line size is 128. This check prevents accidentally crossing73 // Common cache line size is 128. This check prevents accidentally crossing
74 // an additional cache line. In the future it might be nice to try to fit74 // an additional cache line. In the future it might be nice to try to fit
75 // this struct in 128 bytes or less.75 // this struct in 128 bytes or less.
76 assert(@sizeOf(@This()) <= 128 * 4);76 assert(@sizeOf(@This()) <= 128 * 3);
77}77}
7878
79pub const Extended = union(enum) {79pub const Extended = union(enum) {
lib/compiler/Maker/Step/Run.zig+69-79
...@@ -13,6 +13,7 @@ const assert = std.debug.assert;...@@ -13,6 +13,7 @@ const assert = std.debug.assert;
13const mem = std.mem;13const mem = std.mem;
14const process = std.process;14const process = std.process;
15const allocPrint = std.fmt.allocPrint;15const allocPrint = std.fmt.allocPrint;
16const Allocator = std.mem.Allocator;
1617
17const Step = @import("../Step.zig");18const Step = @import("../Step.zig");
18const Maker = @import("../../Maker.zig");19const Maker = @import("../../Maker.zig");
...@@ -28,13 +29,6 @@ cached_test_metadata: ?CachedTestMetadata = null,...@@ -28,13 +29,6 @@ cached_test_metadata: ?CachedTestMetadata = null,
28/// executable that contains fuzz tests.29/// executable that contains fuzz tests.
29rebuilt_executable: ?Path = null,30rebuilt_executable: ?Path = null,
3031
31/// Persisted to reuse memory on subsequent calls to `make`.
32argv: std.ArrayList([]const u8) = .empty,
33/// Persisted to reuse memory on subsequent calls to `make`.
34output_placeholders: std.ArrayList(IndexedOutput) = .empty,
35/// Persisted to reuse memory on subsequent calls to `make`.
36environ_map: std.process.Environ.Map = .{ .array_hash_map = .empty, .allocator = undefined },
37
38pub fn make(32pub fn make(
39 run: *Run,33 run: *Run,
40 run_index: Configuration.Step.Index,34 run_index: Configuration.Step.Index,
...@@ -45,16 +39,17 @@ pub fn make(...@@ -45,16 +39,17 @@ pub fn make(
45 const gpa = maker.gpa;39 const gpa = maker.gpa;
46 const step = maker.stepByIndex(run_index);40 const step = maker.stepByIndex(run_index);
47 const io = graph.io;41 const io = graph.io;
48 const arena = graph.arena; // TODO don't leak into the process arena
49 const conf = &maker.scanned_config.configuration;42 const conf = &maker.scanned_config.configuration;
50 const conf_step = run_index.ptr(conf);43 const conf_step = run_index.ptr(conf);
51 const conf_run = conf_step.extended.get(conf.extra).run;44 const conf_run = conf_step.extended.get(conf.extra).run;
52 const argv_list = &run.argv;
53 const output_placeholders = &run.output_placeholders;
54 const cache_root = graph.local_cache_root;45 const cache_root = graph.local_cache_root;
5546
56 argv_list.clearRetainingCapacity();47 var arena_allocator: std.heap.ArenaAllocator = .init(gpa);
57 output_placeholders.clearRetainingCapacity();48 defer arena_allocator.deinit();
49 const arena = arena_allocator.allocator();
50
51 var argv_list: std.ArrayList([]const u8) = .empty;
52 var output_placeholders: std.ArrayList(IndexedOutput) = .empty;
5853
59 var man = graph.cache.obtain();54 var man = graph.cache.obtain();
60 defer man.deinit();55 defer man.deinit();
...@@ -89,7 +84,7 @@ pub fn make(...@@ -89,7 +84,7 @@ pub fn make(
89 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";84 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
90 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);85 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
91 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{86 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
92 prefix, try convertPathArg(run_index, maker, file_path), suffix,87 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
93 }));88 }));
94 man.hash.addBytesZ(prefix);89 man.hash.addBytesZ(prefix);
95 man.hash.addBytesZ(suffix);90 man.hash.addBytesZ(suffix);
...@@ -100,7 +95,7 @@ pub fn make(...@@ -100,7 +95,7 @@ pub fn make(
100 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";95 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
101 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);96 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
102 const resolved_arg = try mem.concat(arena, u8, &.{97 const resolved_arg = try mem.concat(arena, u8, &.{
103 prefix, try convertPathArg(run_index, maker, file_path), suffix,98 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
104 });99 });
105 argv_list.appendAssumeCapacity(resolved_arg);100 argv_list.appendAssumeCapacity(resolved_arg);
106 man.hash.addBytes(resolved_arg);101 man.hash.addBytes(resolved_arg);
...@@ -144,7 +139,7 @@ pub fn make(...@@ -144,7 +139,7 @@ pub fn make(
144 const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*;139 const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*;
145140
146 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{141 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
147 prefix, try convertPathArg(run_index, maker, file_path), suffix,142 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
148 }));143 }));
149144
150 _ = try man.addFilePath(file_path, null);145 _ = try man.addFilePath(file_path, null);
...@@ -183,7 +178,7 @@ pub fn make(...@@ -183,7 +178,7 @@ pub fn make(
183178
184 man.hash.add(conf_run.flags.test_runner_mode);179 man.hash.add(conf_run.flags.test_runner_mode);
185 if (conf_run.flags.test_runner_mode) {180 if (conf_run.flags.test_runner_mode) {
186 const cache_dir_string = try convertPathArg(run_index, maker, .{ .root_dir = cache_root });181 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root });
187182
188 try argv_list.ensureUnusedCapacity(gpa, 3);183 try argv_list.ensureUnusedCapacity(gpa, 3);
189 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));184 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));
...@@ -259,8 +254,8 @@ pub fn make(...@@ -259,8 +254,8 @@ pub fn make(
259 const digest = if (has_side_effects) man.hash.final() else man.final();254 const digest = if (has_side_effects) man.hash.final() else man.final();
260 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;255 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
261 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);256 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);
262 try populateGeneratedPathsCreateDirs(run, run_index, maker, output_dir_path);257 try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items);
263 try runCommand(run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null);258 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null);
264 if (!has_side_effects) try step.writeManifestAndWatch(maker, &man);259 if (!has_side_effects) try step.writeManifestAndWatch(maker, &man);
265 return;260 return;
266 }261 }
...@@ -270,8 +265,8 @@ pub fn make(...@@ -270,8 +265,8 @@ pub fn make(
270 io.random(@ptrCast(&rand_int));265 io.random(@ptrCast(&rand_int));
271 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);266 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
272267
273 try populateGeneratedPathsCreateDirs(run, run_index, maker, tmp_dir_path);268 try populateGeneratedPathsCreateDirs(arena, run_index, maker, tmp_dir_path, output_placeholders.items, argv_list.items);
274 try runCommand(run, run_index, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null);269 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, tmp_dir_path, null);
275270
276 for (output_placeholders.items) |placeholder| {271 for (output_placeholders.items) |placeholder| {
277 const arg = placeholder.arg_index.get(conf);272 const arg = placeholder.arg_index.get(conf);
...@@ -341,6 +336,7 @@ pub fn make(...@@ -341,6 +336,7 @@ pub fn make(
341/// * A test (or a response from the test runner) times out336/// * A test (or a response from the test runner) times out
342/// * The wait fails, indicating the child closed stdout and stderr337/// * The wait fails, indicating the child closed stdout and stderr
343fn waitZigTest(338fn waitZigTest(
339 arena: Allocator,
344 run: *Run,340 run: *Run,
345 run_index: Configuration.Step.Index,341 run_index: Configuration.Step.Index,
346 maker: *Maker,342 maker: *Maker,
...@@ -363,7 +359,6 @@ fn waitZigTest(...@@ -363,7 +359,6 @@ fn waitZigTest(
363 const graph = maker.graph;359 const graph = maker.graph;
364 const gpa = maker.gpa;360 const gpa = maker.gpa;
365 const io = graph.io;361 const io = graph.io;
366 const arena = graph.arena; // TODO don't leak into the process arena
367 const step = maker.stepByIndex(run_index);362 const step = maker.stepByIndex(run_index);
368363
369 var sub_prog_node: ?std.Progress.Node = null;364 var sub_prog_node: ?std.Progress.Node = null;
...@@ -715,7 +710,7 @@ const FuzzTestRunner = struct {...@@ -715,7 +710,7 @@ const FuzzTestRunner = struct {
715 }710 }
716 }711 }
717712
718 fn listen(f: *FuzzTestRunner) !void {713 fn listen(f: *FuzzTestRunner, arena: Allocator) !void {
719 const maker = f.ctx.fuzz.maker;714 const maker = f.ctx.fuzz.maker;
720 const graph = maker.graph;715 const graph = maker.graph;
721 const io = graph.io;716 const io = graph.io;
...@@ -739,7 +734,7 @@ const FuzzTestRunner = struct {...@@ -739,7 +734,7 @@ const FuzzTestRunner = struct {
739 else => |read_e| return read_e,734 else => |read_e| return read_e,
740 }),735 }),
741 2 => try f.completeStderrRead(id, result.file_read_streaming catch |e| switch (e) {736 2 => try f.completeStderrRead(id, result.file_read_streaming catch |e| switch (e) {
742 error.EndOfStream => return f.instanceEos(id),737 error.EndOfStream => return f.instanceEos(arena, id),
743 else => |read_e| return read_e,738 else => |read_e| return read_e,
744 }),739 }),
745 else => unreachable,740 else => unreachable,
...@@ -901,7 +896,7 @@ const FuzzTestRunner = struct {...@@ -901,7 +896,7 @@ const FuzzTestRunner = struct {
901 } });896 } });
902 }897 }
903898
904 fn instanceEos(f: *FuzzTestRunner, id: u32) !void {899 fn instanceEos(f: *FuzzTestRunner, arena: Allocator, id: u32) !void {
905 const maker = f.ctx.fuzz.maker;900 const maker = f.ctx.fuzz.maker;
906 const instance = &f.instances[id];901 const instance = &f.instances[id];
907 const run_index = f.run_index;902 const run_index = f.run_index;
...@@ -914,7 +909,7 @@ const FuzzTestRunner = struct {...@@ -914,7 +909,7 @@ const FuzzTestRunner = struct {
914 instance.child.stdin = null;909 instance.child.stdin = null;
915 const term = try instance.child.wait(io);910 const term = try instance.child.wait(io);
916 if (!termMatches(.{ .exited = 0 }, term)) {911 if (!termMatches(.{ .exited = 0 }, term)) {
917 step.result_stderr = try f.mergedStderr();912 step.result_stderr = try f.mergedStderr(arena);
918 try f.saveCrash(id, term);913 try f.saveCrash(id, term);
919 return step.fail(maker, "test process unexpectedly {f}", .{fmtTerm(term)});914 return step.fail(maker, "test process unexpectedly {f}", .{fmtTerm(term)});
920 }915 }
...@@ -1057,11 +1052,7 @@ const FuzzTestRunner = struct {...@@ -1057,11 +1052,7 @@ const FuzzTestRunner = struct {
1057 }1052 }
1058 }1053 }
10591054
1060 fn mergedStderr(f: *FuzzTestRunner) std.mem.Allocator.Error![]const u8 {1055 fn mergedStderr(f: *FuzzTestRunner, arena: Allocator) Allocator.Error![]const u8 {
1061 const maker = f.ctx.fuzz.maker;
1062 const graph = maker.graph;
1063 const arena = graph.arena; // TODO don't leak into the process arena
1064
1065 // Collect any available stderr1056 // Collect any available stderr
1066 while (f.batch.next()) |completion| {1057 while (f.batch.next()) |completion| {
1067 if (completion.index % 3 != 2) continue;1058 if (completion.index % 3 != 2) continue;
...@@ -1092,12 +1083,13 @@ fn evalFuzzTest(...@@ -1092,12 +1083,13 @@ fn evalFuzzTest(
1092 var f: FuzzTestRunner = try .init(run, run_index, fuzz_context, progress_node, spawn_options);1083 var f: FuzzTestRunner = try .init(run, run_index, fuzz_context, progress_node, spawn_options);
1093 defer f.deinit();1084 defer f.deinit();
1094 try f.startInstances();1085 try f.startInstances();
1095 try f.listen();1086 try f.listen(fuzz_context.fuzz.maker.graph.arena);
1096}1087}
10971088
1098const StdioPollEnum = enum { stdout, stderr };1089const StdioPollEnum = enum { stdout, stderr };
10991090
1100fn evalZigTest(1091fn evalZigTest(
1092 arena: Allocator,
1101 run: *Run,1093 run: *Run,
1102 run_index: Configuration.Step.Index,1094 run_index: Configuration.Step.Index,
1103 maker: *Maker,1095 maker: *Maker,
...@@ -1113,7 +1105,6 @@ fn evalZigTest(...@@ -1113,7 +1105,6 @@ fn evalZigTest(
1113 const graph = maker.graph;1105 const graph = maker.graph;
1114 const gpa = maker.gpa;1106 const gpa = maker.gpa;
1115 const io = graph.io;1107 const io = graph.io;
1116 const arena = graph.arena; // TODO don't leak into the process arena
1117 const step = maker.stepByIndex(run_index);1108 const step = maker.stepByIndex(run_index);
11181109
1119 // We will update this every time a child runs.1110 // We will update this every time a child runs.
...@@ -1146,6 +1137,7 @@ fn evalZigTest(...@@ -1146,6 +1137,7 @@ fn evalZigTest(
1146 };1137 };
11471138
1148 switch (try waitZigTest(1139 switch (try waitZigTest(
1140 arena,
1149 run,1141 run,
1150 run_index,1142 run_index,
1151 maker,1143 maker,
...@@ -1380,13 +1372,13 @@ fn sendRunFuzzTestMessage(...@@ -1380,13 +1372,13 @@ fn sendRunFuzzTestMessage(
1380}1372}
13811373
1382fn evalGeneric(1374fn evalGeneric(
1375 arena: Allocator,
1383 run_index: Configuration.Step.Index,1376 run_index: Configuration.Step.Index,
1384 maker: *Maker,1377 maker: *Maker,
1385 spawn_options: process.SpawnOptions,1378 spawn_options: process.SpawnOptions,
1386) !EvalGenericResult {1379) !EvalGenericResult {
1387 const graph = maker.graph;1380 const graph = maker.graph;
1388 const io = graph.io;1381 const io = graph.io;
1389 const arena = graph.arena; // TODO don't leak into the process arena
1390 const gpa = maker.gpa;1382 const gpa = maker.gpa;
1391 const conf = &maker.scanned_config.configuration;1383 const conf = &maker.scanned_config.configuration;
1392 const conf_step = run_index.ptr(conf);1384 const conf_step = run_index.ptr(conf);
...@@ -1520,15 +1512,17 @@ pub fn rerunInFuzzMode(...@@ -1520,15 +1512,17 @@ pub fn rerunInFuzzMode(
1520 const graph = maker.graph;1512 const graph = maker.graph;
1521 const step = maker.stepByIndex(run_index);1513 const step = maker.stepByIndex(run_index);
1522 const io = graph.io;1514 const io = graph.io;
1523 const arena = graph.arena; // TODO don't leak into the process arena
1524 const gpa = maker.gpa;1515 const gpa = maker.gpa;
1525 const conf = &maker.scanned_config.configuration;1516 const conf = &maker.scanned_config.configuration;
1526 const conf_step = run_index.ptr(conf);1517 const conf_step = run_index.ptr(conf);
1527 const conf_run = conf_step.extended.get(conf.extra).run;1518 const conf_run = conf_step.extended.get(conf.extra).run;
1528 const argv_list = &run.argv;
1529 const cache_root = graph.local_cache_root;1519 const cache_root = graph.local_cache_root;
15301520
1531 argv_list.clearRetainingCapacity();1521 var arena_allocator: std.heap.ArenaAllocator = .init(gpa);
1522 defer arena_allocator.deinit();
1523 const arena = arena_allocator.allocator();
1524
1525 var argv_list: std.ArrayList([]const u8) = .empty;
15321526
1533 for (conf_run.args.slice) |arg_index| {1527 for (conf_run.args.slice) |arg_index| {
1534 const arg = arg_index.get(conf);1528 const arg = arg_index.get(conf);
...@@ -1543,7 +1537,7 @@ pub fn rerunInFuzzMode(...@@ -1543,7 +1537,7 @@ pub fn rerunInFuzzMode(
1543 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1537 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
1544 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);1538 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
1545 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{1539 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
1546 prefix, try convertPathArg(run_index, maker, file_path), suffix,1540 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
1547 }));1541 }));
1548 },1542 },
1549 .path_directory => {1543 .path_directory => {
...@@ -1551,7 +1545,7 @@ pub fn rerunInFuzzMode(...@@ -1551,7 +1545,7 @@ pub fn rerunInFuzzMode(
1551 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1545 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
1552 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);1546 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
1553 const resolved_arg = try mem.concat(arena, u8, &.{1547 const resolved_arg = try mem.concat(arena, u8, &.{
1554 prefix, try convertPathArg(run_index, maker, file_path), suffix,1548 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
1555 });1549 });
1556 argv_list.appendAssumeCapacity(resolved_arg);1550 argv_list.appendAssumeCapacity(resolved_arg);
1557 },1551 },
...@@ -1593,7 +1587,7 @@ pub fn rerunInFuzzMode(...@@ -1593,7 +1587,7 @@ pub fn rerunInFuzzMode(
1593 producer_make_comp.installed_path orelse1587 producer_make_comp.installed_path orelse
1594 maker.generatedPath(producer.generated_bin.value.?).*;1588 maker.generatedPath(producer.generated_bin.value.?).*;
1595 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{1589 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
1596 prefix, try convertPathArg(run_index, maker, file_path), suffix,1590 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,
1597 }));1591 }));
1598 },1592 },
1599 .output_file => unreachable,1593 .output_file => unreachable,
...@@ -1603,7 +1597,7 @@ pub fn rerunInFuzzMode(...@@ -1603,7 +1597,7 @@ pub fn rerunInFuzzMode(
1603 }1597 }
16041598
1605 if (conf_run.flags.test_runner_mode) {1599 if (conf_run.flags.test_runner_mode) {
1606 const cache_dir_string = try convertPathArg(run_index, maker, .{ .root_dir = cache_root });1600 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root });
16071601
1608 try argv_list.ensureUnusedCapacity(gpa, 3);1602 try argv_list.ensureUnusedCapacity(gpa, 3);
1609 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));1603 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));
...@@ -1620,7 +1614,7 @@ pub fn rerunInFuzzMode(...@@ -1620,7 +1614,7 @@ pub fn rerunInFuzzMode(
1620 var rand_int: u64 = undefined;1614 var rand_int: u64 = undefined;
1621 io.random(@ptrCast(&rand_int));1615 io.random(@ptrCast(&rand_int));
1622 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);1616 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
1623 try runCommand(run, run_index, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{1617 try runCommand(arena, run, run_index, maker, prog_node, argv_list.items, has_side_effects, tmp_dir_path, .{
1624 .fuzz = fuzz,1618 .fuzz = fuzz,
1625 });1619 });
1626}1620}
...@@ -1633,13 +1627,12 @@ fn populateGeneratedPaths(...@@ -1633,13 +1627,12 @@ fn populateGeneratedPaths(
1633) !void {1627) !void {
1634 const conf = &maker.scanned_config.configuration;1628 const conf = &maker.scanned_config.configuration;
1635 const graph = maker.graph;1629 const graph = maker.graph;
1636 const arena = graph.arena; // TODO don't leak into the process arena
16371630
1638 for (output_placeholders) |placeholder| {1631 for (output_placeholders) |placeholder| {
1639 const arg = placeholder.arg_index.get(conf);1632 const arg = placeholder.arg_index.get(conf);
1640 maker.generatedPath(arg.generated.value.?).* = .{1633 maker.generatedPath(arg.generated.value.?).* = .{
1641 .root_dir = cache_root,1634 .root_dir = cache_root,
1642 .sub_path = try Dir.path.join(arena, &.{1635 .sub_path = try Dir.path.join(graph.arena, &.{
1643 "o", digest, arg.basename.value.?.slice(conf),1636 "o", digest, arg.basename.value.?.slice(conf),
1644 }),1637 }),
1645 };1638 };
...@@ -1647,20 +1640,20 @@ fn populateGeneratedPaths(...@@ -1647,20 +1640,20 @@ fn populateGeneratedPaths(
1647}1640}
16481641
1649fn populateGeneratedPathsCreateDirs(1642fn populateGeneratedPathsCreateDirs(
1650 run: *Run,1643 arena: Allocator,
1651 run_index: Configuration.Step.Index,1644 run_index: Configuration.Step.Index,
1652 maker: *Maker,1645 maker: *Maker,
1653 output_dir_path: []const u8,1646 output_dir_path: []const u8,
1647 output_placeholders: []const IndexedOutput,
1648 argv: [][]const u8,
1654) !void {1649) !void {
1655 const step = maker.stepByIndex(run_index);1650 const step = maker.stepByIndex(run_index);
1656 const conf = &maker.scanned_config.configuration;1651 const conf = &maker.scanned_config.configuration;
1657 const graph = maker.graph;1652 const graph = maker.graph;
1658 const io = graph.io;1653 const io = graph.io;
1659 const arena = graph.arena; // TODO don't leak into the process arena
1660 const cache_root = graph.local_cache_root;1654 const cache_root = graph.local_cache_root;
1661 const argv = run.argv.items;
16621655
1663 for (run.output_placeholders.items) |placeholder| {1656 for (output_placeholders) |placeholder| {
1664 const arg = placeholder.arg_index.get(conf);1657 const arg = placeholder.arg_index.get(conf);
1665 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";1658 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
1666 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1659 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
...@@ -1668,7 +1661,7 @@ fn populateGeneratedPathsCreateDirs(...@@ -1668,7 +1661,7 @@ fn populateGeneratedPathsCreateDirs(
16681661
1669 const generated_path: Path = .{1662 const generated_path: Path = .{
1670 .root_dir = cache_root,1663 .root_dir = cache_root,
1671 .sub_path = try Dir.path.join(arena, &.{ output_dir_path, basename }),1664 .sub_path = try Dir.path.join(graph.arena, &.{ output_dir_path, basename }),
1672 };1665 };
1673 const create_path: Path = .{1666 const create_path: Path = .{
1674 .root_dir = cache_root,1667 .root_dir = cache_root,
...@@ -1683,7 +1676,7 @@ fn populateGeneratedPathsCreateDirs(...@@ -1683,7 +1676,7 @@ fn populateGeneratedPathsCreateDirs(
16831676
1684 maker.generatedPath(arg.generated.value.?).* = generated_path;1677 maker.generatedPath(arg.generated.value.?).* = generated_path;
16851678
1686 const arg_output_path = try convertPathArg(run_index, maker, generated_path);1679 const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path);
1687 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });1680 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });
1688 }1681 }
1689}1682}
...@@ -1696,12 +1689,11 @@ fn populateGeneratedStdIo(...@@ -1696,12 +1689,11 @@ fn populateGeneratedStdIo(
1696) !void {1689) !void {
1697 const conf = &maker.scanned_config.configuration;1690 const conf = &maker.scanned_config.configuration;
1698 const graph = maker.graph;1691 const graph = maker.graph;
1699 const arena = graph.arena; // TODO don't leak into the process arena
17001692
1701 if (conf_run.captured_stdout.value) |captured| {1693 if (conf_run.captured_stdout.value) |captured| {
1702 maker.generatedPath(captured.generated_file).* = .{1694 maker.generatedPath(captured.generated_file).* = .{
1703 .root_dir = cache_root,1695 .root_dir = cache_root,
1704 .sub_path = try Dir.path.join(arena, &.{1696 .sub_path = try Dir.path.join(graph.arena, &.{
1705 "o", digest, captured.basename.slice(conf),1697 "o", digest, captured.basename.slice(conf),
1706 }),1698 }),
1707 };1699 };
...@@ -1710,7 +1702,7 @@ fn populateGeneratedStdIo(...@@ -1710,7 +1702,7 @@ fn populateGeneratedStdIo(
1710 if (conf_run.captured_stderr.value) |captured| {1702 if (conf_run.captured_stderr.value) |captured| {
1711 maker.generatedPath(captured.generated_file).* = .{1703 maker.generatedPath(captured.generated_file).* = .{
1712 .root_dir = cache_root,1704 .root_dir = cache_root,
1713 .sub_path = try Dir.path.join(arena, &.{1705 .sub_path = try Dir.path.join(graph.arena, &.{
1714 "o", digest, captured.basename.slice(conf),1706 "o", digest, captured.basename.slice(conf),
1715 }),1707 }),
1716 };1708 };
...@@ -1736,6 +1728,7 @@ const FuzzContext = struct {...@@ -1736,6 +1728,7 @@ const FuzzContext = struct {
1736};1728};
17371729
1738fn runCommand(1730fn runCommand(
1731 arena: Allocator,
1739 run: *Run,1732 run: *Run,
1740 run_index: Configuration.Step.Index,1733 run_index: Configuration.Step.Index,
1741 maker: *Maker,1734 maker: *Maker,
...@@ -1746,7 +1739,6 @@ fn runCommand(...@@ -1746,7 +1739,6 @@ fn runCommand(
1746 fuzz_context: ?FuzzContext,1739 fuzz_context: ?FuzzContext,
1747) Step.ExtendedMakeError!void {1740) Step.ExtendedMakeError!void {
1748 const graph = maker.graph;1741 const graph = maker.graph;
1749 const arena = graph.arena; // TODO don't leak into process arena
1750 const gpa = maker.gpa;1742 const gpa = maker.gpa;
1751 const step = maker.stepByIndex(run_index);1743 const step = maker.stepByIndex(run_index);
1752 const io = graph.io;1744 const io = graph.io;
...@@ -1754,7 +1746,6 @@ fn runCommand(...@@ -1754,7 +1746,6 @@ fn runCommand(
1754 const conf = &maker.scanned_config.configuration;1746 const conf = &maker.scanned_config.configuration;
1755 const conf_step = run_index.ptr(conf);1747 const conf_step = run_index.ptr(conf);
1756 const conf_run = conf_step.extended.get(conf.extra).run;1748 const conf_run = conf_step.extended.get(conf.extra).run;
1757 const environ_map = &run.environ_map;
17581749
1759 const cwd: process.Child.Cwd = if (conf_run.cwd.value) |lazy_cwd|1750 const cwd: process.Child.Cwd = if (conf_run.cwd.value) |lazy_cwd|
1760 .{ .path = try maker.resolveLazyPathIndexAbs(arena, lazy_cwd, run_index) }1751 .{ .path = try maker.resolveLazyPathIndexAbs(arena, lazy_cwd, run_index) }
...@@ -1768,12 +1759,11 @@ fn runCommand(...@@ -1768,12 +1759,11 @@ fn runCommand(
17681759
1769 var interp_argv: std.ArrayList([]const u8) = .empty;1760 var interp_argv: std.ArrayList([]const u8) = .empty;
17701761
1771 // `environ_map` is initialized with an undefined `allocator` field; lazily1762 var environ_map: std.process.Environ.Map = .init(gpa);
1772 // initialize it here.1763 defer environ_map.deinit();
1773 environ_map.allocator = gpa;1764
1774 // In either case we add to this mutatable data structure so that we can1765 // In either case we add to this mutatable data structure so that we can
1775 // tweak the environment below.1766 // tweak the environment below.
1776 environ_map.clearRetainingCapacity();
1777 if (conf_run.environ_map.value) |env_map_index| {1767 if (conf_run.environ_map.value) |env_map_index| {
1778 const conf_env_map = env_map_index.get(conf);1768 const conf_env_map = env_map_index.get(conf);
1779 for (conf_env_map.keys.slice(conf), conf_env_map.values.slice(conf)) |k, v| {1769 for (conf_env_map.keys.slice(conf), conf_env_map.values.slice(conf)) |k, v| {
...@@ -1792,7 +1782,7 @@ fn runCommand(...@@ -1792,7 +1782,7 @@ fn runCommand(
1792 const root_module = producer.root_module.get(conf);1782 const root_module = producer.root_module.get(conf);
1793 const root_module_target = root_module.resolved_target.get(conf).?.result.get(conf);1783 const root_module_target = root_module.resolved_target.get(conf).?.result.get(conf);
1794 if (root_module_target.flags.os_tag == .windows) {1784 if (root_module_target.flags.os_tag == .windows) {
1795 try addPathForDynLibs(maker, producer_index, environ_map, argv[0]);1785 try addPathForDynLibs(maker, arena, producer_index, &environ_map, argv[0]);
1796 }1786 }
1797 }1787 }
17981788
...@@ -1801,15 +1791,16 @@ fn runCommand(...@@ -1801,15 +1791,16 @@ fn runCommand(
1801 .dir => unreachable,1791 .dir => unreachable,
1802 .inherit => null,1792 .inherit => null,
1803 };1793 };
1804 try graph.handleVerbose(cwd_string, environ_map, argv);1794 try graph.handleVerbose(cwd_string, &environ_map, argv);
18051795
1806 const opt_generic_result = spawnChildAndCollect(1796 const opt_generic_result = spawnChildAndCollect(
1797 arena,
1807 run_index,1798 run_index,
1808 run,1799 run,
1809 maker,1800 maker,
1810 progress_node,1801 progress_node,
1811 argv,1802 argv,
1812 environ_map,1803 &environ_map,
1813 has_side_effects,1804 has_side_effects,
1814 fuzz_context,1805 fuzz_context,
1815 ) catch |err| term: {1806 ) catch |err| term: {
...@@ -1863,7 +1854,7 @@ fn runCommand(...@@ -1863,7 +1854,7 @@ fn runCommand(
1863 try environ_map.put("WINEDEBUG", "-all");1854 try environ_map.put("WINEDEBUG", "-all");
1864 }1855 }
1865 } else {1856 } else {
1866 return failForeign(&conf_run, maker, run_index, "-fwine", argv[0], &root_target, &host);1857 return failForeign(arena, &conf_run, maker, run_index, "-fwine", argv[0], &root_target, &host);
1867 }1858 }
1868 },1859 },
1869 .qemu => |bin_name| {1860 .qemu => |bin_name| {
...@@ -1887,11 +1878,11 @@ fn runCommand(...@@ -1887,11 +1878,11 @@ fn runCommand(
1887 root_target.abi,1878 root_target.abi,
1888 ) else unreachable,1879 ) else unreachable,
1889 }));1880 }));
1890 } else return failForeign(&conf_run, maker, run_index, "--libc-runtimes", argv[0], &root_target, &host);1881 } else return failForeign(arena, &conf_run, maker, run_index, "--libc-runtimes", argv[0], &root_target, &host);
1891 }1882 }
18921883
1893 interp_argv.appendSliceAssumeCapacity(argv);1884 interp_argv.appendSliceAssumeCapacity(argv);
1894 } else return failForeign(&conf_run, maker, run_index, "-fqemu", argv[0], &root_target, &host);1885 } else return failForeign(arena, &conf_run, maker, run_index, "-fqemu", argv[0], &root_target, &host);
1895 },1886 },
1896 .darling => |bin_name| {1887 .darling => |bin_name| {
1897 if (graph.enable_darling) {1888 if (graph.enable_darling) {
...@@ -1899,7 +1890,7 @@ fn runCommand(...@@ -1899,7 +1890,7 @@ fn runCommand(
1899 interp_argv.appendAssumeCapacity(bin_name);1890 interp_argv.appendAssumeCapacity(bin_name);
1900 interp_argv.appendSliceAssumeCapacity(argv);1891 interp_argv.appendSliceAssumeCapacity(argv);
1901 } else {1892 } else {
1902 return failForeign(&conf_run, maker, run_index, "-fdarling", argv[0], &root_target, &host);1893 return failForeign(arena, &conf_run, maker, run_index, "-fdarling", argv[0], &root_target, &host);
1903 }1894 }
1904 },1895 },
1905 .wasmtime => |bin_name| {1896 .wasmtime => |bin_name| {
...@@ -1912,7 +1903,7 @@ fn runCommand(...@@ -1912,7 +1903,7 @@ fn runCommand(
1912 interp_argv.appendAssumeCapacity("-Sinherit-env");1903 interp_argv.appendAssumeCapacity("-Sinherit-env");
1913 interp_argv.appendSliceAssumeCapacity(argv);1904 interp_argv.appendSliceAssumeCapacity(argv);
1914 } else {1905 } else {
1915 return failForeign(&conf_run, maker, run_index, "-fwasmtime", argv[0], &root_target, &host);1906 return failForeign(arena, &conf_run, maker, run_index, "-fwasmtime", argv[0], &root_target, &host);
1916 }1907 }
1917 },1908 },
1918 .bad_dl => |foreign_dl| {1909 .bad_dl => |foreign_dl| {
...@@ -1941,15 +1932,16 @@ fn runCommand(...@@ -1941,15 +1932,16 @@ fn runCommand(
19411932
1942 gpa.free(step.result_failed_command.?);1933 gpa.free(step.result_failed_command.?);
1943 step.result_failed_command = null;1934 step.result_failed_command = null;
1944 try graph.handleVerbose(cwd_string, environ_map, interp_argv.items);1935 try graph.handleVerbose(cwd_string, &environ_map, interp_argv.items);
19451936
1946 break :term spawnChildAndCollect(1937 break :term spawnChildAndCollect(
1938 arena,
1947 run_index,1939 run_index,
1948 run,1940 run,
1949 maker,1941 maker,
1950 progress_node,1942 progress_node,
1951 interp_argv.items,1943 interp_argv.items,
1952 environ_map,1944 &environ_map,
1953 has_side_effects,1945 has_side_effects,
1954 fuzz_context,1946 fuzz_context,
1955 ) catch |e| {1947 ) catch |e| {
...@@ -1996,7 +1988,7 @@ fn runCommand(...@@ -1996,7 +1988,7 @@ fn runCommand(
1996 if (stream.captured) |captured| {1988 if (stream.captured) |captured| {
1997 const output_path: Path = .{1989 const output_path: Path = .{
1998 .root_dir = cache_root,1990 .root_dir = cache_root,
1999 .sub_path = try Dir.path.join(arena, &.{1991 .sub_path = try Dir.path.join(graph.arena, &.{
2000 output_dir_path, captured.basename.slice(conf),1992 output_dir_path, captured.basename.slice(conf),
2001 }),1993 }),
2002 };1994 };
...@@ -2117,6 +2109,7 @@ const EvalGenericResult = struct {...@@ -2117,6 +2109,7 @@ const EvalGenericResult = struct {
2117};2109};
21182110
2119fn spawnChildAndCollect(2111fn spawnChildAndCollect(
2112 arena: Allocator,
2120 run_index: Configuration.Step.Index,2113 run_index: Configuration.Step.Index,
2121 run: *Run,2114 run: *Run,
2122 maker: *Maker,2115 maker: *Maker,
...@@ -2129,7 +2122,6 @@ fn spawnChildAndCollect(...@@ -2129,7 +2122,6 @@ fn spawnChildAndCollect(
2129 const step = maker.stepByIndex(run_index);2122 const step = maker.stepByIndex(run_index);
2130 const graph = maker.graph;2123 const graph = maker.graph;
2131 const io = graph.io;2124 const io = graph.io;
2132 const arena = graph.arena; // TODO don't leak into process arena
2133 const gpa = maker.gpa;2125 const gpa = maker.gpa;
2134 const conf = &maker.scanned_config.configuration;2126 const conf = &maker.scanned_config.configuration;
2135 const conf_step = run_index.ptr(conf);2127 const conf_step = run_index.ptr(conf);
...@@ -2189,7 +2181,7 @@ fn spawnChildAndCollect(...@@ -2189,7 +2181,7 @@ fn spawnChildAndCollect(
21892181
2190 if (conf_run.flags.stdio == .zig_test) {2182 if (conf_run.flags.stdio == .zig_test) {
2191 const started: Io.Clock.Timestamp = .now(io, .awake);2183 const started: Io.Clock.Timestamp = .now(io, .awake);
2192 const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) {2184 const result = evalZigTest(graph.arena, run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) {
2193 error.Canceled => |e| return e,2185 error.Canceled => |e| return e,
2194 else => |e| e,2186 else => |e| e,
2195 };2187 };
...@@ -2209,7 +2201,7 @@ fn spawnChildAndCollect(...@@ -2209,7 +2201,7 @@ fn spawnChildAndCollect(
2209 try setColorEnvironmentVariables(&conf_run, environ_map, terminal_mode);2201 try setColorEnvironmentVariables(&conf_run, environ_map, terminal_mode);
22102202
2211 const started: Io.Clock.Timestamp = .now(io, .awake);2203 const started: Io.Clock.Timestamp = .now(io, .awake);
2212 const result = evalGeneric(run_index, maker, spawn_options) catch |err| switch (err) {2204 const result = evalGeneric(arena, run_index, maker, spawn_options) catch |err| switch (err) {
2213 error.Canceled => |e| return e,2205 error.Canceled => |e| return e,
2214 else => |e| e,2206 else => |e| e,
2215 };2207 };
...@@ -2287,12 +2279,11 @@ fn checksContainStderr(conf_run: *const Configuration.Step.Run) bool {...@@ -2287,12 +2279,11 @@ fn checksContainStderr(conf_run: *const Configuration.Step.Run) bool {
2287///2279///
2288/// Whenever a path is included in the argv of a child, it should be put through this function first2280/// Whenever a path is included in the argv of a child, it should be put through this function first
2289/// to make sure the child doesn't see paths relative to a cwd other than its own.2281/// to make sure the child doesn't see paths relative to a cwd other than its own.
2290fn convertPathArg(run_index: Configuration.Step.Index, maker: *Maker, path: Path) ![]const u8 {2282fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker: *Maker, path: Path) ![]const u8 {
2291 const conf = &maker.scanned_config.configuration;2283 const conf = &maker.scanned_config.configuration;
2292 const conf_step = run_index.ptr(conf);2284 const conf_step = run_index.ptr(conf);
2293 const conf_run = conf_step.extended.get(conf.extra).run;2285 const conf_run = conf_step.extended.get(conf.extra).run;
2294 const graph = maker.graph;2286 const graph = maker.graph;
2295 const arena = graph.arena; // TODO don't leak into process arena
22962287
2297 const path_str = try path.toString(arena);2288 const path_str = try path.toString(arena);
2298 if (Dir.path.isAbsolute(path_str)) {2289 if (Dir.path.isAbsolute(path_str)) {
...@@ -2319,13 +2310,13 @@ fn convertPathArg(run_index: Configuration.Step.Index, maker: *Maker, path: Path...@@ -2319,13 +2310,13 @@ fn convertPathArg(run_index: Configuration.Step.Index, maker: *Maker, path: Path
23192310
2320fn addPathForDynLibs(2311fn addPathForDynLibs(
2321 maker: *Maker,2312 maker: *Maker,
2313 arena: Allocator,
2322 artifact: Configuration.Step.Index,2314 artifact: Configuration.Step.Index,
2323 environ_map: *process.Environ.Map,2315 environ_map: *process.Environ.Map,
2324 argv0: []const u8,2316 argv0: []const u8,
2325) !void {2317) !void {
2326 const conf = &maker.scanned_config.configuration;2318 const conf = &maker.scanned_config.configuration;
2327 const graph = maker.graph;2319 const graph = maker.graph;
2328 const arena = graph.arena; // TODO don't leak into process arena
2329 const use_wine = graph.enable_wine and builtin.os.tag != .windows and std.ascii.endsWithIgnoreCase(argv0, ".exe");2320 const use_wine = graph.enable_wine and builtin.os.tag != .windows and std.ascii.endsWithIgnoreCase(argv0, ".exe");
2330 const path_key = if (use_wine) "WINEPATH" else "PATH";2321 const path_key = if (use_wine) "WINEPATH" else "PATH";
2331 const path_delimiter: u8 = if (builtin.os.tag == .windows or use_wine)2322 const path_delimiter: u8 = if (builtin.os.tag == .windows or use_wine)
...@@ -2355,6 +2346,7 @@ fn addPathForDynLibs(...@@ -2355,6 +2346,7 @@ fn addPathForDynLibs(
2355}2346}
23562347
2357fn failForeign(2348fn failForeign(
2349 arena: Allocator,
2358 conf_run: *const Configuration.Step.Run,2350 conf_run: *const Configuration.Step.Run,
2359 maker: *Maker,2351 maker: *Maker,
2360 step_index: Configuration.Step.Index,2352 step_index: Configuration.Step.Index,
...@@ -2368,10 +2360,8 @@ fn failForeign(...@@ -2368,10 +2360,8 @@ fn failForeign(
2368 .check, .zig_test => {2360 .check, .zig_test => {
2369 if (conf_run.flags.skip_foreign_checks) return error.MakeSkipped;2361 if (conf_run.flags.skip_foreign_checks) return error.MakeSkipped;
23702362
2371 const graph = maker.graph;2363 const host_name = try host_target.zigTriple(arena);
2372 const process_arena = graph.arena; // TODO don't leak into process arena2364 const foreign_name = try artifact_target.zigTriple(arena);
2373 const host_name = try host_target.zigTriple(process_arena);
2374 const foreign_name = try artifact_target.zigTriple(process_arena);
23752365
2376 return step.fail(maker,2366 return step.fail(maker,
2377 \\unable to spawn foreign binary '{s}' ({s}) on host system ({s})2367 \\unable to spawn foreign binary '{s}' ({s}) on host system ({s})